From 5a5c549fe9a3fef595297bd21d36bed8409dc37d Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 30 Dec 2015 11:57:38 +0000 Subject: [PATCH] Vendor import of lld trunk r256633: https://llvm.org/svn/llvm-project/lld/trunk@256633 --- CMakeLists.txt | 5 +- CODE_OWNERS.TXT | 19 + COFF/CMakeLists.txt | 33 + COFF/Chunks.cpp | 340 ++++ COFF/Chunks.h | 332 ++++ COFF/Config.h | 140 ++ COFF/DLL.cpp | 556 ++++++ COFF/DLL.h | 84 + COFF/Driver.cpp | 677 ++++++++ COFF/Driver.h | 180 ++ COFF/DriverUtils.cpp | 718 ++++++++ COFF/Error.cpp | 30 + COFF/Error.h | 28 + COFF/ICF.cpp | 244 +++ COFF/InputFiles.cpp | 367 ++++ COFF/InputFiles.h | 222 +++ COFF/MarkLive.cpp | 61 + COFF/ModuleDef.cpp | 291 ++++ .../WinLinkOptions.td => COFF/Options.td | 63 +- COFF/PDB.cpp | 60 + COFF/README.md | 265 +++ COFF/SymbolTable.cpp | 445 +++++ COFF/SymbolTable.h | 125 ++ COFF/Symbols.cpp | 243 +++ COFF/Symbols.h | 407 +++++ COFF/Writer.cpp | 765 ++++++++ COFF/Writer.h | 26 + ELF/CMakeLists.txt | 26 + ELF/Config.h | 84 + ELF/Driver.cpp | 299 ++++ ELF/Driver.h | 67 + ELF/DriverUtils.cpp | 120 ++ ELF/Error.cpp | 38 + ELF/Error.h | 32 + ELF/InputFiles.cpp | 496 ++++++ ELF/InputFiles.h | 211 +++ ELF/InputSection.cpp | 399 +++++ ELF/InputSection.h | 187 ++ ELF/LinkerScript.cpp | 318 ++++ ELF/MarkLive.cpp | 131 ++ ELF/Options.td | 161 ++ ELF/OutputSections.cpp | 1534 +++++++++++++++++ ELF/OutputSections.h | 485 ++++++ ELF/README.md | 21 + ELF/SymbolTable.cpp | 267 +++ ELF/SymbolTable.h | 98 ++ ELF/Symbols.cpp | 148 ++ ELF/Symbols.h | 327 ++++ ELF/Target.cpp | 1481 ++++++++++++++++ ELF/Target.h | 117 ++ ELF/Writer.cpp | 1282 ++++++++++++++ ELF/Writer.h | 24 + Makefile | 86 - docs/Makefile | 155 -- docs/Readers.rst | 7 +- docs/design.rst | 55 +- docs/getting_started.rst | 4 +- docs/index.rst | 11 +- docs/open_projects.rst | 1 - docs/windows_support.rst | 31 +- include/Makefile | 4 - include/lld/Config/Makefile | 32 - include/lld/Core/Alias.h | 10 +- include/lld/Core/DefinedAtom.h | 14 +- include/lld/Core/Error.h | 26 +- include/lld/Core/File.h | 178 +- include/lld/Core/LLVM.h | 2 + include/lld/Core/LinkingContext.h | 15 +- include/lld/Core/Parallel.h | 106 +- include/lld/Core/Pass.h | 4 +- include/lld/Core/PassManager.h | 7 +- include/lld/Core/Reader.h | 19 +- include/lld/Core/Reference.h | 2 +- include/lld/Core/Resolver.h | 2 +- include/lld/Core/SharedLibraryFile.h | 16 +- include/lld/Core/Simple.h | 87 +- include/lld/Core/SymbolTable.h | 2 +- include/lld/Core/TODO.txt | 2 +- include/lld/Core/Writer.h | 12 +- include/lld/Driver/Driver.h | 48 +- include/lld/Driver/WinLinkModuleDef.h | 200 --- include/lld/Makefile | 44 - include/lld/ReaderWriter/ELFLinkingContext.h | 274 +-- include/lld/ReaderWriter/ELFTargets.h | 38 - include/lld/ReaderWriter/LinkerScript.h | 187 +- .../lld/ReaderWriter/MachOLinkingContext.h | 76 +- .../lld/ReaderWriter/PECOFFLinkingContext.h | 463 ----- .../ReaderWriter/RelocationHelperFunctions.h | 57 - include/lld/ReaderWriter/YamlContext.h | 12 +- lib/Config/Makefile | 13 - lib/Core/DefinedAtom.cpp | 1 + lib/Core/Error.cpp | 52 +- lib/Core/File.cpp | 8 +- lib/Core/LinkingContext.cpp | 8 +- lib/Core/Makefile | 13 - lib/Core/Reader.cpp | 16 +- lib/Core/Resolver.cpp | 57 +- lib/Core/SymbolTable.cpp | 13 +- lib/Core/TODO.txt | 18 - lib/Core/Writer.cpp | 4 - lib/Driver/CMakeLists.txt | 9 +- lib/Driver/CoreDriver.cpp | 23 +- lib/Driver/DarwinLdDriver.cpp | 234 ++- lib/Driver/DarwinLdOptions.td | 22 +- lib/Driver/Driver.cpp | 82 +- lib/Driver/GnuLdDriver.cpp | 263 +-- lib/Driver/GnuLdOptions.td | 67 +- lib/Driver/Makefile | 38 - lib/Driver/TODO.rst | 2 - lib/Driver/UniversalDriver.cpp | 71 +- lib/Driver/WinLinkDriver.cpp | 1371 --------------- lib/Driver/WinLinkModuleDef.cpp | 295 ---- lib/Makefile | 16 - lib/ReaderWriter/CMakeLists.txt | 2 - lib/ReaderWriter/CoreLinkingContext.cpp | 135 +- .../ELF/AArch64/AArch64DynamicLibraryWriter.h | 50 +- lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h | 41 - .../ELF/AArch64/AArch64ELFReader.h | 62 - .../ELF/AArch64/AArch64ExecutableWriter.cpp | 52 + .../ELF/AArch64/AArch64ExecutableWriter.h | 48 +- .../ELF/AArch64/AArch64LinkingContext.cpp | 26 +- .../ELF/AArch64/AArch64LinkingContext.h | 8 +- .../ELF/AArch64/AArch64RelocationHandler.cpp | 590 ++++--- .../ELF/AArch64/AArch64RelocationHandler.h | 13 +- .../ELF/AArch64/AArch64RelocationPass.cpp | 241 ++- .../ELF/AArch64/AArch64SectionChunks.cpp | 39 + .../ELF/AArch64/AArch64SectionChunks.h | 37 + .../ELF/AArch64/AArch64TargetHandler.cpp | 43 +- .../ELF/AArch64/AArch64TargetHandler.h | 68 +- lib/ReaderWriter/ELF/AArch64/CMakeLists.txt | 2 + lib/ReaderWriter/ELF/AArch64/Makefile | 15 - .../ELF/AMDGPU/AMDGPUExecutableWriter.cpp | 34 + .../ELF/AMDGPU/AMDGPUExecutableWriter.h | 41 + .../ELF/AMDGPU/AMDGPULinkingContext.cpp | 41 + .../ELF/AMDGPU/AMDGPULinkingContext.h | 36 + .../ELF/AMDGPU/AMDGPURelocationHandler.cpp | 19 + .../ELF/AMDGPU/AMDGPURelocationHandler.h | 31 + .../ELF/AMDGPU/AMDGPUSymbolTable.cpp | 32 + .../ELF/AMDGPU/AMDGPUSymbolTable.h | 32 + .../ELF/AMDGPU/AMDGPUTargetHandler.cpp | 65 + .../ELF/AMDGPU/AMDGPUTargetHandler.h | 80 + lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt | 13 + .../ELF/ARM/ARMDynamicLibraryWriter.h | 49 + lib/ReaderWriter/ELF/ARM/ARMELFFile.h | 143 +- lib/ReaderWriter/ELF/ARM/ARMELFReader.h | 62 - lib/ReaderWriter/ELF/ARM/ARMELFWriters.h | 120 ++ .../ELF/ARM/ARMExecutableWriter.h | 99 +- .../ELF/ARM/ARMLinkingContext.cpp | 48 +- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h | 46 +- .../ELF/ARM/ARMRelocationHandler.cpp | 582 ++++--- .../ELF/ARM/ARMRelocationHandler.h | 15 +- .../ELF/ARM/ARMRelocationPass.cpp | 822 +++++++-- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h | 39 +- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp | 28 +- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 164 +- lib/ReaderWriter/ELF/ARM/Makefile | 15 - lib/ReaderWriter/ELF/ARM/TODO.rst | 13 +- lib/ReaderWriter/ELF/Atoms.cpp | 297 ++++ lib/ReaderWriter/ELF/Atoms.h | 468 +---- lib/ReaderWriter/ELF/CMakeLists.txt | 11 + lib/ReaderWriter/ELF/Chunk.h | 75 +- lib/ReaderWriter/ELF/CreateELF.h | 118 -- lib/ReaderWriter/ELF/DefaultLayout.h | 1050 ----------- lib/ReaderWriter/ELF/DefaultTargetHandler.h | 38 - lib/ReaderWriter/ELF/DynamicFile.cpp | 146 ++ lib/ReaderWriter/ELF/DynamicFile.h | 92 +- lib/ReaderWriter/ELF/DynamicLibraryWriter.h | 40 +- lib/ReaderWriter/ELF/ELFFile.cpp | 829 +++++++++ lib/ReaderWriter/ELF/ELFFile.h | 948 +--------- lib/ReaderWriter/ELF/ELFLinkingContext.cpp | 86 +- lib/ReaderWriter/ELF/ELFReader.h | 85 +- lib/ReaderWriter/ELF/ExecutableWriter.h | 137 +- lib/ReaderWriter/ELF/FileCommon.cpp | 66 + lib/ReaderWriter/ELF/FileCommon.h | 45 + lib/ReaderWriter/ELF/HeaderChunks.cpp | 205 +++ lib/ReaderWriter/ELF/HeaderChunks.h | 276 +-- .../ELF/Hexagon/HexagonDynamicLibraryWriter.h | 62 +- lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h | 125 +- .../ELF/Hexagon/HexagonELFReader.h | 62 - .../ELF/Hexagon/HexagonELFWriters.h | 61 - .../ELF/Hexagon/HexagonEncodings.h | 37 + .../ELF/Hexagon/HexagonExecutableAtoms.h | 29 - .../ELF/Hexagon/HexagonExecutableWriter.h | 75 +- .../ELF/Hexagon/HexagonLinkingContext.cpp | 34 +- .../ELF/Hexagon/HexagonLinkingContext.h | 22 +- .../ELF/Hexagon/HexagonRelocationFunctions.h | 49 - .../ELF/Hexagon/HexagonRelocationHandler.cpp | 328 ++-- .../ELF/Hexagon/HexagonRelocationHandler.h | 14 +- .../ELF/Hexagon/HexagonSectionChunks.h | 86 - .../ELF/Hexagon/HexagonTargetHandler.cpp | 146 +- .../ELF/Hexagon/HexagonTargetHandler.h | 123 +- lib/ReaderWriter/ELF/Hexagon/Makefile | 16 - lib/ReaderWriter/ELF/Layout.h | 59 - lib/ReaderWriter/ELF/Makefile | 18 - lib/ReaderWriter/ELF/Mips/CMakeLists.txt | 6 +- lib/ReaderWriter/ELF/Mips/Makefile | 15 - .../ELF/Mips/MipsAbiInfoHandler.cpp | 675 ++++++++ .../ELF/Mips/MipsAbiInfoHandler.h | 83 + .../ELF/Mips/MipsCtorsOrderPass.cpp | 7 +- .../ELF/Mips/MipsCtorsOrderPass.h | 2 +- .../ELF/Mips/MipsDynamicLibraryWriter.h | 101 -- lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h | 89 +- lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp | 348 ++++ lib/ReaderWriter/ELF/Mips/MipsELFFile.h | 291 +--- .../ELF/Mips/MipsELFFlagsMerger.cpp | 149 -- .../ELF/Mips/MipsELFFlagsMerger.h | 36 - lib/ReaderWriter/ELF/Mips/MipsELFReader.h | 93 - lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp | 292 ++++ lib/ReaderWriter/ELF/Mips/MipsELFWriters.h | 116 +- .../ELF/Mips/MipsExecutableWriter.h | 154 -- .../ELF/Mips/MipsLinkingContext.cpp | 97 +- .../ELF/Mips/MipsLinkingContext.h | 22 +- .../ELF/Mips/MipsRelocationHandler.cpp | 683 ++++---- .../ELF/Mips/MipsRelocationHandler.h | 14 +- .../ELF/Mips/MipsRelocationPass.cpp | 789 ++++++--- .../ELF/Mips/MipsSectionChunks.cpp | 264 +++ lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h | 176 +- .../ELF/Mips/MipsTargetHandler.cpp | 171 +- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h | 224 +-- .../ELF/Mips/MipsTargetLayout.cpp | 111 ++ lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h | 71 + lib/ReaderWriter/ELF/OrderPass.h | 5 +- lib/ReaderWriter/ELF/OutputELFWriter.cpp | 514 ++++++ lib/ReaderWriter/ELF/OutputELFWriter.h | 488 +----- lib/ReaderWriter/ELF/Reader.cpp | 6 +- lib/ReaderWriter/ELF/SectionChunks.cpp | 996 +++++++++++ lib/ReaderWriter/ELF/SectionChunks.h | 1124 ++---------- lib/ReaderWriter/ELF/SegmentChunks.cpp | 519 ++++++ lib/ReaderWriter/ELF/SegmentChunks.h | 486 +----- lib/ReaderWriter/ELF/TargetHandler.h | 67 +- lib/ReaderWriter/ELF/TargetLayout.cpp | 747 ++++++++ lib/ReaderWriter/ELF/TargetLayout.h | 317 +++- lib/ReaderWriter/ELF/Writer.cpp | 4 +- lib/ReaderWriter/ELF/Writer.h | 7 +- lib/ReaderWriter/ELF/X86/Makefile | 15 - .../ELF/X86/X86DynamicLibraryWriter.h | 49 +- lib/ReaderWriter/ELF/X86/X86ELFFile.h | 41 - lib/ReaderWriter/ELF/X86/X86ELFReader.h | 62 - .../ELF/X86/X86ExecutableWriter.h | 34 +- .../ELF/X86/X86LinkingContext.cpp | 23 +- lib/ReaderWriter/ELF/X86/X86LinkingContext.h | 2 + .../ELF/X86/X86RelocationHandler.cpp | 17 +- .../ELF/X86/X86RelocationHandler.h | 5 +- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp | 29 +- lib/ReaderWriter/ELF/X86/X86TargetHandler.h | 35 +- lib/ReaderWriter/ELF/X86_64/CMakeLists.txt | 1 + .../ExampleLinkingContext.cpp | 4 +- .../ExampleSubTarget/ExampleTargetHandler.cpp | 5 +- .../ExampleSubTarget/ExampleTargetHandler.h | 2 +- .../ELF/X86_64/ExampleSubTarget/Makefile | 15 - lib/ReaderWriter/ELF/X86_64/Makefile | 19 - .../ELF/X86_64/X86_64DynamicLibraryWriter.h | 38 +- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h | 41 - lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h | 62 - lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h | 21 - .../ELF/X86_64/X86_64ExecutableWriter.h | 54 +- .../ELF/X86_64/X86_64LinkingContext.cpp | 22 +- .../ELF/X86_64/X86_64LinkingContext.h | 7 +- .../ELF/X86_64/X86_64RelocationHandler.cpp | 54 +- .../ELF/X86_64/X86_64RelocationHandler.h | 10 +- .../ELF/X86_64/X86_64RelocationPass.cpp | 62 +- .../ELF/X86_64/X86_64SectionChunks.cpp | 37 + .../ELF/X86_64/X86_64SectionChunks.h | 36 + .../ELF/X86_64/X86_64TargetHandler.cpp | 30 +- .../ELF/X86_64/X86_64TargetHandler.h | 85 +- lib/ReaderWriter/FileArchive.cpp | 106 +- lib/ReaderWriter/LinkerScript.cpp | 411 ++++- lib/ReaderWriter/MachO/ArchHandler.h | 6 + lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 52 +- lib/ReaderWriter/MachO/ArchHandler_arm64.cpp | 23 +- lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 21 +- lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 113 +- lib/ReaderWriter/MachO/Atoms.h | 36 +- lib/ReaderWriter/MachO/CMakeLists.txt | 1 + lib/ReaderWriter/MachO/CompactUnwindPass.cpp | 85 +- ...{ExecutableAtoms.hpp => ExecutableAtoms.h} | 25 +- lib/ReaderWriter/MachO/File.h | 40 +- lib/ReaderWriter/MachO/FlatNamespaceFile.h | 61 + lib/ReaderWriter/MachO/GOTPass.cpp | 29 +- lib/ReaderWriter/MachO/LayoutPass.cpp | 22 +- lib/ReaderWriter/MachO/LayoutPass.h | 17 +- .../MachO/MachOLinkingContext.cpp | 100 +- lib/ReaderWriter/MachO/MachONormalizedFile.h | 59 +- .../MachO/MachONormalizedFileBinaryReader.cpp | 52 +- .../MachO/MachONormalizedFileBinaryWriter.cpp | 75 +- .../MachO/MachONormalizedFileFromAtoms.cpp | 202 +-- .../MachO/MachONormalizedFileToAtoms.cpp | 304 +++- .../MachO/MachONormalizedFileYAML.cpp | 6 +- lib/ReaderWriter/MachO/MachOPasses.h | 1 + lib/ReaderWriter/MachO/Makefile | 14 - lib/ReaderWriter/MachO/SectCreateFile.h | 93 + lib/ReaderWriter/MachO/ShimPass.cpp | 23 +- lib/ReaderWriter/MachO/StubsPass.cpp | 70 +- lib/ReaderWriter/MachO/TLVPass.cpp | 137 ++ lib/ReaderWriter/MachO/WriterMachO.cpp | 28 +- lib/ReaderWriter/Makefile | 16 - lib/ReaderWriter/Native/CMakeLists.txt | 7 - lib/ReaderWriter/Native/Makefile | 14 - lib/ReaderWriter/Native/NativeFileFormat.h | 258 --- lib/ReaderWriter/Native/ReaderNative.cpp | 1013 ----------- lib/ReaderWriter/Native/WriterNative.cpp | 566 ------ lib/ReaderWriter/PECOFF/Atoms.h | 312 ---- lib/ReaderWriter/PECOFF/CMakeLists.txt | 16 - lib/ReaderWriter/PECOFF/EdataPass.cpp | 227 --- lib/ReaderWriter/PECOFF/EdataPass.h | 99 -- lib/ReaderWriter/PECOFF/IdataPass.cpp | 345 ---- lib/ReaderWriter/PECOFF/IdataPass.h | 218 --- lib/ReaderWriter/PECOFF/InferSubsystemPass.h | 66 - .../PECOFF/LinkerGeneratedSymbolFile.cpp | 48 - .../PECOFF/LinkerGeneratedSymbolFile.h | 309 ---- lib/ReaderWriter/PECOFF/LoadConfigPass.cpp | 75 - lib/ReaderWriter/PECOFF/LoadConfigPass.h | 63 - lib/ReaderWriter/PECOFF/Makefile | 14 - lib/ReaderWriter/PECOFF/OrderPass.h | 67 - lib/ReaderWriter/PECOFF/PDBPass.h | 43 - .../PECOFF/PECOFFLinkingContext.cpp | 352 ---- lib/ReaderWriter/PECOFF/Pass.cpp | 95 - lib/ReaderWriter/PECOFF/Pass.h | 34 - lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 1140 ------------ .../PECOFF/ReaderImportHeader.cpp | 389 ----- .../PECOFF/WriterImportLibrary.cpp | 118 -- lib/ReaderWriter/PECOFF/WriterImportLibrary.h | 23 - lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 1417 --------------- lib/ReaderWriter/YAML/Makefile | 14 - lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 137 +- test/CMakeLists.txt | 4 +- .../Inputs/armnt-executable.obj.yaml} | 2 +- .../Inputs/armnt-executable.s} | 6 +- test/COFF/Inputs/conflict.ll | 6 + test/COFF/Inputs/entry-mangled.ll | 6 + test/COFF/Inputs/export.ll | 18 + .../Inputs/export.yaml} | 26 +- test/COFF/Inputs/export2.yaml | 29 + .../Inputs/hello32.yaml} | 88 +- test/COFF/Inputs/hello64.asm | 24 + test/COFF/Inputs/hello64.obj | Bin 0 -> 682 bytes .../Inputs/import.yaml} | 22 +- test/COFF/Inputs/imports-mangle.lib | Bin 0 -> 2114 bytes .../Inputs/include1a.yaml} | 35 +- test/COFF/Inputs/include1b.yaml | 33 + test/COFF/Inputs/include1c.yaml | 29 + test/{pecoff => COFF}/Inputs/library.lib | Bin test/COFF/Inputs/lto-chkstk-chkstk.s | 3 + test/COFF/Inputs/lto-chkstk-foo.s | 3 + test/COFF/Inputs/lto-comdat1.ll | 13 + test/COFF/Inputs/lto-comdat2.ll | 13 + test/COFF/Inputs/lto-dep.ll | 10 + .../Inputs/machine-x64.yaml} | 14 +- .../Inputs/machine-x86.yaml} | 10 +- test/{pecoff => COFF}/Inputs/resource.res | Bin test/COFF/Inputs/ret42.lib | Bin 0 -> 550 bytes test/COFF/Inputs/ret42.obj | Bin 0 -> 408 bytes .../Inputs/ret42.yaml} | 28 +- test/COFF/Inputs/std32.lib | Bin 0 -> 1898 bytes test/COFF/Inputs/std64.lib | Bin 0 -> 2068 bytes test/COFF/Inputs/weak-external.ll | 6 + test/COFF/Inputs/weak-external2.ll | 6 + test/COFF/Inputs/weak-external3.ll | 8 + test/COFF/alternatename.test | 61 + test/COFF/ar-comdat.test | 38 + .../armnt-blx23t.test} | 27 + .../armnt-branch24t.test} | 24 +- test/COFF/armnt-entry-point.test | 5 + .../armnt-imports.test} | 12 + .../armnt-mov32t-exec.test} | 21 + .../armnt-movt32t.test} | 17 + test/COFF/base.test | 57 + test/COFF/baserel.test | 215 +++ .../common.test} | 39 +- test/COFF/conflict.test | 41 + .../subsystem.main.yaml => COFF/debug.test} | 13 +- test/COFF/defparser.test | 13 + test/COFF/delayimports.test | 41 + test/COFF/delayimports32.test | 86 + test/COFF/dll.test | 53 + test/COFF/dllorder.test | 65 + test/COFF/driver.test | 3 + test/COFF/entry-inference.test | 50 + .../entry-inference2.test} | 36 +- test/COFF/entry-inference32.test | 35 + .../entry-mangled.test} | 20 +- test/COFF/entrylib.ll | 11 + test/COFF/export-exe.test | 11 + test/COFF/export.test | 82 + test/COFF/export32.test | 133 ++ test/COFF/failifmismatch.test | 11 + test/COFF/filetype.test | 4 + test/COFF/force.test | 43 + test/COFF/heap.test | 25 + test/COFF/hello32.test | 129 ++ test/COFF/help.test | 3 + test/COFF/icf-circular.test | 81 + test/COFF/icf-circular2.test | 69 + .../icf-different-align.test} | 44 +- .../secrel1.obj.yaml => COFF/icf-local.test} | 73 +- test/COFF/icf-simple.test | 71 + .../imports-mangle.test} | 75 +- test/COFF/imports.test | 35 + test/COFF/include.test | 83 + test/COFF/include2.test | 14 + test/COFF/internal.test | 42 + test/COFF/invalid-obj.test | 14 + test/COFF/largeaddressaware.test | 21 + test/COFF/libpath.test | 18 + test/COFF/linkenv.test | 4 + test/COFF/lldmap.test | 8 + test/COFF/loadcfg.ll | 15 + .../loadcfg.test} | 46 +- .../loadcfg32.test} | 13 +- test/COFF/locally-imported.test | 61 + .../locally-imported32.test} | 47 +- .../long-section-name.test} | 21 +- test/COFF/lto-chkstk.ll | 17 + test/COFF/lto-comdat.ll | 131 ++ test/COFF/lto-linker-opts.ll | 11 + test/COFF/lto-new-symbol.ll | 16 + test/COFF/lto-opt-level.ll | 21 + test/COFF/lto-parallel.ll | 20 + test/COFF/lto.ll | 130 ++ test/COFF/machine.test | 30 + test/{pecoff => COFF}/manifest.test | 24 +- .../merge.test} | 50 +- test/COFF/nodefaultlib.test | 30 + test/COFF/noentry.test | 11 + test/COFF/opt.test | 69 + test/COFF/options.test | 51 + test/COFF/order.test | 15 + test/COFF/out.test | 16 + test/COFF/reloc-arm.test | 71 + test/COFF/reloc-x64.test | 102 ++ .../main.obj.yaml => COFF/reloc-x86.test} | 76 +- test/COFF/resource.test | 14 + test/COFF/responsefile.test | 7 + test/COFF/safeseh.test | 51 + .../Inputs/nop64.obj.yaml => COFF/seh.test} | 53 +- test/COFF/sort-debug.test | 296 ++++ test/COFF/stack.test | 25 + test/COFF/subsystem-inference.test | 74 + test/COFF/subsystem.test | 19 + test/COFF/symtab.test | 254 +++ .../armnt-exports.obj.yaml => COFF/tls.test} | 26 +- test/COFF/tls32.test | 43 + .../unwind.obj.yaml => COFF/unwind.test} | 69 + test/COFF/version.test | 19 + test/COFF/weak-external.test | 36 + test/COFF/weak-external2.test | 30 + test/COFF/weak-external3.test | 32 + test/Driver/def-lib-search.test | 4 +- test/Driver/flavor-option.test | 2 +- test/Driver/lib-search.test | 10 +- test/Driver/so-whole-archive.test | 4 +- test/Driver/trivial-driver.test | 2 +- test/Driver/undef-basic.objtxt | 2 +- test/ELF/Inputs/abs.s | 4 + test/ELF/Inputs/abs255.s | 2 + test/ELF/Inputs/abs256.s | 2 + test/ELF/Inputs/abs257.s | 2 + test/ELF/Inputs/allow-multiple-definition.s | 4 + test/ELF/Inputs/allow-shlib-undefined.s | 3 + test/ELF/Inputs/archive.s | 5 + test/ELF/Inputs/archive2.s | 2 + test/ELF/Inputs/archive3.s | 2 + test/ELF/Inputs/archive4.s | 1 + test/ELF/Inputs/comdat.s | 3 + test/ELF/Inputs/common.s | 3 + test/ELF/Inputs/discard-merge-unnamed.o | Bin 0 -> 584 bytes test/ELF/Inputs/dynamic-reloc.s | 2 + test/ELF/Inputs/invalid-binding.elf | Bin 0 -> 536 bytes test/ELF/Inputs/invalid-data-encoding.a | Bin 0 -> 156 bytes test/ELF/Inputs/invalid-file-class.a | Bin 0 -> 156 bytes .../ELF/Inputs/invalid-multiple-eh-relocs.elf | Bin 0 -> 784 bytes test/ELF/Inputs/invalid-section-index.elf | Bin 0 -> 544 bytes test/ELF/Inputs/invalid-shentsize-zero.elf | Bin 0 -> 512 bytes test/ELF/Inputs/invalid-shstrndx.so | Bin 0 -> 13032 bytes test/ELF/Inputs/invalid-symtab-sh_info.elf | Bin 0 -> 512 bytes test/ELF/Inputs/libsearch-dyn.s | 3 + test/ELF/Inputs/libsearch-st.s | 3 + test/ELF/Inputs/merge.s | 6 + test/ELF/Inputs/mips-dynamic.s | 4 + .../Inputs/no-symtab.o} | Bin test/ELF/Inputs/relocation-copy-align.s | 9 + test/ELF/Inputs/relocation-copy.s | 22 + test/ELF/Inputs/relocation-size-shared.s | 6 + test/ELF/Inputs/resolution.s | 107 ++ test/ELF/Inputs/shared-ppc64.s | 9 + test/ELF/Inputs/shared.s | 6 + test/ELF/Inputs/shared2.s | 6 + test/ELF/Inputs/shared3.s | 3 + test/ELF/Inputs/tls-got.s | 14 + test/ELF/Inputs/tls-mismatch.s | 4 + test/ELF/Inputs/tls-opt-gdie.s | 20 + test/ELF/Inputs/tls-opt-gdiele-i686.s | 20 + test/ELF/Inputs/tls-opt-iele-i686-nopic.s | 15 + test/ELF/Inputs/visibility.s | 13 + test/ELF/Inputs/whole-archive.s | 2 + test/ELF/aarch64-abs16.s | 27 + test/ELF/aarch64-abs32.s | 27 + test/ELF/aarch64-call26-error.s | 11 + test/ELF/aarch64-copy.s | 93 + test/ELF/aarch64-data-relocs.s | 23 + test/ELF/aarch64-fpic-abs16.s | 7 + test/ELF/aarch64-fpic-add_abs_lo12_nc.s | 10 + test/ELF/aarch64-fpic-adr_prel_lo21.s | 10 + test/ELF/aarch64-fpic-adr_prel_pg_hi21.s | 10 + test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s | 10 + test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s | 10 + test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s | 10 + test/ELF/aarch64-fpic-prel16.s | 7 + test/ELF/aarch64-fpic-prel32.s | 7 + test/ELF/aarch64-fpic-prel64.s | 7 + test/ELF/aarch64-hi21-error.s | 10 + test/ELF/aarch64-jump26-error.s | 11 + test/ELF/aarch64-lo21-error.s | 10 + test/ELF/aarch64-prel16.s | 31 + test/ELF/aarch64-prel32.s | 31 + test/ELF/aarch64-relocs.s | 122 ++ test/ELF/allow-multiple-definition.s | 29 + test/ELF/allow-shlib-undefined.s | 25 + test/ELF/archive.s | 36 + test/ELF/as-needed.s | 44 + test/ELF/basic-aarch64.s | 193 +++ test/ELF/basic-freebsd.s | 25 + test/ELF/basic-mips.s | 272 +++ test/ELF/basic.s | 216 +++ test/ELF/basic32.s | 163 ++ test/ELF/basic64be.s | 260 +++ test/ELF/bss.s | 27 + test/ELF/comdat.s | 72 + test/ELF/common.s | 56 + test/ELF/default-output.s | 16 + test/ELF/discard-locals.s | 50 + test/ELF/discard-merge-locals.s | 24 + test/ELF/discard-merge-unnamed.s | 16 + test/ELF/discard-none.s | 54 + test/ELF/dt_flags.s | 21 + test/ELF/duplicate-internal.s | 11 + test/ELF/dynamic-reloc-index.s | 21 + test/ELF/dynamic-reloc-weak.s | 33 + test/ELF/dynamic-reloc.s | 64 + test/ELF/eh-align-cie.s | 57 + test/ELF/eh-frame-merge.s | 58 + test/ELF/eh-frame-plt.s | 16 + test/ELF/eh-frame-rel.s | 7 + test/ELF/eh-frame-type.test | 16 + test/ELF/ehframe-relocation.s | 29 + test/ELF/empty-archive.s | 3 + test/ELF/emulation.s | 177 ++ test/ELF/end-preserve.s | 16 + test/ELF/end-update.s | 29 + test/ELF/end.s | 79 + test/ELF/entry.s | 21 + test/ELF/gc-sections-eh.s | 19 + test/ELF/gc-sections-print.s | 23 + test/ELF/gc-sections.s | 102 ++ test/ELF/global_offset_table.s | 5 + test/ELF/gnu-hash-table.s | 195 +++ test/ELF/gnu-ifunc-i386.s | 130 ++ test/ELF/gnu-ifunc-nosym-i386.s | 29 + test/ELF/gnu-ifunc-nosym.s | 29 + test/ELF/gnu-ifunc.s | 126 ++ test/ELF/gnu-unique.s | 24 + test/ELF/gnustack.s | 30 + test/ELF/got-aarch64.s | 40 + test/ELF/got-i386.s | 56 + test/ELF/got.s | 45 + test/ELF/incompatible-ar-first.s | 11 + test/ELF/incompatible.s | 58 + test/ELF/init-fini.s | 43 + test/ELF/invalid-cie-length.s | 9 + test/ELF/invalid-cie-length2.s | 9 + test/ELF/invalid-cie-length3.s | 9 + test/ELF/invalid-cie-length4.s | 10 + test/ELF/invalid-cie-length5.s | 10 + test/ELF/invalid-cie-reference.s | 32 + test/ELF/invalid-elf.test | 34 + test/ELF/invalid-fde-rel.s | 32 + test/ELF/invalid-relocations.test | 22 + test/ELF/libsearch.s | 83 + test/ELF/linkerscript-ouputformat.s | 10 + test/ELF/linkerscript-outputarch.s | 10 + test/ELF/linkerscript-sections.s | 119 ++ test/ELF/linkerscript.s | 114 ++ test/ELF/linkerscript2.s | 11 + test/ELF/lit.local.cfg | 2 + test/ELF/local-dynamic.s | 83 + test/ELF/local-got-shared.s | 35 + test/ELF/local-got.s | 48 + test/ELF/local.s | 82 + test/ELF/many-sections.s | 116 ++ test/ELF/merge-invalid-size.s | 7 + test/ELF/merge-shared.s | 26 + test/ELF/merge-string-align.s | 39 + test/ELF/merge-string-error.s | 11 + test/ELF/merge-string-no-null.s | 8 + test/ELF/merge-string.s | 85 + test/ELF/merge-sym.s | 21 + test/ELF/merge.s | 109 ++ test/ELF/mips-call16.s | 40 + test/ELF/mips-dynamic.s | 91 + test/ELF/mips-dynsym-sort.s | 43 + test/ELF/mips-elf-flags.s | 27 + test/ELF/mips-gnu-hash.s | 15 + test/ELF/mips-got-relocs.s | 99 ++ test/ELF/mips-gprel32-relocs.s | 31 + test/ELF/mips-hilo-gp-disp.s | 42 + test/ELF/mips-hilo-hi-only.s | 28 + test/ELF/mips-hilo.s | 53 + test/ELF/mips-jalr.test | 47 + test/ELF/mips-pc-relocs.s | 38 + test/ELF/mips-reginfo.s | 26 + test/ELF/mips-relocs.s | 42 + test/ELF/new-dtags.test | 15 + test/ELF/no-inhibit-exec.s | 15 + test/ELF/no-obj.s | 8 + test/ELF/no-symtab.s | 4 + test/ELF/no-undefined.s | 7 + test/ELF/output-section.s | 34 + test/ELF/plt-aarch64.s | 205 +++ test/ELF/plt-i686.s | 158 ++ test/ELF/plt.s | 119 ++ test/ELF/ppc64-addr16-error.s | 7 + test/ELF/ppc64-rel-calls.s | 42 + test/ELF/ppc64-relocs.s | 130 ++ test/ELF/ppc64-shared-rel-toc.s | 27 + test/ELF/ppc64-toc-restore.s | 62 + test/ELF/ppc64-weak-undef-call-shared.s | 16 + test/ELF/ppc64-weak-undef-call.s | 27 + test/ELF/pre_init_fini_array.s | 140 ++ test/ELF/pre_init_fini_array_missing.s | 30 + test/ELF/progname.s | 20 + test/ELF/program-header-layout.s | 98 ++ test/ELF/relative-dynamic-reloc-ppc64.s | 66 + test/ELF/relative-dynamic-reloc.s | 69 + test/ELF/relocatable.s | 9 + test/ELF/relocation-absolute.s | 12 + test/ELF/relocation-common.s | 14 + test/ELF/relocation-copy-align.s | 31 + test/ELF/relocation-copy-i686.s | 63 + test/ELF/relocation-copy.s | 63 + test/ELF/relocation-i686.s | 84 + test/ELF/relocation-in-merge.s | 7 + test/ELF/relocation-local.s | 38 + test/ELF/relocation-past-merge-end.s | 7 + test/ELF/relocation-size-shared.s | 78 + test/ELF/relocation-size.s | 123 ++ test/ELF/relocation-undefined-weak.s | 27 + test/ELF/relocation.s | 117 ++ test/ELF/relro.s | 242 +++ test/ELF/resolution.s | 430 +++++ test/ELF/section-align-0.test | 19 + test/ELF/section-layout.s | 54 + test/ELF/section-name.s | 37 + test/ELF/section-symbol.s | 29 + test/ELF/shared-be.s | 35 + test/ELF/shared.s | 294 ++++ test/ELF/soname.s | 11 + test/ELF/soname2.s | 8 + test/ELF/startstop-shared.s | 18 + test/ELF/startstop.s | 61 + test/ELF/string-table.s | 80 + test/ELF/strip-all.s | 25 + test/ELF/symbols.s | 182 ++ test/ELF/sysroot.s | 36 + test/ELF/tls-align.s | 21 + test/ELF/tls-dynamic-i686.s | 92 + test/ELF/tls-dynamic.s | 81 + test/ELF/tls-error.s | 12 + test/ELF/tls-got.s | 58 + test/ELF/tls-i686.s | 69 + test/ELF/tls-mismatch.s | 9 + test/ELF/tls-opt-gdie.s | 55 + test/ELF/tls-opt-gdiele-i686.s | 59 + test/ELF/tls-opt-i686.s | 69 + test/ELF/tls-opt-iele-i686-nopic.s | 159 ++ test/ELF/tls-opt-local.s | 52 + test/ELF/tls-opt.s | 93 + test/ELF/tls-static.s | 13 + test/ELF/tls.s | 170 ++ test/ELF/undef-start.s | 4 + test/ELF/undef.s | 8 + test/ELF/undefined-opt.s | 55 + test/ELF/valid-cie-length-dw64.s | 13 + test/ELF/visibility.s | 108 ++ test/ELF/whole-archive.s | 34 + test/ELF/writable-merge.s | 6 + test/ELF/x86-64-reloc-32-error.s | 8 + test/ELF/x86-64-reloc-32S-error.s | 7 + test/LinkerScript/phdrs-sections.test | 29 + test/LinkerScript/sections.test | 6 + test/Makefile | 71 - test/core/Inputs/archive-basic.objtxt | 21 + test/core/Inputs/archive-chain.objtxt | 24 + test/core/Inputs/archive-chain2.objtxt | 21 + .../core/Inputs/archive-tentdef-search.objtxt | 11 + test/core/Inputs/associates.objtxt | 8 + test/core/Inputs/auto-hide-coalesce.objtxt | 20 + test/core/Inputs/code-model-attributes.objtxt | 4 + .../core/Inputs/code-model-attributes2.objtxt | 4 + .../core/Inputs/code-model-attributes3.objtxt | 4 + .../core/Inputs/code-model-attributes4.objtxt | 4 + .../core/Inputs/code-model-attributes5.objtxt | 4 + test/core/Inputs/constants-coalesce.objtxt | 9 + test/core/Inputs/constants-coalesce2.objtxt | 10 + test/core/Inputs/cstring-coalesce.objtxt | 6 + test/core/Inputs/cstring-coalesce2.objtxt | 6 + .../Inputs/custom-section-coalesce.objtxt | 15 + .../Inputs/custom-section-coalesce2.objtxt | 13 + test/core/Inputs/dead-strip-attributes.objtxt | 4 + .../core/Inputs/dead-strip-attributes2.objtxt | 4 + test/core/Inputs/dead-strip-basic.objtxt | 9 + test/core/Inputs/dead-strip-basic2.objtxt | 8 + test/core/Inputs/dead-strip-globals.objtxt | 9 + test/core/Inputs/dead-strip-globals2.objtxt | 8 + .../Inputs/error-duplicate-absolutes.objtxt | 5 + .../gnulinkonce-rearrange-resolve.objtxt | 26 + .../Inputs/gnulinkonce-remaining-undef.objtxt | 34 + .../gnulinkonce-remaining-undef2.objtxt | 4 + test/core/Inputs/gnulinkonce-resolve.objtxt | 25 + test/core/Inputs/gnulinkonce-simple.objtxt | 4 + test/core/Inputs/inline-coalesce.objtxt | 6 + test/core/Inputs/inline-coalesce2.objtxt | 6 + test/core/Inputs/multiple-def-error.objtxt | 5 + .../core/Inputs/sectiongroup-deadstrip.objtxt | 3 + .../sectiongroup-gnulinkonce-error.objtxt | 26 + .../sectiongroup-rearrange-resolve.objtxt | 25 + .../sectiongroup-remaining-undef.objtxt | 34 + .../sectiongroup-remaining-undef2.objtxt | 4 + test/core/Inputs/sectiongroup-resolve.objtxt | 26 + test/core/Inputs/sectiongroup-simple.objtxt | 4 + .../Inputs/shared-library-coalesce.objtxt | 28 + test/core/Inputs/tent-merge.objtxt | 6 + test/core/Inputs/undef-coalesce-error.objtxt | 8 + test/core/Inputs/undef-coalesce-error2.objtxt | 8 + test/core/Inputs/undef-coalesce.objtxt | 8 + test/core/Inputs/undef-coalesce2.objtxt | 8 + test/core/Inputs/undef-fallback.objtxt | 7 + test/core/Inputs/undef-weak-coalesce.objtxt | 20 + test/core/Inputs/weak-coalesce.objtxt | 5 + test/core/Inputs/weak-coalesce2.objtxt | 6 + test/core/archive-basic.objtxt | 23 +- test/core/archive-chain.objtxt | 49 +- test/core/archive-tentdef-search.objtxt | 16 +- test/core/associates.objtxt | 11 +- test/core/auto-hide-coalesce.objtxt | 23 +- test/core/code-model-attributes.objtxt | 27 +- test/core/constants-coalesce.objtxt | 22 +- test/core/cstring-coalesce.objtxt | 12 - test/core/custom-section-coalesce.objtxt | 32 +- test/core/dead-strip-attributes.objtxt | 11 +- test/core/dead-strip-basic.objtxt | 21 +- test/core/dead-strip-globals.objtxt | 21 +- test/core/error-duplicate-absolutes.objtxt | 7 +- .../core/gnulinkonce-rearrange-resolve.objtxt | 28 +- test/core/gnulinkonce-remaining-undef.objtxt | 41 +- test/core/gnulinkonce-resolve.objtxt | 28 +- test/core/gnulinkonce-simple.objtxt | 6 +- test/core/inline-coalesce.objtxt | 14 +- test/core/multiple-def-error.objtxt | 7 +- test/core/sectiongroup-deadstrip.objtxt | 6 +- .../sectiongroup-gnulinkonce-error.objtxt | 28 +- .../sectiongroup-rearrange-resolve.objtxt | 28 +- test/core/sectiongroup-remaining-undef.objtxt | 40 +- test/core/sectiongroup-resolve.objtxt | 26 - test/core/sectiongroup-simple.objtxt | 4 - test/core/shared-library-coalesce.objtxt | 31 +- test/core/tent-merge.objtxt | 8 +- test/core/undef-coalesce-error.objtxt | 20 +- test/core/undef-coalesce.objtxt | 18 +- test/core/undef-fallback.objtxt | 10 +- test/core/undef-weak-coalesce.objtxt | 22 +- test/core/weak-coalesce.objtxt | 18 +- test/darwin/Inputs/native-and-mach-o.objtxt | 17 + test/darwin/Inputs/native-and-mach-o2.objtxt | 19 + test/darwin/native-and-mach-o.objtxt | 44 +- test/elf/ARM/rel-arm-prel31.test | 47 - test/elf/Inputs/init_array.x86-64 | Bin 3440 -> 0 bytes test/elf/Mips/hilo16-1.test | 44 - test/elf/Mips/hilo16-2.test | 68 - test/elf/Mips/hilo16-3.test | 45 - test/elf/Mips/hilo16-8-micro.test | 81 - test/elf/Mips/hilo16-9-micro.test | 68 - test/elf/Mips/r26-2-micro.test | 88 - test/elf/Mips/r26-2.test | 82 - test/elf/Mips/rel-dynamic-02.test | 82 - test/elf/Mips/rel-dynamic-06-64.test | 101 -- test/elf/Mips/rel-dynamic-06.test | 103 -- test/elf/X86_64/demangle.test | 12 - test/elf/X86_64/dynlib-nointerp-section.test | 4 - test/elf/X86_64/extern-tls.test | 16 - test/elf/init_array.test | 6 - test/lit.cfg | 87 +- test/mach-o/Inputs/PIE.yaml | 6 + test/mach-o/Inputs/arm-interworking.yaml | 83 + test/mach-o/Inputs/arm-shims.yaml | 60 + test/mach-o/Inputs/cstring-sections.yaml | 25 + test/mach-o/Inputs/got-order.yaml | 53 + test/mach-o/Inputs/got-order2.yaml | 11 + test/mach-o/Inputs/hello-world-arm64.yaml | 8 + test/mach-o/Inputs/hello-world-armv6.yaml | 7 + test/mach-o/Inputs/hello-world-armv7.yaml | 7 + test/mach-o/Inputs/hello-world-x86.yaml | 7 + test/mach-o/Inputs/hello-world-x86_64.yaml | 8 + test/mach-o/Inputs/hw.raw_bytes | 1 + test/mach-o/Inputs/interposing-section.yaml | 6 + test/mach-o/Inputs/lazy-bind-x86_64-2.yaml | 8 + test/mach-o/Inputs/lazy-bind-x86_64-3.yaml | 8 + test/mach-o/Inputs/lazy-bind-x86_64.yaml | 8 + test/mach-o/Inputs/linker-as-ld.yaml | 6 + .../Inputs/re-exported-dylib-ordinal.yaml | 21 + .../Inputs/re-exported-dylib-ordinal2.yaml | 18 + .../Inputs/re-exported-dylib-ordinal3.yaml | 19 + .../Inputs/unwind-info-simple-arm64.yaml | 13 + test/mach-o/Inputs/use-simple-dylib.yaml | 58 + test/mach-o/Inputs/write-final-sections.yaml | 20 + test/mach-o/Inputs/wrong-arch-error.yaml | 24 + test/mach-o/PIE.yaml | 16 +- test/mach-o/align_text.yaml | 10 +- test/mach-o/arm-interworking-movw.yaml | 20 +- test/mach-o/arm-interworking.yaml | 160 +- test/mach-o/arm-shims.yaml | 83 +- test/mach-o/arm-subsections-via-symbols.yaml | 4 +- test/mach-o/arm64-reloc-negDelta32-fixup.yaml | 124 ++ .../arm64-relocs-errors-delta64-offset.yaml | 65 + test/mach-o/cstring-sections.yaml | 26 - test/mach-o/data-only-dylib.yaml | 2 +- test/mach-o/demangle.yaml | 2 +- ...b-exports.yaml => executable-exports.yaml} | 13 +- test/mach-o/exported_symbols_list-dylib.yaml | 2 +- test/mach-o/exported_symbols_list-obj.yaml | 2 +- test/mach-o/exported_symbols_list-undef.yaml | 2 +- test/mach-o/fat-archive.yaml | 8 +- test/mach-o/flat_namespace_undef_error.yaml | 17 + .../mach-o/flat_namespace_undef_suppress.yaml | 17 + test/mach-o/force_load-dylib.yaml | 4 +- test/mach-o/force_load-x86_64.yaml | 4 +- test/mach-o/framework-user-paths.yaml | 2 +- test/mach-o/gcc_except_tab-got-arm64.yaml | 53 + test/mach-o/got-order.yaml | 85 +- test/mach-o/hello-world-arm64.yaml | 14 +- test/mach-o/hello-world-armv6.yaml | 10 +- test/mach-o/hello-world-armv7.yaml | 25 +- test/mach-o/hello-world-x86.yaml | 19 +- test/mach-o/hello-world-x86_64.yaml | 55 +- test/mach-o/image-base.yaml | 13 +- test/mach-o/infer-arch.yaml | 2 +- test/mach-o/interposing-section.yaml | 25 +- test/mach-o/keep_private_externs.yaml | 2 +- test/mach-o/lazy-bind-x86_64.yaml | 31 +- test/mach-o/library-order.yaml | 6 +- test/mach-o/library-rescan.yaml | 6 +- test/mach-o/linker-as-ld.yaml | 11 +- test/mach-o/objc_export_list.yaml | 18 +- test/mach-o/parse-aliases.yaml | 2 +- test/mach-o/parse-arm-relocs.yaml | 14 +- test/mach-o/parse-cfstring64.yaml | 8 +- test/mach-o/parse-data-in-code-armv7.yaml | 12 +- test/mach-o/parse-data-relocs-x86_64.yaml | 230 ++- test/mach-o/parse-eh-frame-relocs-x86_64.yaml | 176 ++ test/mach-o/parse-eh-frame-x86-anon.yaml | 50 +- test/mach-o/parse-eh-frame-x86-labeled.yaml | 58 +- test/mach-o/parse-function.yaml | 6 +- test/mach-o/parse-initializers64.yaml | 10 +- test/mach-o/parse-literals-error.yaml | 2 +- test/mach-o/parse-literals.yaml | 22 +- test/mach-o/parse-relocs-x86.yaml | 30 +- test/mach-o/parse-tentative-defs.yaml | 10 +- test/mach-o/parse-text-relocs-x86_64.yaml | 42 +- test/mach-o/parse-tlv-relocs-x86-64.yaml | 100 ++ test/mach-o/re-exported-dylib-ordinal.yaml | 67 +- test/mach-o/rpath.yaml | 2 +- test/mach-o/run-tlv-pass-x86-64.yaml | 144 ++ test/mach-o/sectalign.yaml | 4 +- test/mach-o/sectcreate.yaml | 12 + test/mach-o/stack-size.yaml | 24 + ...olevel_namespace_undef_dynamic_lookup.yaml | 17 + ...evel_namespace_undef_warning_suppress.yaml | 23 + test/mach-o/unwind-info-simple-arm64.yaml | 89 +- test/mach-o/unwind-info-simple-x86_64.yaml | 23 +- test/mach-o/upward-dylib-load-command.yaml | 4 +- test/mach-o/use-simple-dylib.yaml | 62 +- test/mach-o/write-final-sections.yaml | 48 +- test/mach-o/wrong-arch-error.yaml | 25 +- test/{elf => old-elf}/AArch64/Inputs/fn.c | 0 test/{elf => old-elf}/AArch64/Inputs/fn.o | Bin .../AArch64/Inputs/general-dyn-tls-0.yaml | 64 + .../AArch64/Inputs/initfini-option.c | 0 .../AArch64/Inputs/initfini-option.o | Bin .../AArch64/Inputs/initfini.c | 0 .../AArch64/Inputs/initfini.o | Bin .../AArch64/Inputs/initial-exec-tls-1.yaml | 77 + test/{elf => old-elf}/AArch64/Inputs/main.c | 0 test/{elf => old-elf}/AArch64/Inputs/main.o | Bin .../AArch64/Inputs/no-interp-section.c | 0 .../AArch64/Inputs/no-interp-section.o | Bin .../AArch64/Inputs/zerosizedsection.o | Bin .../AArch64/Inputs/zerosizedsection.s | 0 test/{elf => old-elf}/AArch64/defsym.test | 2 +- .../AArch64/dontignorezerosize-sections.test | 2 +- test/old-elf/AArch64/dynamicvars.test | 113 ++ .../AArch64/dynlib-nointerp-section.test | 2 +- test/old-elf/AArch64/general-dyn-tls-0.test | 103 ++ test/{elf => old-elf}/AArch64/initfini.test | 2 +- test/old-elf/AArch64/initial-exec-tls-0.test | 146 ++ test/old-elf/AArch64/local-tls.test | 184 ++ test/old-elf/AArch64/rel-abs16-overflow.test | 44 + test/old-elf/AArch64/rel-abs16.test | 53 + .../AArch64/rel-abs32-overflow.test | 2 +- test/{elf => old-elf}/AArch64/rel-abs32.test | 2 +- test/{elf => old-elf}/AArch64/rel-abs64.test | 2 +- .../AArch64/rel-adr_prel_lo21-overflow.test | 45 + test/old-elf/AArch64/rel-adr_prel_lo21.test | 51 + .../rel-adr_prel_pg_hi21-overflow.test | 45 + .../old-elf/AArch64/rel-adr_prel_pg_hi21.test | 52 + test/{elf => old-elf}/AArch64/rel-bad.test | 2 +- test/old-elf/AArch64/rel-prel16-overflow.test | 53 + test/old-elf/AArch64/rel-prel16.test | 59 + test/old-elf/AArch64/rel-prel32-overflow.test | 53 + test/old-elf/AArch64/rel-prel32.test | 59 + test/old-elf/AArch64/rel-prel64.test | 59 + test/old-elf/AMDGPU/hsa.test | 53 + test/old-elf/ARM/Inputs/fn.c | 1 + test/old-elf/ARM/Inputs/libfn.so | Bin 0 -> 4972 bytes test/old-elf/ARM/Inputs/libobj.so | Bin 0 -> 5067 bytes test/old-elf/ARM/Inputs/obj.c | 4 + test/{elf => old-elf}/ARM/arm-symbols.test | 3 +- test/{elf => old-elf}/ARM/defsym.test | 3 +- test/old-elf/ARM/dynamic-symbols.test | 83 + test/{elf => old-elf}/ARM/entry-point.test | 44 +- test/old-elf/ARM/exidx.test | 254 +++ test/old-elf/ARM/header-flags.test | 57 + test/old-elf/ARM/mapping-code-model.test | 160 ++ test/old-elf/ARM/mapping-symbols.test | 122 ++ test/{elf => old-elf}/ARM/missing-symbol.test | 3 +- test/old-elf/ARM/plt-dynamic.test | 200 +++ test/old-elf/ARM/plt-ifunc-interwork.test | 396 +++++ test/old-elf/ARM/plt-ifunc-mapping.test | 109 ++ test/{elf => old-elf}/ARM/rel-abs32.test | 3 +- test/{elf => old-elf}/ARM/rel-arm-call.test | 56 +- .../ARM/rel-arm-jump24-veneer-b.test | 53 +- .../ARM/rel-arm-jump24-veneer-bl.test | 50 +- test/{elf => old-elf}/ARM/rel-arm-jump24.test | 54 +- test/{elf => old-elf}/ARM/rel-arm-mov.test | 4 +- test/old-elf/ARM/rel-arm-prel31.test | 90 + test/old-elf/ARM/rel-arm-target1.test | 114 ++ .../ARM/rel-arm-thm-interwork.test | 4 +- test/old-elf/ARM/rel-base-prel.test | 61 + .../ARM/rel-copy.test} | 43 +- test/old-elf/ARM/rel-glob-dat.test | 57 + .../ARM/rel-got-brel.test} | 54 +- test/old-elf/ARM/rel-group-relocs.test | 71 + test/old-elf/ARM/rel-ifunc.test | 101 ++ test/old-elf/ARM/rel-jump-slot.test | 50 + test/{elf => old-elf}/ARM/rel-rel32.test | 3 +- test/old-elf/ARM/rel-thm-call.test | 114 ++ test/{elf => old-elf}/ARM/rel-thm-jump11.test | 138 +- .../ARM/rel-thm-jump24-veneer.test | 50 +- test/old-elf/ARM/rel-thm-jump24.test | 110 ++ test/{elf => old-elf}/ARM/rel-thm-mov.test | 4 +- test/{elf => old-elf}/ARM/rel-tls-ie32.test | 44 +- test/{elf => old-elf}/ARM/rel-tls-le32.test | 34 +- test/old-elf/ARM/rel-v4bx.test | 72 + test/{elf => old-elf}/ARM/thm-symbols.test | 3 +- test/old-elf/ARM/two-got-for-symbol.test | 62 + .../ARM/undef-lazy-symbol.test | 20 +- test/old-elf/ARM/veneer-mapping.test | 92 + test/old-elf/ARM/weak-branch.test | 221 +++ .../Hexagon/Inputs/dynobj-data.c | 0 .../Hexagon/Inputs/dynobj-data.o | Bin test/{elf => old-elf}/Hexagon/Inputs/dynobj.c | 0 test/{elf => old-elf}/Hexagon/Inputs/dynobj.o | Bin .../Hexagon/Inputs/got-plt-order.c | 0 .../Hexagon/Inputs/got-plt-order.o | Bin .../Hexagon/Inputs/libMaxAlignment.a | Bin .../Hexagon/Inputs/sda-base.o | Bin test/{elf => old-elf}/Hexagon/Inputs/sdata1.c | 0 test/{elf => old-elf}/Hexagon/Inputs/sdata1.o | Bin test/{elf => old-elf}/Hexagon/Inputs/sdata2.c | 0 test/{elf => old-elf}/Hexagon/Inputs/sdata2.o | Bin .../Hexagon/Inputs/use-shared.hexagon | Bin .../{elf => old-elf}/Hexagon/dynlib-data.test | 2 +- .../Hexagon/dynlib-gotoff.test | 22 +- .../{elf => old-elf}/Hexagon/dynlib-hash.test | 2 +- .../{elf => old-elf}/Hexagon/dynlib-rela.test | 2 +- .../{elf => old-elf}/Hexagon/dynlib-syms.test | 2 +- test/{elf => old-elf}/Hexagon/dynlib.test | 2 +- .../Hexagon/hexagon-got-plt-order.test | 2 +- .../Hexagon/hexagon-plt-setup.test | 2 +- .../Hexagon/maxalignment.test | 2 +- test/{elf => old-elf}/Hexagon/rela-order.test | 2 +- test/{elf => old-elf}/Hexagon/sda-base.test | 2 +- .../Hexagon/zerofillquick-sdata.test | 2 +- test/{elf => old-elf}/Inputs/abs-test.i386 | Bin test/old-elf/Inputs/allowduplicates.objtxt | 12 + test/{elf => old-elf}/Inputs/bar.o.x86-64 | Bin .../Inputs/branch-test.hexagon | Bin test/{elf => old-elf}/Inputs/branch-test.ppc | Bin .../Inputs/consecutive-weak-defs.o.yaml | 15 +- .../Inputs/constants-merge.x86-64 | Bin test/{elf => old-elf}/Inputs/constdata.x86-64 | Bin test/{elf => old-elf}/Inputs/foo.o.x86-64 | Bin test/{elf => old-elf}/Inputs/globalconst.c | 0 .../Inputs/globalconst.o.x86-64 | Bin test/{elf => old-elf}/Inputs/gotpcrel.S | 0 test/{elf => old-elf}/Inputs/gotpcrel.x86-64 | Bin .../Inputs/group-cmd-search-1.ls | 0 .../Inputs/group-cmd-search-2.ls | 0 .../Inputs/group-cmd-search-3.ls | 0 test/{elf => old-elf}/Inputs/ifunc.S | 0 test/{elf => old-elf}/Inputs/ifunc.cpp | 0 test/{elf => old-elf}/Inputs/ifunc.cpp.x86-64 | Bin test/{elf => old-elf}/Inputs/ifunc.x86-64 | Bin test/{elf => old-elf}/Inputs/libfnarchive.a | Bin .../Inputs/libifunc.x86-64.so | Bin test/{elf => old-elf}/Inputs/libundef.so | Bin test/{elf => old-elf}/Inputs/libweaksym.so | Bin .../Inputs/main-with-global-def.o.yaml | 13 +- test/{elf => old-elf}/Inputs/mainobj.x86_64 | Bin .../Inputs/no-unique-section-names.x86-64 | Bin 0 -> 2128 bytes .../Inputs/object-test.elf-hexagon | Bin .../Inputs/object-test.elf-i386 | Bin test/{elf => old-elf}/Inputs/phdr.i386 | Bin .../Inputs/quickdata-sort-test.o.elf-hexagon | Bin .../quickdata-sortcommon-test.o.elf-hexagon | Bin .../Inputs/quickdata-test.elf-hexagon | Bin .../Inputs/reloc-test.elf-i386 | Bin test/{elf => old-elf}/Inputs/reloc-xb.x86 | Bin test/{elf => old-elf}/Inputs/reloc-xt.x86 | Bin .../Inputs/relocs-dynamic.x86-64 | Bin test/{elf => old-elf}/Inputs/relocs.x86-64 | Bin test/{elf => old-elf}/Inputs/responsefile | 0 .../Inputs/rodata-test.hexagon | Bin test/{elf => old-elf}/Inputs/rodata-test.i386 | Bin test/{elf => old-elf}/Inputs/rodata.c | 0 test/{elf => old-elf}/Inputs/rodata.o | Bin .../{elf => old-elf}/Inputs/section-test.i386 | Bin test/{elf => old-elf}/Inputs/shared.c | 0 test/{elf => old-elf}/Inputs/shared.so-x86-64 | Bin test/old-elf/Inputs/shndx.o-x86_64 | Bin 0 -> 624 bytes test/old-elf/Inputs/stripped-empty.x86_64 | Bin 0 -> 416 bytes .../Inputs/target-test.hexagon | Bin test/{elf => old-elf}/Inputs/target-test.ppc | Bin test/old-elf/Inputs/tls-tbss-size.yaml | 59 + test/{elf => old-elf}/Inputs/tls.S | 0 test/{elf => old-elf}/Inputs/tls.c | 0 test/{elf => old-elf}/Inputs/tls.x86-64 | Bin test/{elf => old-elf}/Inputs/tlsAddr.x86-64 | Bin test/{elf => old-elf}/Inputs/tlsaddr.c | 0 .../Inputs/undef-from-main-so.c | 0 .../{elf => old-elf}/Inputs/undef-from-main.c | 0 test/{elf => old-elf}/Inputs/undef-pc32.o | Bin test/{elf => old-elf}/Inputs/undef.o | Bin test/{elf => old-elf}/Inputs/undef2-so.o.yaml | 1 - test/{elf => old-elf}/Inputs/use-shared-32s.c | 0 .../Inputs/use-shared-32s.x86-64 | Bin test/{elf => old-elf}/Inputs/use-shared.c | 0 .../{elf => old-elf}/Inputs/use-shared.x86-64 | Bin test/{elf => old-elf}/Inputs/weaksym.o | Bin test/{elf => old-elf}/Inputs/writersyms.o | Bin test/{elf => old-elf}/Inputs/x86-64-relocs.S | 0 test/old-elf/Mips/abi-flags-01.test | 35 + test/old-elf/Mips/abi-flags-02.test | 92 + test/old-elf/Mips/abi-flags-03.test | 149 ++ test/old-elf/Mips/abi-flags-04.test | 125 ++ test/old-elf/Mips/abi-flags-05.test | 186 ++ test/old-elf/Mips/abi-flags-06.test | 79 + test/old-elf/Mips/abi-flags-07.test | 60 + test/old-elf/Mips/abi-flags-08.test | 71 + test/old-elf/Mips/abi-flags-09.test | 67 + test/old-elf/Mips/abi-flags-10.test | 60 + test/old-elf/Mips/abi-flags-11.test | 59 + .../Mips/base-address-64.test | 6 +- test/{elf => old-elf}/Mips/base-address.test | 24 +- test/{elf => old-elf}/Mips/ctors-order.test | 23 +- test/old-elf/Mips/driver-hash-style.test | 15 + test/{elf => old-elf}/Mips/dt-textrel-64.test | 4 +- test/{elf => old-elf}/Mips/dt-textrel.test | 4 +- test/old-elf/Mips/dynamic-linking.test | 22 + test/old-elf/Mips/dynamic-sym.test | 41 + .../{elf => old-elf}/Mips/dynlib-dynamic.test | 2 +- .../Mips/dynlib-dynsym-micro.test | 18 +- test/{elf => old-elf}/Mips/dynlib-dynsym.test | 18 +- .../Mips/dynlib-fileheader-64.test | 14 +- .../Mips/dynlib-fileheader-micro-64.test | 14 +- .../Mips/dynlib-fileheader-micro.test | 23 +- .../Mips/dynlib-fileheader.test | 22 +- .../{elf => old-elf}/Mips/dynsym-table-1.test | 8 +- .../{elf => old-elf}/Mips/dynsym-table-2.test | 6 +- .../Mips/e-flags-merge-1-64.test | 2 +- .../Mips/e-flags-merge-1.test | 4 +- .../Mips/e-flags-merge-10.test | 2 +- .../Mips/e-flags-merge-11.test | 2 +- test/old-elf/Mips/e-flags-merge-12.test | 44 + .../Mips/e-flags-merge-2-64.test | 2 +- .../Mips/e-flags-merge-2.test | 2 +- .../Mips/e-flags-merge-3-64.test | 8 +- .../Mips/e-flags-merge-3.test | 8 +- .../Mips/e-flags-merge-4-64.test | 2 +- .../Mips/e-flags-merge-4.test | 2 +- .../Mips/e-flags-merge-5-64.test | 4 +- .../Mips/e-flags-merge-5.test | 4 +- .../Mips/e-flags-merge-6-64.test | 2 +- .../Mips/e-flags-merge-6.test | 2 +- .../Mips/e-flags-merge-7-64.test | 2 +- .../Mips/e-flags-merge-7.test | 2 +- .../Mips/e-flags-merge-8.test | 2 +- .../Mips/e-flags-merge-9.test | 2 +- test/{elf => old-elf}/Mips/entry-name.test | 6 +- test/{elf => old-elf}/Mips/exe-dynamic.test | 22 +- .../Mips/exe-dynsym-micro.test | 10 +- test/{elf => old-elf}/Mips/exe-dynsym.test | 10 +- test/old-elf/Mips/exe-fileheader-02.test | 62 + test/old-elf/Mips/exe-fileheader-03.test | 72 + .../Mips/exe-fileheader-64.test | 14 +- test/old-elf/Mips/exe-fileheader-be-64.test | 60 + test/old-elf/Mips/exe-fileheader-be.test | 60 + .../Mips/exe-fileheader-micro-64.test | 14 +- .../Mips/exe-fileheader-micro.test | 16 +- test/old-elf/Mips/exe-fileheader-n32.test | 65 + .../{elf => old-elf}/Mips/exe-fileheader.test | 20 +- test/{elf => old-elf}/Mips/exe-got-micro.test | 12 +- test/{elf => old-elf}/Mips/exe-got.test | 12 +- test/old-elf/Mips/got-page-32-micro.test | 251 +++ test/{elf => old-elf}/Mips/got-page-32.test | 93 +- test/old-elf/Mips/got-page-64-micro.test | 210 +++ test/{elf => old-elf}/Mips/got-page-64.test | 38 +- test/{elf => old-elf}/Mips/got16-2.test | 2 +- test/{elf => old-elf}/Mips/got16-micro.test | 18 +- test/{elf => old-elf}/Mips/got16.test | 16 +- test/{elf => old-elf}/Mips/gotsym.test | 8 +- .../{elf => old-elf}/Mips/gp-sym-1-micro.test | 6 +- test/{elf => old-elf}/Mips/gp-sym-1.test | 6 +- test/{elf => old-elf}/Mips/gp-sym-2.test | 6 +- test/old-elf/Mips/hilo16-1.test | 40 + test/old-elf/Mips/hilo16-2.test | 70 + test/old-elf/Mips/hilo16-3-overflow.test | 44 + test/old-elf/Mips/hilo16-3.test | 74 + test/{elf => old-elf}/Mips/hilo16-4.test | 2 +- test/{elf => old-elf}/Mips/hilo16-5.test | 4 +- test/old-elf/Mips/hilo16-8-micro.test | 81 + test/old-elf/Mips/hilo16-9-micro.test | 142 ++ .../{elf => old-elf}/Mips/initfini-micro.test | 2 +- .../{elf => old-elf}/Mips/interpreter-64.test | 2 +- test/old-elf/Mips/interpreter-n32.test | 27 + test/{elf => old-elf}/Mips/interpreter.test | 2 +- .../Mips/invalid-reginfo.test | 2 +- .../{elf => old-elf}/Mips/jalx-align-err.test | 4 +- test/old-elf/Mips/jalx-jalr.test | 47 + test/old-elf/Mips/jalx.test | 71 + test/{elf => old-elf}/Mips/jump-fix-err.test | 2 +- test/old-elf/Mips/la25-stub-be.test | 113 ++ test/old-elf/Mips/la25-stub-micro-be.test | 121 ++ .../Mips/la25-stub-micro.test | 36 +- test/old-elf/Mips/la25-stub-npic-01.test | 153 ++ test/old-elf/Mips/la25-stub-npic-02.test | 123 ++ test/old-elf/Mips/la25-stub-npic-shared.test | 152 ++ test/old-elf/Mips/la25-stub-pic.test | 144 ++ test/{elf => old-elf}/Mips/la25-stub.test | 28 +- test/old-elf/Mips/mips-options-01.test | 34 + test/old-elf/Mips/mips-options-02.test | 104 ++ test/old-elf/Mips/mips-options-03.test | 41 + test/old-elf/Mips/mips-options-04.test | 77 + test/old-elf/Mips/mips-options-05.test | 119 ++ .../Mips/mips-options-gp0.test | 23 +- test/old-elf/Mips/n32-rela-chain.test | 68 + test/{elf => old-elf}/Mips/n64-rel-chain.test | 86 +- test/old-elf/Mips/n64-rel-shift.test | 48 + test/{elf => old-elf}/Mips/opt-emulation.test | 6 +- test/{elf => old-elf}/Mips/pc23-range.test | 12 +- .../Mips/plt-entry-mixed-1.test | 6 +- .../Mips/plt-entry-mixed-2.test | 12 +- .../Mips/plt-entry-mixed-3.test | 4 +- .../Mips/plt-entry-mixed-4.test | 10 +- test/old-elf/Mips/plt-entry-r6-be.test | 109 ++ test/{elf => old-elf}/Mips/plt-entry-r6.test | 6 +- test/old-elf/Mips/plt-header-be.test | 104 ++ test/old-elf/Mips/plt-header-micro-be.test | 105 ++ .../Mips/plt-header-micro.test | 4 +- .../Mips/plt-header-mixed.test | 6 +- test/{elf => old-elf}/Mips/plt-header.test | 6 +- test/{elf => old-elf}/Mips/r26-1-micro.test | 4 +- test/{elf => old-elf}/Mips/r26-1.test | 4 +- test/old-elf/Mips/r26-2-micro.test | 31 + test/old-elf/Mips/r26-2.test | 31 + test/old-elf/Mips/reginfo-01.test | 30 + test/old-elf/Mips/reginfo-02.test | 107 ++ test/old-elf/Mips/reginfo-03.test | 45 + test/old-elf/Mips/reginfo-04.test | 81 + test/old-elf/Mips/reginfo-05.test | 123 ++ test/old-elf/Mips/rel-16-overflow.test | 45 + test/old-elf/Mips/rel-16.test | 51 + test/old-elf/Mips/rel-32-be.test | 60 + test/{elf => old-elf}/Mips/rel-32.test | 2 +- test/{elf => old-elf}/Mips/rel-64.test | 2 +- test/old-elf/Mips/rel-call-hilo-01.test | 109 ++ test/old-elf/Mips/rel-call-hilo-micro.test | 154 ++ .../{elf => old-elf}/Mips/rel-copy-micro.test | 10 +- test/{elf => old-elf}/Mips/rel-copy-pc.test | 6 +- test/{elf => old-elf}/Mips/rel-copy.test | 14 +- .../Mips/rel-dynamic-01-micro.test | 12 +- .../{elf => old-elf}/Mips/rel-dynamic-01.test | 38 +- test/old-elf/Mips/rel-dynamic-02.test | 101 ++ .../Mips/rel-dynamic-03-micro.test | 4 +- .../{elf => old-elf}/Mips/rel-dynamic-03.test | 6 +- .../Mips/rel-dynamic-04-micro.test | 19 +- .../{elf => old-elf}/Mips/rel-dynamic-04.test | 19 +- .../Mips/rel-dynamic-05-micro.test | 4 +- .../{elf => old-elf}/Mips/rel-dynamic-05.test | 24 +- test/old-elf/Mips/rel-dynamic-06-64.test | 114 ++ test/old-elf/Mips/rel-dynamic-06.test | 115 ++ .../Mips/rel-dynamic-07-64.test | 91 +- .../{elf => old-elf}/Mips/rel-dynamic-07.test | 91 +- .../Mips/rel-dynamic-08-64.test | 46 +- .../Mips/rel-dynamic-08-micro.test | 46 +- .../{elf => old-elf}/Mips/rel-dynamic-08.test | 46 +- .../Mips/rel-dynamic-09-micro.test | 2 +- .../{elf => old-elf}/Mips/rel-dynamic-09.test | 2 +- .../Mips/rel-dynamic-10-micro.test | 2 +- .../{elf => old-elf}/Mips/rel-dynamic-10.test | 2 +- .../{elf => old-elf}/Mips/rel-dynamic-11.test | 4 +- .../{elf => old-elf}/Mips/rel-dynamic-12.test | 36 +- test/old-elf/Mips/rel-dynamic-13.test | 94 + test/old-elf/Mips/rel-dynamic-14.test | 94 + test/old-elf/Mips/rel-dynamic-15.test | 81 + test/old-elf/Mips/rel-eh-01.test | 186 ++ test/old-elf/Mips/rel-eh-02.test | 130 ++ test/old-elf/Mips/rel-eh-03.test | 128 ++ test/old-elf/Mips/rel-got-hilo-01.test | 109 ++ test/old-elf/Mips/rel-got-hilo-micro.test | 154 ++ .../Mips/rel-gprel16-micro-overflow.test | 57 + test/old-elf/Mips/rel-gprel16-micro.test | 78 + test/old-elf/Mips/rel-gprel16-overflow.test | 48 + test/{elf => old-elf}/Mips/rel-gprel16.test | 24 +- .../{elf => old-elf}/Mips/rel-gprel32-64.test | 24 +- test/{elf => old-elf}/Mips/rel-gprel32.test | 14 +- .../Mips/rel-gprel7-micro-overflow.test | 48 + test/old-elf/Mips/rel-gprel7-micro.test | 65 + test/old-elf/Mips/rel-hi0-lo16-micro.test | 58 + test/old-elf/Mips/rel-high-01.test | 25 + test/old-elf/Mips/rel-high-02.test | 25 + test/old-elf/Mips/rel-jalr-01.test | 101 ++ test/old-elf/Mips/rel-jalr-02.test | 68 + test/old-elf/Mips/rel-lit-micro.test | 59 + test/old-elf/Mips/rel-lit.test | 57 + test/{elf => old-elf}/Mips/rel-pc-hilo.test | 30 +- test/old-elf/Mips/rel-pc16-align.test | 43 + test/old-elf/Mips/rel-pc16-overflow.test | 45 + test/old-elf/Mips/rel-pc16.test | 53 + test/old-elf/Mips/rel-pc18-s3-align.test | 44 + test/old-elf/Mips/rel-pc18-s3-micro.test | 56 + test/{elf => old-elf}/Mips/rel-pc18-s3.test | 16 +- test/old-elf/Mips/rel-pc19-s2-align.test | 44 + test/old-elf/Mips/rel-pc19-s2-micro.test | 56 + test/{elf => old-elf}/Mips/rel-pc19-s2.test | 16 +- test/old-elf/Mips/rel-pc21-s2-align.test | 44 + test/old-elf/Mips/rel-pc21-s2-micro.test | 56 + test/old-elf/Mips/rel-pc21-s2-overflow.test | 45 + test/{elf => old-elf}/Mips/rel-pc21-s2.test | 16 +- test/old-elf/Mips/rel-pc26-s2-align.test | 44 + test/old-elf/Mips/rel-pc26-s2-micro.test | 56 + test/{elf => old-elf}/Mips/rel-pc26-s2.test | 16 +- test/{elf => old-elf}/Mips/rel-pc32.test | 12 +- .../Mips/rel-pc7-10-16-23.test | 40 +- test/old-elf/Mips/rel-sub-micro.test | 62 + test/{elf => old-elf}/Mips/rel-sub.test | 2 +- test/old-elf/Mips/rld_map.test | 42 + test/old-elf/Mips/sign-rela.test | 54 + test/{elf => old-elf}/Mips/st-other.test | 12 +- test/old-elf/Mips/static-01.test | 119 ++ test/{elf => old-elf}/Mips/tls-1-micro.test | 4 +- test/{elf => old-elf}/Mips/tls-1.test | 4 +- test/old-elf/Mips/tls-2-64-static.test | 71 + test/{elf => old-elf}/Mips/tls-2-64.test | 2 +- test/{elf => old-elf}/Mips/tls-2-micro.test | 2 +- test/old-elf/Mips/tls-2-static.test | 125 ++ test/{elf => old-elf}/Mips/tls-2.test | 2 +- test/old-elf/Mips/tls-3-64-static.test | 70 + test/{elf => old-elf}/Mips/tls-3-micro.test | 4 +- test/old-elf/Mips/tls-3-static.test | 67 + test/{elf => old-elf}/Mips/tls-3.test | 4 +- test/old-elf/Mips/tls-4-64-static.test | 71 + test/{elf => old-elf}/Mips/tls-4-micro.test | 2 +- test/old-elf/Mips/tls-4-static.test | 68 + test/{elf => old-elf}/Mips/tls-4.test | 2 +- test/{elf => old-elf}/Mips/tls-5-64.test | 2 +- test/{elf => old-elf}/Mips/tls-5-micro.test | 2 +- test/{elf => old-elf}/Mips/tls-5.test | 2 +- test/old-elf/Mips/validate-rel-01.test | 82 + test/old-elf/Mips/validate-rel-03.test | 56 + .../X86_64/ExampleTarget/triple.test | 2 +- .../{elf => old-elf}/X86_64/Inputs/constint.c | 0 .../{elf => old-elf}/X86_64/Inputs/constint.o | Bin test/{elf => old-elf}/X86_64/Inputs/debug0.c | 0 .../X86_64/Inputs/debug0.x86-64 | Bin test/{elf => old-elf}/X86_64/Inputs/debug1.c | 0 .../X86_64/Inputs/debug1.x86-64 | Bin .../X86_64/Inputs/externtls.c | 0 .../X86_64/Inputs/externtls.x86-64 | Bin test/{elf => old-elf}/X86_64/Inputs/fn.c | 0 test/{elf => old-elf}/X86_64/Inputs/fn.o | Bin .../X86_64/Inputs/generaltls-so.o.yaml | 1 - test/{elf => old-elf}/X86_64/Inputs/group/1.c | 0 test/{elf => old-elf}/X86_64/Inputs/group/1.o | Bin .../{elf => old-elf}/X86_64/Inputs/group/fn.c | 0 .../{elf => old-elf}/X86_64/Inputs/group/fn.o | Bin .../X86_64/Inputs/group/fn1.c | 0 .../X86_64/Inputs/group/fn1.o | Bin .../X86_64/Inputs/group/fn2.c | 0 .../X86_64/Inputs/group/fn2.o | Bin .../X86_64/Inputs/group/group.sh | 0 .../X86_64/Inputs/group/libfn.a | Bin .../X86_64/Inputs/group/libfn.so | Bin .../X86_64/Inputs/group/libfn1.a | Bin .../X86_64/Inputs/group/libfn2.so | Bin .../X86_64/Inputs/initfini-option.c | 0 .../X86_64/Inputs/initfini-option.o | Bin .../{elf => old-elf}/X86_64/Inputs/initfini.c | 0 .../{elf => old-elf}/X86_64/Inputs/initfini.o | Bin .../{elf => old-elf}/X86_64/Inputs/largebss.c | 0 .../{elf => old-elf}/X86_64/Inputs/largebss.o | Bin .../X86_64/Inputs/layoutpass/1.c | 0 .../X86_64/Inputs/layoutpass/1.o | Bin .../X86_64/Inputs/layoutpass/2.c | 0 .../X86_64/Inputs/layoutpass/2.o | Bin .../X86_64/Inputs/layoutpass/3.c | 0 .../X86_64/Inputs/layoutpass/3.o | Bin .../X86_64/Inputs/layoutpass/lib2.a | Bin test/{elf => old-elf}/X86_64/Inputs/libfn.a | Bin test/{elf => old-elf}/X86_64/Inputs/libfn.so | Bin test/{elf => old-elf}/X86_64/Inputs/main.c | 0 test/{elf => old-elf}/X86_64/Inputs/main.o | Bin .../X86_64/Inputs/multi-ovrd.c | 0 .../X86_64/Inputs/multi-ovrd.o | Bin .../X86_64/Inputs/multi-weak.c | 0 .../X86_64/Inputs/multi-weak.o | Bin .../X86_64/Inputs/multiweaksyms.o | Bin test/{elf => old-elf}/X86_64/Inputs/nmagic.c | 0 test/{elf => old-elf}/X86_64/Inputs/nmagic.o | Bin .../X86_64/Inputs/no-interp-section.c | 0 .../X86_64/Inputs/no-interp-section.o | Bin test/{elf => old-elf}/X86_64/Inputs/note.o | Bin test/{elf => old-elf}/X86_64/Inputs/note.s | 0 .../X86_64/Inputs/note_ro_rw.o | Bin .../X86_64/Inputs/note_ro_rw.s | 0 test/{elf => old-elf}/X86_64/Inputs/ovrd.c | 0 test/{elf => old-elf}/X86_64/Inputs/ovrd.o | Bin test/{elf => old-elf}/X86_64/Inputs/rodata.c | 0 test/{elf => old-elf}/X86_64/Inputs/rodata.o | Bin test/{elf => old-elf}/X86_64/Inputs/rodata.s | 0 test/{elf => old-elf}/X86_64/Inputs/rwint.c | 0 test/{elf => old-elf}/X86_64/Inputs/rwint.o | Bin .../X86_64/Inputs/sectionmap.c | 0 .../X86_64/Inputs/sectionmap.o | Bin .../{elf => old-elf}/X86_64/Inputs/undefcpp.c | 0 .../{elf => old-elf}/X86_64/Inputs/undefcpp.o | Bin .../X86_64/Inputs/weak-zero-sized.o | Bin test/{elf => old-elf}/X86_64/Inputs/weak.c | 0 test/{elf => old-elf}/X86_64/Inputs/weak.o | Bin test/{elf => old-elf}/X86_64/Inputs/weak.s | 0 .../X86_64/Inputs/zerosizedsection.o | Bin .../X86_64/Inputs/zerosizedsection.s | 0 test/{elf => old-elf}/X86_64/alignoffset.test | 3 +- test/{elf => old-elf}/X86_64/debug.test | 4 +- test/{elf => old-elf}/X86_64/defsym.test | 2 +- test/old-elf/X86_64/demangle.test | 12 + .../X86_64/dontignorezerosize-sections.test | 2 +- test/{elf => old-elf}/X86_64/dynamicvars.test | 3 +- .../X86_64/dynlib-nointerp-section.test | 4 + .../X86_64/dynlib-search.test | 2 +- test/{elf => old-elf}/X86_64/dynsym-weak.test | 8 +- test/old-elf/X86_64/extern-tls.test | 16 + .../X86_64/general-dynamic-tls.test | 5 +- test/{elf => old-elf}/X86_64/imagebase.test | 4 +- .../X86_64/initfini-order.test | 2 +- test/{elf => old-elf}/X86_64/initfini.test | 2 +- test/{elf => old-elf}/X86_64/largebss.test | 2 +- .../X86_64/layoutpass-order.test | 2 +- test/{elf => old-elf}/X86_64/maxpagesize.test | 12 +- .../X86_64/mergesimilarstrings.test | 4 +- .../X86_64/multi-weak-layout.test | 12 +- .../X86_64/multi-weak-override.test | 4 +- .../X86_64/multi-weak-syms-order.test | 4 +- test/{elf => old-elf}/X86_64/nmagic.test | 2 +- .../X86_64/noalignsegments.test | 4 +- .../X86_64/note-sections-ro_plus_rw.test | 2 +- .../X86_64/note-sections.test | 2 +- test/{elf => old-elf}/X86_64/omagic.test | 4 +- .../X86_64/outputsegments.test | 5 +- .../X86_64/reloc_r_x86_64_16.test | 3 +- .../X86_64/reloc_r_x86_64_pc16.test | 3 +- .../X86_64/reloc_r_x86_64_pc64.test | 3 +- test/{elf => old-elf}/X86_64/rodata.test | 2 +- .../X86_64/sectionchoice.test | 2 +- test/{elf => old-elf}/X86_64/sectionmap.test | 2 +- .../X86_64/startGroupEndGroup.test | 16 +- .../X86_64/startGroupEndGroupWithDynlib.test | 2 +- .../X86_64/staticlib-search.test | 2 +- test/{elf => old-elf}/X86_64/undef.test | 4 +- .../X86_64/underscore-end.test | 4 +- .../X86_64/weak-override.test | 4 +- .../X86_64/weak-zero-sized.test | 10 +- test/{elf => old-elf}/X86_64/weaksym.test | 3 +- test/{elf => old-elf}/X86_64/yamlinput.test | 4 +- test/{elf => old-elf}/abs-dup.objtxt | 2 +- test/{elf => old-elf}/abs.test | 2 +- test/{elf => old-elf}/allowduplicates.objtxt | 30 +- .../archive-elf-forceload.test | 2 +- test/{elf => old-elf}/archive-elf.test | 2 +- test/{elf => old-elf}/as-needed.test | 4 +- test/{elf => old-elf}/branch.test | 4 +- test/{elf => old-elf}/check.test | 4 +- test/{elf => old-elf}/checkrodata.test | 4 +- test/{elf => old-elf}/common.test | 2 +- .../consecutive-weak-sym-defs.test | 2 +- test/{elf => old-elf}/defsym.objtxt | 9 +- test/old-elf/discard-all.test | 88 + test/old-elf/discard-locals.test | 65 + test/{elf => old-elf}/dynamic-segorder.test | 2 +- test/{elf => old-elf}/dynamic-undef.test | 16 +- test/{elf => old-elf}/dynamic.test | 4 +- test/{elf => old-elf}/eh_frame_hdr.test | 2 +- test/{elf => old-elf}/entry.objtxt | 14 +- test/{elf => old-elf}/export-dynamic.test | 3 +- test/{elf => old-elf}/filenotfound.test | 2 +- ...nulinkonce-report-discarded-reference.test | 6 +- .../gnulinkonce/gnulinkonce-report-undef.test | 6 +- .../gnulinkonce/gnulinkonce.test | 6 +- test/{elf => old-elf}/gotpcrel.test | 2 +- test/{elf => old-elf}/gottpoff.test | 7 +- test/{elf => old-elf}/group-cmd-search.test | 20 +- .../hexagon-quickdata-sort.test | 2 +- .../hexagon-quickdata-sortcommon.test | 2 +- test/{elf => old-elf}/ifunc.test | 8 +- .../ignore-unknownoption.test | 2 +- test/{elf => old-elf}/init_array-order.test | 2 +- test/old-elf/init_array.test | 127 ++ .../initfini-options.test-1.test | 2 +- .../initfini-options.test-2.test | 2 +- .../initfini-options.test-3.test | 2 +- test/{elf => old-elf}/librarynotfound.test | 2 +- test/{elf => old-elf}/linker-as-ld.test | 2 +- .../linkerscript/Inputs/externs.ls | 0 .../linkerscript/Inputs/invalid.ls | 0 .../linkerscript/Inputs/prog1.o.yaml | 15 +- .../linkerscript/Inputs/prog2.o.yaml | 15 +- .../linkerscript/Inputs/prog3.o.yaml | 13 +- .../linkerscript/Inputs/simple-pic.o.yaml | 32 + .../linkerscript/Inputs/simple.o.yaml | 13 +- .../linkerscript/Inputs/valid.ls | 0 .../linkerscript/externs.objtxt | 4 +- .../linkerscript/filename-with-wildcards.test | 49 + .../linkerscript/invalid-script-cli-1.test | 4 +- .../linkerscript/invalid-script-cli-2.test | 2 +- .../linkerscript/invalid.test | 2 +- test/old-elf/linkerscript/phdrs-all-none.test | 26 + .../linkerscript/phdrs-custom-none.test | 36 + test/old-elf/linkerscript/phdrs-default.test | 82 + .../old-elf/linkerscript/phdrs-different.test | 45 + .../linkerscript/phdrs-extra-program.test | 27 + test/old-elf/linkerscript/phdrs-flags.test | 46 + .../linkerscript/phdrs-has-program.test | 33 + test/old-elf/linkerscript/phdrs-invalid.test | 63 + .../linkerscript/phdrs-misplaced-program.test | 26 + .../linkerscript/phdrs-no-program.test | 25 + test/old-elf/linkerscript/phdrs-one-none.test | 36 + .../linkerscript/phdrs-program-flags.test | 33 + .../phdrs-program-good-phdrs.test | 34 + .../linkerscript/phdrs-program-no-phdrs.test | 26 + .../phdrs-program-wrong-phdrs.test | 26 + .../linkerscript/phdrs-same-flags.test | 35 + test/old-elf/linkerscript/phdrs-same.test | 36 + .../phdrs/sections-empty-phdrs.script | 11 + .../phdrs/sections-no-phdrs.script | 7 + .../phdrs/sections-none-phdrs.script | 11 + .../phdrs/undef-empty-phdrs.script | 11 + .../linkerscript/phdrs/undef-id-phdrs.script | 12 + .../linkerscript/phdrs/undef-no-phdrs.script | 7 + .../linkerscript/sections-order.test | 18 +- .../linkerscript/sections-with-wildcards.test | 2 +- .../linkerscript/symbol-definition-so.test | 32 + .../linkerscript/symbol-definition.test | 2 +- .../linkerscript/valid-script-cli.objtxt | 10 +- test/{elf => old-elf}/loginputfiles.test | 2 +- test/{elf => old-elf}/mergeatoms.test | 2 +- test/{elf => old-elf}/mergeconstants.test | 4 +- test/{elf => old-elf}/mergeglobalatoms.test | 2 +- test/old-elf/no-unique-section-names.test | 19 + test/{elf => old-elf}/note.test | 9 +- .../options/dynamic-linker.test | 6 +- .../old-elf/options/target-specific-args.test | 5 + test/{elf => old-elf}/phdr.test | 4 +- test/{elf => old-elf}/quickdata.test | 2 +- test/{elf => old-elf}/reloc.test | 6 +- test/{elf => old-elf}/responsefile.test | 2 +- test/{elf => old-elf}/rodata.test | 2 +- test/{elf => old-elf}/rosegment.test | 4 +- .../sectiongroup-new-members.test | 6 +- .../sectionGroups/sectiongroup-simple.test | 6 +- .../sectiongroup-undef-member-other.test | 4 +- .../sectiongroup-undef-member.test | 4 +- .../sectiongroup-with-globalsymbols.test | 9 +- ...ongroup-with-undef-external-reference.test | 7 +- .../sectiongroup-with-undef-signature.test | 7 +- test/{elf => old-elf}/sections.test | 2 +- test/{elf => old-elf}/sh_addralign.test | 3 +- test/old-elf/shndx.test | 18 + test/{elf => old-elf}/soname.test | 2 +- test/old-elf/start-stop-sym.test | 108 ++ test/{elf => old-elf}/strip-all.test | 13 +- test/{elf => old-elf}/stripped-empty.test | 2 +- test/{elf => old-elf}/symbols.test | 4 +- test/old-elf/tls-tbss-size.test | 176 ++ test/{elf => old-elf}/tls.test | 6 +- test/{elf => old-elf}/tlsAddr.test | 2 +- .../undef-from-dso-to-main.test | 6 +- .../{elf => old-elf}/undef-from-main-dso.test | 4 +- test/{elf => old-elf}/weaksym.test | 2 +- test/{elf => old-elf}/wrap.test | 7 +- .../x86-64-dynamic-relocs.test | 6 +- test/{elf => old-elf}/x86-64-dynamic.test | 8 +- test/{elf => old-elf}/x86.test | 2 +- test/{elf => old-elf}/x86_64-kinds.test | 4 +- test/old-elf/zoption_dtflags.test | 89 + test/pecoff/Inputs/abs.obj.yaml | 11 - test/pecoff/Inputs/alignment.obj.yaml | 103 -- test/pecoff/Inputs/alternatename1.obj.yaml | 23 - test/pecoff/Inputs/armnt-ImageBase.obj.yaml | 39 - test/pecoff/Inputs/armnt-ImageBase.s | 16 - test/pecoff/Inputs/armnt-addr32-exec.s | 24 - test/pecoff/Inputs/armnt-addr32.obj.yaml | 39 - test/pecoff/Inputs/armnt-addr32.s | 18 - test/pecoff/Inputs/armnt-blx23t.s | 33 - test/pecoff/Inputs/armnt-branch24t.s | 26 - test/pecoff/Inputs/armnt-exports.def | 4 - test/pecoff/Inputs/armnt-import.s | 21 - test/pecoff/Inputs/armnt-mov32t-exec.s | 30 - test/pecoff/Inputs/armnt-mov32t.s | 24 - test/pecoff/Inputs/armnt-obj.s | 12 - test/pecoff/Inputs/basereloc.obj.yaml | 164 -- test/pecoff/Inputs/bss.asm | 20 - test/pecoff/Inputs/bss.obj | Bin 683 -> 0 bytes test/pecoff/Inputs/drectve.obj.yaml | 79 - test/pecoff/Inputs/drectve3.lib | Bin 462 -> 0 bytes test/pecoff/Inputs/entry.obj.yaml | 40 - test/pecoff/Inputs/exports.def | 6 - test/pecoff/Inputs/exports2.def | 6 - test/pecoff/Inputs/grouped-sections.asm | 18 - test/pecoff/Inputs/grouped-sections.obj.yaml | 83 - test/pecoff/Inputs/hello.asm | 24 - test/pecoff/Inputs/hello.obj.yaml | 111 -- test/pecoff/Inputs/hello64.asm | 22 - test/pecoff/Inputs/hello64.obj.yaml | 110 -- test/pecoff/Inputs/hello64lib.asm | 14 - test/pecoff/Inputs/hello64lib.lib | Bin 1938 -> 0 bytes .../Inputs/machine-type-unknown.obj.yaml | 38 - test/pecoff/Inputs/merge-largest1.obj.yaml | 30 - test/pecoff/Inputs/merge-largest2.obj.yaml | 30 - test/pecoff/Inputs/merge-same-size1.obj.yaml | 30 - test/pecoff/Inputs/merge-same-size2.obj.yaml | 30 - test/pecoff/Inputs/merge-same-size3.obj.yaml | 30 - .../Inputs/nonstandard-sections.obj.yaml | 53 - test/pecoff/Inputs/nop.asm | 9 - test/pecoff/Inputs/reloc64.obj.yaml | 63 - test/pecoff/Inputs/resource.rc | 4 - test/pecoff/Inputs/responsefile.txt | 1 - test/pecoff/Inputs/secrel2.obj.yaml | 47 - test/pecoff/Inputs/seh.c | 13 - test/pecoff/Inputs/seh.obj.yaml | 387 ----- test/pecoff/Inputs/static-data1.obj.yaml | 67 - test/pecoff/Inputs/static-data2.obj.yaml | 67 - test/pecoff/Inputs/static.lib | Bin 1120 -> 0 bytes test/pecoff/Inputs/vars-main-x86.obj.yaml | 69 - test/pecoff/Inputs/vars-main.c | 7 - test/pecoff/Inputs/vars.c | 20 - test/pecoff/Inputs/vars.dll.yaml | 19 - test/pecoff/Inputs/vars.lib | Bin 1994 -> 0 bytes test/pecoff/Inputs/vars64.lib | Bin 2016 -> 0 bytes test/pecoff/Inputs/weak-externals.asm | 25 - test/pecoff/Inputs/weak-externals.obj.yaml | 91 - test/pecoff/alignment.test | 22 - test/pecoff/alternatename.test | 44 - test/pecoff/armnt-ImageBase.test | 14 - test/pecoff/armnt-addr32-exec.test | 11 - test/pecoff/armnt-addr32.test | 11 - test/pecoff/armnt-address-of-entry-point.test | 6 - test/pecoff/armnt-blx23t.test | 27 - test/pecoff/armnt-branch24t.test | 20 - test/pecoff/armnt-exports.s | 28 - test/pecoff/armnt-exports.test | 10 - test/pecoff/armnt-imports.test | 11 - test/pecoff/armnt-mov32t-exec.test | 21 - test/pecoff/armnt-movt32t.test | 17 - test/pecoff/armnt.test | 6 - test/pecoff/associative.test | 10 - test/pecoff/base-reloc.test | 78 - test/pecoff/baseaddr.test | 18 - test/pecoff/bss-section.test | 21 - test/pecoff/comdat.test | 12 - test/pecoff/common-symbol.test | 14 - test/pecoff/conflicting-machine.test | 6 - test/pecoff/delayimport.test | 54 - test/pecoff/dll.test | 7 - test/pecoff/dosstub.test | 11 - test/pecoff/drectve.test | 39 - test/pecoff/dynamic.test | 11 - test/pecoff/dynamicbase.test | 24 - test/pecoff/entry.test | 41 - test/pecoff/export-warning.test | 19 - test/pecoff/export.test | 90 - test/pecoff/exportlib.test | 32 - test/pecoff/exportlib2.test | 21 - test/pecoff/grouped-sections.test | 17 - test/pecoff/hello.test | 51 - test/pecoff/hello64.test | 22 - test/pecoff/help.test | 4 - test/pecoff/imagebase.test | 15 - test/pecoff/importlib.test | 55 - test/pecoff/include.test | 8 - test/pecoff/lib.test | 15 - test/pecoff/libarg.test | 9 - test/pecoff/localyimported.test | 15 - test/pecoff/long-section-name.test | 7 - test/pecoff/machinetype.test | 13 - test/pecoff/merge-largest.test | 24 - test/pecoff/merge-same-size.test | 32 - test/pecoff/multi.test | 17 - test/pecoff/noentry.test | 10 - test/pecoff/nonstandard-sections.test | 75 - test/pecoff/options.test | 40 - test/pecoff/pe32plus.test | 87 - test/pecoff/reloc.test | 16 - test/pecoff/reloc64.test | 20 - test/pecoff/resource.test | 16 - test/pecoff/responsefile.test | 7 - test/pecoff/safeseh.test | 9 - test/pecoff/secrel.test | 16 - test/pecoff/section-attribute.test | 45 - test/pecoff/section-renaming.test | 61 - test/pecoff/seh.test | 31 - test/pecoff/seh64.test | 57 - test/pecoff/subsystem.test | 12 - test/pecoff/tls.test | 14 - test/pecoff/trivial.test | 103 -- test/pecoff/unknown-drectve.test | 6 - test/pecoff/weak-external.test | 9 - tools/Makefile | 17 - tools/linker-script-test/Makefile | 24 - tools/lld/CMakeLists.txt | 22 +- tools/lld/Makefile | 30 - tools/lld/lld.cpp | 5 +- unittests/CoreTests/Makefile | 14 - unittests/DriverTests/CMakeLists.txt | 4 +- unittests/DriverTests/DarwinLdDriverTest.cpp | 6 +- unittests/DriverTests/DriverTest.h | 2 +- unittests/DriverTests/GnuLdDriverTest.cpp | 21 +- unittests/DriverTests/Makefile | 20 - unittests/DriverTests/UniversalDriverTest.cpp | 4 +- unittests/DriverTests/WinLinkDriverTest.cpp | 728 -------- .../DriverTests/WinLinkModuleDefTest.cpp | 155 -- .../MachONormalizedFileBinaryReaderTests.cpp | 16 +- .../MachONormalizedFileBinaryWriterTests.cpp | 17 +- .../MachONormalizedFileToAtomsTests.cpp | 2 +- .../MachONormalizedFileYAMLTests.cpp | 36 +- unittests/Makefile | 31 - utils/astyle-options | 7 - 1664 files changed, 63388 insertions(+), 30579 deletions(-) create mode 100644 CODE_OWNERS.TXT create mode 100644 COFF/CMakeLists.txt create mode 100644 COFF/Chunks.cpp create mode 100644 COFF/Chunks.h create mode 100644 COFF/Config.h create mode 100644 COFF/DLL.cpp create mode 100644 COFF/DLL.h create mode 100644 COFF/Driver.cpp create mode 100644 COFF/Driver.h create mode 100644 COFF/DriverUtils.cpp create mode 100644 COFF/Error.cpp create mode 100644 COFF/Error.h create mode 100644 COFF/ICF.cpp create mode 100644 COFF/InputFiles.cpp create mode 100644 COFF/InputFiles.h create mode 100644 COFF/MarkLive.cpp create mode 100644 COFF/ModuleDef.cpp rename lib/Driver/WinLinkOptions.td => COFF/Options.td (91%) create mode 100644 COFF/PDB.cpp create mode 100644 COFF/README.md create mode 100644 COFF/SymbolTable.cpp create mode 100644 COFF/SymbolTable.h create mode 100644 COFF/Symbols.cpp create mode 100644 COFF/Symbols.h create mode 100644 COFF/Writer.cpp create mode 100644 COFF/Writer.h create mode 100644 ELF/CMakeLists.txt create mode 100644 ELF/Config.h create mode 100644 ELF/Driver.cpp create mode 100644 ELF/Driver.h create mode 100644 ELF/DriverUtils.cpp create mode 100644 ELF/Error.cpp create mode 100644 ELF/Error.h create mode 100644 ELF/InputFiles.cpp create mode 100644 ELF/InputFiles.h create mode 100644 ELF/InputSection.cpp create mode 100644 ELF/InputSection.h create mode 100644 ELF/LinkerScript.cpp create mode 100644 ELF/MarkLive.cpp create mode 100644 ELF/Options.td create mode 100644 ELF/OutputSections.cpp create mode 100644 ELF/OutputSections.h create mode 100644 ELF/README.md create mode 100644 ELF/SymbolTable.cpp create mode 100644 ELF/SymbolTable.h create mode 100644 ELF/Symbols.cpp create mode 100644 ELF/Symbols.h create mode 100644 ELF/Target.cpp create mode 100644 ELF/Target.h create mode 100644 ELF/Writer.cpp create mode 100644 ELF/Writer.h delete mode 100644 Makefile delete mode 100644 docs/Makefile delete mode 100644 include/Makefile delete mode 100644 include/lld/Config/Makefile delete mode 100644 include/lld/Driver/WinLinkModuleDef.h delete mode 100644 include/lld/Makefile delete mode 100644 include/lld/ReaderWriter/ELFTargets.h delete mode 100644 include/lld/ReaderWriter/PECOFFLinkingContext.h delete mode 100644 include/lld/ReaderWriter/RelocationHelperFunctions.h delete mode 100644 lib/Config/Makefile delete mode 100644 lib/Core/Makefile delete mode 100644 lib/Core/TODO.txt delete mode 100644 lib/Driver/Makefile delete mode 100644 lib/Driver/WinLinkDriver.cpp delete mode 100644 lib/Driver/WinLinkModuleDef.cpp delete mode 100644 lib/Makefile delete mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h delete mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h delete mode 100644 lib/ReaderWriter/ELF/AArch64/Makefile create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h delete mode 100644 lib/ReaderWriter/ELF/ARM/ARMELFReader.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMELFWriters.h delete mode 100644 lib/ReaderWriter/ELF/ARM/Makefile create mode 100644 lib/ReaderWriter/ELF/Atoms.cpp delete mode 100644 lib/ReaderWriter/ELF/CreateELF.h delete mode 100644 lib/ReaderWriter/ELF/DefaultLayout.h delete mode 100644 lib/ReaderWriter/ELF/DefaultTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/DynamicFile.cpp create mode 100644 lib/ReaderWriter/ELF/ELFFile.cpp create mode 100644 lib/ReaderWriter/ELF/FileCommon.cpp create mode 100644 lib/ReaderWriter/ELF/FileCommon.h create mode 100644 lib/ReaderWriter/ELF/HeaderChunks.cpp delete mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h delete mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h delete mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h delete mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h delete mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h delete mode 100644 lib/ReaderWriter/ELF/Hexagon/Makefile delete mode 100644 lib/ReaderWriter/ELF/Layout.h delete mode 100644 lib/ReaderWriter/ELF/Makefile delete mode 100644 lib/ReaderWriter/ELF/Mips/Makefile create mode 100644 lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h delete mode 100644 lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp delete mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp delete mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h delete mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFReader.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp delete mode 100644 lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h create mode 100644 lib/ReaderWriter/ELF/OutputELFWriter.cpp create mode 100644 lib/ReaderWriter/ELF/SectionChunks.cpp create mode 100644 lib/ReaderWriter/ELF/SegmentChunks.cpp create mode 100644 lib/ReaderWriter/ELF/TargetLayout.cpp delete mode 100644 lib/ReaderWriter/ELF/X86/Makefile delete mode 100644 lib/ReaderWriter/ELF/X86/X86ELFFile.h delete mode 100644 lib/ReaderWriter/ELF/X86/X86ELFReader.h delete mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile delete mode 100644 lib/ReaderWriter/ELF/X86_64/Makefile delete mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h delete mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h delete mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h rename lib/ReaderWriter/MachO/{ExecutableAtoms.hpp => ExecutableAtoms.h} (79%) create mode 100644 lib/ReaderWriter/MachO/FlatNamespaceFile.h delete mode 100644 lib/ReaderWriter/MachO/Makefile create mode 100644 lib/ReaderWriter/MachO/SectCreateFile.h create mode 100644 lib/ReaderWriter/MachO/TLVPass.cpp delete mode 100644 lib/ReaderWriter/Makefile delete mode 100644 lib/ReaderWriter/Native/CMakeLists.txt delete mode 100644 lib/ReaderWriter/Native/Makefile delete mode 100644 lib/ReaderWriter/Native/NativeFileFormat.h delete mode 100644 lib/ReaderWriter/Native/ReaderNative.cpp delete mode 100644 lib/ReaderWriter/Native/WriterNative.cpp delete mode 100644 lib/ReaderWriter/PECOFF/Atoms.h delete mode 100644 lib/ReaderWriter/PECOFF/CMakeLists.txt delete mode 100644 lib/ReaderWriter/PECOFF/EdataPass.cpp delete mode 100644 lib/ReaderWriter/PECOFF/EdataPass.h delete mode 100644 lib/ReaderWriter/PECOFF/IdataPass.cpp delete mode 100644 lib/ReaderWriter/PECOFF/IdataPass.h delete mode 100644 lib/ReaderWriter/PECOFF/InferSubsystemPass.h delete mode 100644 lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp delete mode 100644 lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h delete mode 100644 lib/ReaderWriter/PECOFF/LoadConfigPass.cpp delete mode 100644 lib/ReaderWriter/PECOFF/LoadConfigPass.h delete mode 100644 lib/ReaderWriter/PECOFF/Makefile delete mode 100644 lib/ReaderWriter/PECOFF/OrderPass.h delete mode 100644 lib/ReaderWriter/PECOFF/PDBPass.h delete mode 100644 lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp delete mode 100644 lib/ReaderWriter/PECOFF/Pass.cpp delete mode 100644 lib/ReaderWriter/PECOFF/Pass.h delete mode 100644 lib/ReaderWriter/PECOFF/ReaderCOFF.cpp delete mode 100644 lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp delete mode 100644 lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp delete mode 100644 lib/ReaderWriter/PECOFF/WriterImportLibrary.h delete mode 100644 lib/ReaderWriter/PECOFF/WriterPECOFF.cpp delete mode 100644 lib/ReaderWriter/YAML/Makefile rename test/{pecoff/Inputs/executable.obj.yaml => COFF/Inputs/armnt-executable.obj.yaml} (97%) rename test/{pecoff/Inputs/executable.s => COFF/Inputs/armnt-executable.s} (83%) create mode 100644 test/COFF/Inputs/conflict.ll create mode 100644 test/COFF/Inputs/entry-mangled.ll create mode 100644 test/COFF/Inputs/export.ll rename test/{pecoff/Inputs/export.obj.yaml => COFF/Inputs/export.yaml} (69%) create mode 100644 test/COFF/Inputs/export2.yaml rename test/{pecoff/Inputs/reloc.obj.yaml => COFF/Inputs/hello32.yaml} (62%) create mode 100644 test/COFF/Inputs/hello64.asm create mode 100644 test/COFF/Inputs/hello64.obj rename test/{pecoff/Inputs/associative3.obj.yaml => COFF/Inputs/import.yaml} (62%) create mode 100644 test/COFF/Inputs/imports-mangle.lib rename test/{pecoff/Inputs/unknown-drectve.obj.yaml => COFF/Inputs/include1a.yaml} (53%) create mode 100644 test/COFF/Inputs/include1b.yaml create mode 100644 test/COFF/Inputs/include1c.yaml rename test/{pecoff => COFF}/Inputs/library.lib (100%) create mode 100644 test/COFF/Inputs/lto-chkstk-chkstk.s create mode 100644 test/COFF/Inputs/lto-chkstk-foo.s create mode 100644 test/COFF/Inputs/lto-comdat1.ll create mode 100644 test/COFF/Inputs/lto-comdat2.ll create mode 100644 test/COFF/Inputs/lto-dep.ll rename test/{pecoff/Inputs/tlsused.obj.yaml => COFF/Inputs/machine-x64.yaml} (65%) rename test/{pecoff/Inputs/alternatename2.obj.yaml => COFF/Inputs/machine-x86.yaml} (74%) rename test/{pecoff => COFF}/Inputs/resource.res (100%) mode change 100755 => 100644 create mode 100644 test/COFF/Inputs/ret42.lib create mode 100644 test/COFF/Inputs/ret42.obj rename test/{pecoff/Inputs/imagebase.obj.yaml => COFF/Inputs/ret42.yaml} (63%) create mode 100644 test/COFF/Inputs/std32.lib create mode 100644 test/COFF/Inputs/std64.lib create mode 100644 test/COFF/Inputs/weak-external.ll create mode 100644 test/COFF/Inputs/weak-external2.ll create mode 100644 test/COFF/Inputs/weak-external3.ll create mode 100644 test/COFF/alternatename.test create mode 100644 test/COFF/ar-comdat.test rename test/{pecoff/Inputs/armnt-blx23t.obj.yaml => COFF/armnt-blx23t.test} (54%) rename test/{pecoff/Inputs/armnt-branch24t.obj.yaml => COFF/armnt-branch24t.test} (61%) create mode 100644 test/COFF/armnt-entry-point.test rename test/{pecoff/Inputs/armnt-import.obj.yaml => COFF/armnt-imports.test} (76%) rename test/{pecoff/Inputs/armnt-mov32t-exec.obj.yaml => COFF/armnt-mov32t-exec.test} (61%) rename test/{pecoff/Inputs/armnt-mov32t.obj.yaml => COFF/armnt-movt32t.test} (74%) create mode 100644 test/COFF/base.test create mode 100644 test/COFF/baserel.test rename test/{pecoff/Inputs/common-symbol.obj.yaml => COFF/common.test} (73%) create mode 100644 test/COFF/conflict.test rename test/{pecoff/Inputs/subsystem.main.yaml => COFF/debug.test} (78%) create mode 100644 test/COFF/defparser.test create mode 100644 test/COFF/delayimports.test create mode 100644 test/COFF/delayimports32.test create mode 100644 test/COFF/dll.test create mode 100644 test/COFF/dllorder.test create mode 100644 test/COFF/driver.test create mode 100644 test/COFF/entry-inference.test rename test/{pecoff/Inputs/alternatename3.obj.yaml => COFF/entry-inference2.test} (63%) create mode 100644 test/COFF/entry-inference32.test rename test/{pecoff/Inputs/armnt-obj.yaml => COFF/entry-mangled.test} (53%) create mode 100644 test/COFF/entrylib.ll create mode 100644 test/COFF/export-exe.test create mode 100644 test/COFF/export.test create mode 100644 test/COFF/export32.test create mode 100644 test/COFF/failifmismatch.test create mode 100644 test/COFF/filetype.test create mode 100644 test/COFF/force.test create mode 100644 test/COFF/heap.test create mode 100644 test/COFF/hello32.test create mode 100644 test/COFF/help.test create mode 100644 test/COFF/icf-circular.test create mode 100644 test/COFF/icf-circular2.test rename test/{pecoff/Inputs/comdat.obj.yaml => COFF/icf-different-align.test} (59%) rename test/{pecoff/Inputs/secrel1.obj.yaml => COFF/icf-local.test} (50%) create mode 100644 test/COFF/icf-simple.test rename test/{pecoff/Inputs/vars-main-x64.obj.yaml => COFF/imports-mangle.test} (56%) create mode 100644 test/COFF/imports.test create mode 100644 test/COFF/include.test create mode 100644 test/COFF/include2.test create mode 100644 test/COFF/internal.test create mode 100644 test/COFF/invalid-obj.test create mode 100644 test/COFF/largeaddressaware.test create mode 100644 test/COFF/libpath.test create mode 100644 test/COFF/linkenv.test create mode 100644 test/COFF/lldmap.test create mode 100644 test/COFF/loadcfg.ll rename test/{pecoff/Inputs/associative1.obj.yaml => COFF/loadcfg.test} (63%) rename test/{pecoff/Inputs/subsystem.winmain.yaml => COFF/loadcfg32.test} (75%) create mode 100644 test/COFF/locally-imported.test rename test/{pecoff/Inputs/drectve2.obj.yaml => COFF/locally-imported32.test} (50%) rename test/{pecoff/Inputs/nop.obj.yaml => COFF/long-section-name.test} (73%) create mode 100644 test/COFF/lto-chkstk.ll create mode 100644 test/COFF/lto-comdat.ll create mode 100644 test/COFF/lto-linker-opts.ll create mode 100644 test/COFF/lto-new-symbol.ll create mode 100644 test/COFF/lto-opt-level.ll create mode 100644 test/COFF/lto-parallel.ll create mode 100644 test/COFF/lto.ll create mode 100644 test/COFF/machine.test rename test/{pecoff => COFF}/manifest.test (71%) rename test/{pecoff/Inputs/armnt-addr32-exec.obj.yaml => COFF/merge.test} (50%) create mode 100644 test/COFF/nodefaultlib.test create mode 100644 test/COFF/noentry.test create mode 100644 test/COFF/opt.test create mode 100644 test/COFF/options.test create mode 100644 test/COFF/order.test create mode 100644 test/COFF/out.test create mode 100644 test/COFF/reloc-arm.test create mode 100644 test/COFF/reloc-x64.test rename test/{pecoff/Inputs/main.obj.yaml => COFF/reloc-x86.test} (50%) create mode 100644 test/COFF/resource.test create mode 100644 test/COFF/responsefile.test create mode 100644 test/COFF/safeseh.test rename test/{pecoff/Inputs/nop64.obj.yaml => COFF/seh.test} (63%) create mode 100644 test/COFF/sort-debug.test create mode 100644 test/COFF/stack.test create mode 100644 test/COFF/subsystem-inference.test create mode 100644 test/COFF/subsystem.test create mode 100644 test/COFF/symtab.test rename test/{pecoff/Inputs/armnt-exports.obj.yaml => COFF/tls.test} (56%) create mode 100644 test/COFF/tls32.test rename test/{pecoff/Inputs/unwind.obj.yaml => COFF/unwind.test} (66%) create mode 100644 test/COFF/version.test create mode 100644 test/COFF/weak-external.test create mode 100644 test/COFF/weak-external2.test create mode 100644 test/COFF/weak-external3.test create mode 100644 test/ELF/Inputs/abs.s create mode 100644 test/ELF/Inputs/abs255.s create mode 100644 test/ELF/Inputs/abs256.s create mode 100644 test/ELF/Inputs/abs257.s create mode 100644 test/ELF/Inputs/allow-multiple-definition.s create mode 100644 test/ELF/Inputs/allow-shlib-undefined.s create mode 100644 test/ELF/Inputs/archive.s create mode 100644 test/ELF/Inputs/archive2.s create mode 100644 test/ELF/Inputs/archive3.s create mode 100644 test/ELF/Inputs/archive4.s create mode 100644 test/ELF/Inputs/comdat.s create mode 100644 test/ELF/Inputs/common.s create mode 100644 test/ELF/Inputs/discard-merge-unnamed.o create mode 100644 test/ELF/Inputs/dynamic-reloc.s create mode 100644 test/ELF/Inputs/invalid-binding.elf create mode 100644 test/ELF/Inputs/invalid-data-encoding.a create mode 100644 test/ELF/Inputs/invalid-file-class.a create mode 100644 test/ELF/Inputs/invalid-multiple-eh-relocs.elf create mode 100644 test/ELF/Inputs/invalid-section-index.elf create mode 100644 test/ELF/Inputs/invalid-shentsize-zero.elf create mode 100755 test/ELF/Inputs/invalid-shstrndx.so create mode 100644 test/ELF/Inputs/invalid-symtab-sh_info.elf create mode 100644 test/ELF/Inputs/libsearch-dyn.s create mode 100644 test/ELF/Inputs/libsearch-st.s create mode 100644 test/ELF/Inputs/merge.s create mode 100644 test/ELF/Inputs/mips-dynamic.s rename test/{elf/Inputs/stripped-empty.x86_64 => ELF/Inputs/no-symtab.o} (100%) create mode 100644 test/ELF/Inputs/relocation-copy-align.s create mode 100644 test/ELF/Inputs/relocation-copy.s create mode 100644 test/ELF/Inputs/relocation-size-shared.s create mode 100644 test/ELF/Inputs/resolution.s create mode 100644 test/ELF/Inputs/shared-ppc64.s create mode 100644 test/ELF/Inputs/shared.s create mode 100644 test/ELF/Inputs/shared2.s create mode 100644 test/ELF/Inputs/shared3.s create mode 100644 test/ELF/Inputs/tls-got.s create mode 100644 test/ELF/Inputs/tls-mismatch.s create mode 100644 test/ELF/Inputs/tls-opt-gdie.s create mode 100644 test/ELF/Inputs/tls-opt-gdiele-i686.s create mode 100644 test/ELF/Inputs/tls-opt-iele-i686-nopic.s create mode 100644 test/ELF/Inputs/visibility.s create mode 100644 test/ELF/Inputs/whole-archive.s create mode 100644 test/ELF/aarch64-abs16.s create mode 100644 test/ELF/aarch64-abs32.s create mode 100644 test/ELF/aarch64-call26-error.s create mode 100644 test/ELF/aarch64-copy.s create mode 100644 test/ELF/aarch64-data-relocs.s create mode 100644 test/ELF/aarch64-fpic-abs16.s create mode 100644 test/ELF/aarch64-fpic-add_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-adr_prel_lo21.s create mode 100644 test/ELF/aarch64-fpic-adr_prel_pg_hi21.s create mode 100644 test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-prel16.s create mode 100644 test/ELF/aarch64-fpic-prel32.s create mode 100644 test/ELF/aarch64-fpic-prel64.s create mode 100644 test/ELF/aarch64-hi21-error.s create mode 100644 test/ELF/aarch64-jump26-error.s create mode 100644 test/ELF/aarch64-lo21-error.s create mode 100644 test/ELF/aarch64-prel16.s create mode 100644 test/ELF/aarch64-prel32.s create mode 100644 test/ELF/aarch64-relocs.s create mode 100644 test/ELF/allow-multiple-definition.s create mode 100644 test/ELF/allow-shlib-undefined.s create mode 100644 test/ELF/archive.s create mode 100644 test/ELF/as-needed.s create mode 100644 test/ELF/basic-aarch64.s create mode 100644 test/ELF/basic-freebsd.s create mode 100644 test/ELF/basic-mips.s create mode 100644 test/ELF/basic.s create mode 100644 test/ELF/basic32.s create mode 100644 test/ELF/basic64be.s create mode 100644 test/ELF/bss.s create mode 100644 test/ELF/comdat.s create mode 100644 test/ELF/common.s create mode 100644 test/ELF/default-output.s create mode 100644 test/ELF/discard-locals.s create mode 100644 test/ELF/discard-merge-locals.s create mode 100644 test/ELF/discard-merge-unnamed.s create mode 100644 test/ELF/discard-none.s create mode 100644 test/ELF/dt_flags.s create mode 100644 test/ELF/duplicate-internal.s create mode 100644 test/ELF/dynamic-reloc-index.s create mode 100644 test/ELF/dynamic-reloc-weak.s create mode 100644 test/ELF/dynamic-reloc.s create mode 100644 test/ELF/eh-align-cie.s create mode 100644 test/ELF/eh-frame-merge.s create mode 100644 test/ELF/eh-frame-plt.s create mode 100644 test/ELF/eh-frame-rel.s create mode 100644 test/ELF/eh-frame-type.test create mode 100644 test/ELF/ehframe-relocation.s create mode 100644 test/ELF/empty-archive.s create mode 100644 test/ELF/emulation.s create mode 100644 test/ELF/end-preserve.s create mode 100644 test/ELF/end-update.s create mode 100644 test/ELF/end.s create mode 100644 test/ELF/entry.s create mode 100644 test/ELF/gc-sections-eh.s create mode 100644 test/ELF/gc-sections-print.s create mode 100644 test/ELF/gc-sections.s create mode 100644 test/ELF/global_offset_table.s create mode 100644 test/ELF/gnu-hash-table.s create mode 100644 test/ELF/gnu-ifunc-i386.s create mode 100644 test/ELF/gnu-ifunc-nosym-i386.s create mode 100644 test/ELF/gnu-ifunc-nosym.s create mode 100644 test/ELF/gnu-ifunc.s create mode 100644 test/ELF/gnu-unique.s create mode 100644 test/ELF/gnustack.s create mode 100644 test/ELF/got-aarch64.s create mode 100644 test/ELF/got-i386.s create mode 100644 test/ELF/got.s create mode 100644 test/ELF/incompatible-ar-first.s create mode 100644 test/ELF/incompatible.s create mode 100644 test/ELF/init-fini.s create mode 100644 test/ELF/invalid-cie-length.s create mode 100644 test/ELF/invalid-cie-length2.s create mode 100644 test/ELF/invalid-cie-length3.s create mode 100644 test/ELF/invalid-cie-length4.s create mode 100644 test/ELF/invalid-cie-length5.s create mode 100644 test/ELF/invalid-cie-reference.s create mode 100644 test/ELF/invalid-elf.test create mode 100644 test/ELF/invalid-fde-rel.s create mode 100644 test/ELF/invalid-relocations.test create mode 100644 test/ELF/libsearch.s create mode 100644 test/ELF/linkerscript-ouputformat.s create mode 100644 test/ELF/linkerscript-outputarch.s create mode 100644 test/ELF/linkerscript-sections.s create mode 100644 test/ELF/linkerscript.s create mode 100644 test/ELF/linkerscript2.s create mode 100644 test/ELF/lit.local.cfg create mode 100644 test/ELF/local-dynamic.s create mode 100644 test/ELF/local-got-shared.s create mode 100644 test/ELF/local-got.s create mode 100644 test/ELF/local.s create mode 100644 test/ELF/many-sections.s create mode 100644 test/ELF/merge-invalid-size.s create mode 100644 test/ELF/merge-shared.s create mode 100644 test/ELF/merge-string-align.s create mode 100644 test/ELF/merge-string-error.s create mode 100644 test/ELF/merge-string-no-null.s create mode 100644 test/ELF/merge-string.s create mode 100644 test/ELF/merge-sym.s create mode 100644 test/ELF/merge.s create mode 100644 test/ELF/mips-call16.s create mode 100644 test/ELF/mips-dynamic.s create mode 100644 test/ELF/mips-dynsym-sort.s create mode 100644 test/ELF/mips-elf-flags.s create mode 100644 test/ELF/mips-gnu-hash.s create mode 100644 test/ELF/mips-got-relocs.s create mode 100644 test/ELF/mips-gprel32-relocs.s create mode 100644 test/ELF/mips-hilo-gp-disp.s create mode 100644 test/ELF/mips-hilo-hi-only.s create mode 100644 test/ELF/mips-hilo.s create mode 100644 test/ELF/mips-jalr.test create mode 100644 test/ELF/mips-pc-relocs.s create mode 100644 test/ELF/mips-reginfo.s create mode 100644 test/ELF/mips-relocs.s create mode 100644 test/ELF/new-dtags.test create mode 100644 test/ELF/no-inhibit-exec.s create mode 100644 test/ELF/no-obj.s create mode 100644 test/ELF/no-symtab.s create mode 100644 test/ELF/no-undefined.s create mode 100644 test/ELF/output-section.s create mode 100644 test/ELF/plt-aarch64.s create mode 100644 test/ELF/plt-i686.s create mode 100644 test/ELF/plt.s create mode 100644 test/ELF/ppc64-addr16-error.s create mode 100644 test/ELF/ppc64-rel-calls.s create mode 100644 test/ELF/ppc64-relocs.s create mode 100644 test/ELF/ppc64-shared-rel-toc.s create mode 100644 test/ELF/ppc64-toc-restore.s create mode 100644 test/ELF/ppc64-weak-undef-call-shared.s create mode 100644 test/ELF/ppc64-weak-undef-call.s create mode 100644 test/ELF/pre_init_fini_array.s create mode 100644 test/ELF/pre_init_fini_array_missing.s create mode 100644 test/ELF/progname.s create mode 100644 test/ELF/program-header-layout.s create mode 100644 test/ELF/relative-dynamic-reloc-ppc64.s create mode 100644 test/ELF/relative-dynamic-reloc.s create mode 100644 test/ELF/relocatable.s create mode 100644 test/ELF/relocation-absolute.s create mode 100644 test/ELF/relocation-common.s create mode 100644 test/ELF/relocation-copy-align.s create mode 100644 test/ELF/relocation-copy-i686.s create mode 100644 test/ELF/relocation-copy.s create mode 100644 test/ELF/relocation-i686.s create mode 100644 test/ELF/relocation-in-merge.s create mode 100644 test/ELF/relocation-local.s create mode 100644 test/ELF/relocation-past-merge-end.s create mode 100644 test/ELF/relocation-size-shared.s create mode 100644 test/ELF/relocation-size.s create mode 100644 test/ELF/relocation-undefined-weak.s create mode 100644 test/ELF/relocation.s create mode 100644 test/ELF/relro.s create mode 100644 test/ELF/resolution.s create mode 100644 test/ELF/section-align-0.test create mode 100644 test/ELF/section-layout.s create mode 100644 test/ELF/section-name.s create mode 100644 test/ELF/section-symbol.s create mode 100644 test/ELF/shared-be.s create mode 100644 test/ELF/shared.s create mode 100644 test/ELF/soname.s create mode 100644 test/ELF/soname2.s create mode 100644 test/ELF/startstop-shared.s create mode 100644 test/ELF/startstop.s create mode 100644 test/ELF/string-table.s create mode 100644 test/ELF/strip-all.s create mode 100644 test/ELF/symbols.s create mode 100644 test/ELF/sysroot.s create mode 100644 test/ELF/tls-align.s create mode 100644 test/ELF/tls-dynamic-i686.s create mode 100644 test/ELF/tls-dynamic.s create mode 100644 test/ELF/tls-error.s create mode 100644 test/ELF/tls-got.s create mode 100644 test/ELF/tls-i686.s create mode 100644 test/ELF/tls-mismatch.s create mode 100644 test/ELF/tls-opt-gdie.s create mode 100644 test/ELF/tls-opt-gdiele-i686.s create mode 100644 test/ELF/tls-opt-i686.s create mode 100644 test/ELF/tls-opt-iele-i686-nopic.s create mode 100644 test/ELF/tls-opt-local.s create mode 100644 test/ELF/tls-opt.s create mode 100644 test/ELF/tls-static.s create mode 100644 test/ELF/tls.s create mode 100644 test/ELF/undef-start.s create mode 100644 test/ELF/undef.s create mode 100644 test/ELF/undefined-opt.s create mode 100644 test/ELF/valid-cie-length-dw64.s create mode 100644 test/ELF/visibility.s create mode 100644 test/ELF/whole-archive.s create mode 100644 test/ELF/writable-merge.s create mode 100644 test/ELF/x86-64-reloc-32-error.s create mode 100644 test/ELF/x86-64-reloc-32S-error.s create mode 100644 test/LinkerScript/phdrs-sections.test delete mode 100644 test/Makefile create mode 100644 test/core/Inputs/archive-basic.objtxt create mode 100644 test/core/Inputs/archive-chain.objtxt create mode 100644 test/core/Inputs/archive-chain2.objtxt create mode 100644 test/core/Inputs/archive-tentdef-search.objtxt create mode 100644 test/core/Inputs/associates.objtxt create mode 100644 test/core/Inputs/auto-hide-coalesce.objtxt create mode 100644 test/core/Inputs/code-model-attributes.objtxt create mode 100644 test/core/Inputs/code-model-attributes2.objtxt create mode 100644 test/core/Inputs/code-model-attributes3.objtxt create mode 100644 test/core/Inputs/code-model-attributes4.objtxt create mode 100644 test/core/Inputs/code-model-attributes5.objtxt create mode 100644 test/core/Inputs/constants-coalesce.objtxt create mode 100644 test/core/Inputs/constants-coalesce2.objtxt create mode 100644 test/core/Inputs/cstring-coalesce.objtxt create mode 100644 test/core/Inputs/cstring-coalesce2.objtxt create mode 100644 test/core/Inputs/custom-section-coalesce.objtxt create mode 100644 test/core/Inputs/custom-section-coalesce2.objtxt create mode 100644 test/core/Inputs/dead-strip-attributes.objtxt create mode 100644 test/core/Inputs/dead-strip-attributes2.objtxt create mode 100644 test/core/Inputs/dead-strip-basic.objtxt create mode 100644 test/core/Inputs/dead-strip-basic2.objtxt create mode 100644 test/core/Inputs/dead-strip-globals.objtxt create mode 100644 test/core/Inputs/dead-strip-globals2.objtxt create mode 100644 test/core/Inputs/error-duplicate-absolutes.objtxt create mode 100644 test/core/Inputs/gnulinkonce-rearrange-resolve.objtxt create mode 100644 test/core/Inputs/gnulinkonce-remaining-undef.objtxt create mode 100644 test/core/Inputs/gnulinkonce-remaining-undef2.objtxt create mode 100644 test/core/Inputs/gnulinkonce-resolve.objtxt create mode 100644 test/core/Inputs/gnulinkonce-simple.objtxt create mode 100644 test/core/Inputs/inline-coalesce.objtxt create mode 100644 test/core/Inputs/inline-coalesce2.objtxt create mode 100644 test/core/Inputs/multiple-def-error.objtxt create mode 100644 test/core/Inputs/sectiongroup-deadstrip.objtxt create mode 100644 test/core/Inputs/sectiongroup-gnulinkonce-error.objtxt create mode 100644 test/core/Inputs/sectiongroup-rearrange-resolve.objtxt create mode 100644 test/core/Inputs/sectiongroup-remaining-undef.objtxt create mode 100644 test/core/Inputs/sectiongroup-remaining-undef2.objtxt create mode 100644 test/core/Inputs/sectiongroup-resolve.objtxt create mode 100644 test/core/Inputs/sectiongroup-simple.objtxt create mode 100644 test/core/Inputs/shared-library-coalesce.objtxt create mode 100644 test/core/Inputs/tent-merge.objtxt create mode 100644 test/core/Inputs/undef-coalesce-error.objtxt create mode 100644 test/core/Inputs/undef-coalesce-error2.objtxt create mode 100644 test/core/Inputs/undef-coalesce.objtxt create mode 100644 test/core/Inputs/undef-coalesce2.objtxt create mode 100644 test/core/Inputs/undef-fallback.objtxt create mode 100644 test/core/Inputs/undef-weak-coalesce.objtxt create mode 100644 test/core/Inputs/weak-coalesce.objtxt create mode 100644 test/core/Inputs/weak-coalesce2.objtxt create mode 100644 test/darwin/Inputs/native-and-mach-o.objtxt create mode 100644 test/darwin/Inputs/native-and-mach-o2.objtxt delete mode 100644 test/elf/ARM/rel-arm-prel31.test delete mode 100644 test/elf/Inputs/init_array.x86-64 delete mode 100644 test/elf/Mips/hilo16-1.test delete mode 100644 test/elf/Mips/hilo16-2.test delete mode 100644 test/elf/Mips/hilo16-3.test delete mode 100644 test/elf/Mips/hilo16-8-micro.test delete mode 100644 test/elf/Mips/hilo16-9-micro.test delete mode 100644 test/elf/Mips/r26-2-micro.test delete mode 100644 test/elf/Mips/r26-2.test delete mode 100644 test/elf/Mips/rel-dynamic-02.test delete mode 100644 test/elf/Mips/rel-dynamic-06-64.test delete mode 100644 test/elf/Mips/rel-dynamic-06.test delete mode 100644 test/elf/X86_64/demangle.test delete mode 100644 test/elf/X86_64/dynlib-nointerp-section.test delete mode 100644 test/elf/X86_64/extern-tls.test delete mode 100644 test/elf/init_array.test create mode 100644 test/mach-o/Inputs/PIE.yaml create mode 100644 test/mach-o/Inputs/arm-interworking.yaml create mode 100644 test/mach-o/Inputs/arm-shims.yaml create mode 100644 test/mach-o/Inputs/cstring-sections.yaml create mode 100644 test/mach-o/Inputs/got-order.yaml create mode 100644 test/mach-o/Inputs/got-order2.yaml create mode 100644 test/mach-o/Inputs/hello-world-arm64.yaml create mode 100644 test/mach-o/Inputs/hello-world-armv6.yaml create mode 100644 test/mach-o/Inputs/hello-world-armv7.yaml create mode 100644 test/mach-o/Inputs/hello-world-x86.yaml create mode 100644 test/mach-o/Inputs/hello-world-x86_64.yaml create mode 100644 test/mach-o/Inputs/hw.raw_bytes create mode 100644 test/mach-o/Inputs/interposing-section.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64-2.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64-3.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64.yaml create mode 100644 test/mach-o/Inputs/linker-as-ld.yaml create mode 100644 test/mach-o/Inputs/re-exported-dylib-ordinal.yaml create mode 100644 test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml create mode 100644 test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml create mode 100644 test/mach-o/Inputs/unwind-info-simple-arm64.yaml create mode 100644 test/mach-o/Inputs/use-simple-dylib.yaml create mode 100644 test/mach-o/Inputs/write-final-sections.yaml create mode 100644 test/mach-o/Inputs/wrong-arch-error.yaml create mode 100644 test/mach-o/arm64-reloc-negDelta32-fixup.yaml create mode 100644 test/mach-o/arm64-relocs-errors-delta64-offset.yaml rename test/mach-o/{dylib-exports.yaml => executable-exports.yaml} (79%) create mode 100644 test/mach-o/flat_namespace_undef_error.yaml create mode 100644 test/mach-o/flat_namespace_undef_suppress.yaml create mode 100644 test/mach-o/gcc_except_tab-got-arm64.yaml create mode 100644 test/mach-o/parse-eh-frame-relocs-x86_64.yaml create mode 100644 test/mach-o/parse-tlv-relocs-x86-64.yaml create mode 100644 test/mach-o/run-tlv-pass-x86-64.yaml create mode 100644 test/mach-o/sectcreate.yaml create mode 100644 test/mach-o/stack-size.yaml create mode 100644 test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml create mode 100644 test/mach-o/twolevel_namespace_undef_warning_suppress.yaml rename test/{elf => old-elf}/AArch64/Inputs/fn.c (100%) rename test/{elf => old-elf}/AArch64/Inputs/fn.o (100%) create mode 100644 test/old-elf/AArch64/Inputs/general-dyn-tls-0.yaml rename test/{elf => old-elf}/AArch64/Inputs/initfini-option.c (100%) rename test/{elf => old-elf}/AArch64/Inputs/initfini-option.o (100%) rename test/{elf => old-elf}/AArch64/Inputs/initfini.c (100%) rename test/{elf => old-elf}/AArch64/Inputs/initfini.o (100%) create mode 100644 test/old-elf/AArch64/Inputs/initial-exec-tls-1.yaml rename test/{elf => old-elf}/AArch64/Inputs/main.c (100%) rename test/{elf => old-elf}/AArch64/Inputs/main.o (100%) rename test/{elf => old-elf}/AArch64/Inputs/no-interp-section.c (100%) rename test/{elf => old-elf}/AArch64/Inputs/no-interp-section.o (100%) rename test/{elf => old-elf}/AArch64/Inputs/zerosizedsection.o (100%) rename test/{elf => old-elf}/AArch64/Inputs/zerosizedsection.s (100%) rename test/{elf => old-elf}/AArch64/defsym.test (87%) rename test/{elf => old-elf}/AArch64/dontignorezerosize-sections.test (76%) create mode 100644 test/old-elf/AArch64/dynamicvars.test rename test/{elf => old-elf}/AArch64/dynlib-nointerp-section.test (52%) create mode 100644 test/old-elf/AArch64/general-dyn-tls-0.test rename test/{elf => old-elf}/AArch64/initfini.test (91%) create mode 100644 test/old-elf/AArch64/initial-exec-tls-0.test create mode 100644 test/old-elf/AArch64/local-tls.test create mode 100644 test/old-elf/AArch64/rel-abs16-overflow.test create mode 100644 test/old-elf/AArch64/rel-abs16.test rename test/{elf => old-elf}/AArch64/rel-abs32-overflow.test (93%) rename test/{elf => old-elf}/AArch64/rel-abs32.test (95%) rename test/{elf => old-elf}/AArch64/rel-abs64.test (95%) create mode 100644 test/old-elf/AArch64/rel-adr_prel_lo21-overflow.test create mode 100644 test/old-elf/AArch64/rel-adr_prel_lo21.test create mode 100644 test/old-elf/AArch64/rel-adr_prel_pg_hi21-overflow.test create mode 100644 test/old-elf/AArch64/rel-adr_prel_pg_hi21.test rename test/{elf => old-elf}/AArch64/rel-bad.test (91%) create mode 100644 test/old-elf/AArch64/rel-prel16-overflow.test create mode 100644 test/old-elf/AArch64/rel-prel16.test create mode 100644 test/old-elf/AArch64/rel-prel32-overflow.test create mode 100644 test/old-elf/AArch64/rel-prel32.test create mode 100644 test/old-elf/AArch64/rel-prel64.test create mode 100644 test/old-elf/AMDGPU/hsa.test create mode 100644 test/old-elf/ARM/Inputs/fn.c create mode 100755 test/old-elf/ARM/Inputs/libfn.so create mode 100755 test/old-elf/ARM/Inputs/libobj.so create mode 100644 test/old-elf/ARM/Inputs/obj.c rename test/{elf => old-elf}/ARM/arm-symbols.test (95%) rename test/{elf => old-elf}/ARM/defsym.test (94%) create mode 100644 test/old-elf/ARM/dynamic-symbols.test rename test/{elf => old-elf}/ARM/entry-point.test (62%) create mode 100644 test/old-elf/ARM/exidx.test create mode 100644 test/old-elf/ARM/header-flags.test create mode 100644 test/old-elf/ARM/mapping-code-model.test create mode 100644 test/old-elf/ARM/mapping-symbols.test rename test/{elf => old-elf}/ARM/missing-symbol.test (92%) create mode 100644 test/old-elf/ARM/plt-dynamic.test create mode 100644 test/old-elf/ARM/plt-ifunc-interwork.test create mode 100644 test/old-elf/ARM/plt-ifunc-mapping.test rename test/{elf => old-elf}/ARM/rel-abs32.test (95%) rename test/{elf => old-elf}/ARM/rel-arm-call.test (51%) rename test/{elf => old-elf}/ARM/rel-arm-jump24-veneer-b.test (62%) rename test/{elf => old-elf}/ARM/rel-arm-jump24-veneer-bl.test (62%) rename test/{elf => old-elf}/ARM/rel-arm-jump24.test (51%) rename test/{elf => old-elf}/ARM/rel-arm-mov.test (95%) create mode 100644 test/old-elf/ARM/rel-arm-prel31.test create mode 100644 test/old-elf/ARM/rel-arm-target1.test rename test/{elf => old-elf}/ARM/rel-arm-thm-interwork.test (97%) create mode 100644 test/old-elf/ARM/rel-base-prel.test rename test/{elf/ARM/rel-thm-jump24.test => old-elf/ARM/rel-copy.test} (56%) create mode 100644 test/old-elf/ARM/rel-glob-dat.test rename test/{elf/ARM/rel-thm-call.test => old-elf/ARM/rel-got-brel.test} (52%) create mode 100644 test/old-elf/ARM/rel-group-relocs.test create mode 100644 test/old-elf/ARM/rel-ifunc.test create mode 100644 test/old-elf/ARM/rel-jump-slot.test rename test/{elf => old-elf}/ARM/rel-rel32.test (94%) create mode 100644 test/old-elf/ARM/rel-thm-call.test rename test/{elf => old-elf}/ARM/rel-thm-jump11.test (52%) rename test/{elf => old-elf}/ARM/rel-thm-jump24-veneer.test (64%) create mode 100644 test/old-elf/ARM/rel-thm-jump24.test rename test/{elf => old-elf}/ARM/rel-thm-mov.test (96%) rename test/{elf => old-elf}/ARM/rel-tls-ie32.test (68%) rename test/{elf => old-elf}/ARM/rel-tls-le32.test (66%) create mode 100644 test/old-elf/ARM/rel-v4bx.test rename test/{elf => old-elf}/ARM/thm-symbols.test (95%) create mode 100644 test/old-elf/ARM/two-got-for-symbol.test rename test/{elf => old-elf}/ARM/undef-lazy-symbol.test (88%) create mode 100644 test/old-elf/ARM/veneer-mapping.test create mode 100644 test/old-elf/ARM/weak-branch.test rename test/{elf => old-elf}/Hexagon/Inputs/dynobj-data.c (100%) rename test/{elf => old-elf}/Hexagon/Inputs/dynobj-data.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/dynobj.c (100%) rename test/{elf => old-elf}/Hexagon/Inputs/dynobj.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/got-plt-order.c (100%) rename test/{elf => old-elf}/Hexagon/Inputs/got-plt-order.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/libMaxAlignment.a (100%) rename test/{elf => old-elf}/Hexagon/Inputs/sda-base.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/sdata1.c (100%) rename test/{elf => old-elf}/Hexagon/Inputs/sdata1.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/sdata2.c (100%) rename test/{elf => old-elf}/Hexagon/Inputs/sdata2.o (100%) rename test/{elf => old-elf}/Hexagon/Inputs/use-shared.hexagon (100%) rename test/{elf => old-elf}/Hexagon/dynlib-data.test (84%) rename test/{elf => old-elf}/Hexagon/dynlib-gotoff.test (92%) rename test/{elf => old-elf}/Hexagon/dynlib-hash.test (83%) rename test/{elf => old-elf}/Hexagon/dynlib-rela.test (74%) rename test/{elf => old-elf}/Hexagon/dynlib-syms.test (75%) rename test/{elf => old-elf}/Hexagon/dynlib.test (91%) rename test/{elf => old-elf}/Hexagon/hexagon-got-plt-order.test (51%) rename test/{elf => old-elf}/Hexagon/hexagon-plt-setup.test (82%) rename test/{elf => old-elf}/Hexagon/maxalignment.test (73%) rename test/{elf => old-elf}/Hexagon/rela-order.test (71%) rename test/{elf => old-elf}/Hexagon/sda-base.test (50%) rename test/{elf => old-elf}/Hexagon/zerofillquick-sdata.test (88%) rename test/{elf => old-elf}/Inputs/abs-test.i386 (100%) create mode 100644 test/old-elf/Inputs/allowduplicates.objtxt rename test/{elf => old-elf}/Inputs/bar.o.x86-64 (100%) rename test/{elf => old-elf}/Inputs/branch-test.hexagon (100%) rename test/{elf => old-elf}/Inputs/branch-test.ppc (100%) rename test/{elf => old-elf}/Inputs/consecutive-weak-defs.o.yaml (92%) rename test/{elf => old-elf}/Inputs/constants-merge.x86-64 (100%) rename test/{elf => old-elf}/Inputs/constdata.x86-64 (100%) rename test/{elf => old-elf}/Inputs/foo.o.x86-64 (100%) rename test/{elf => old-elf}/Inputs/globalconst.c (100%) rename test/{elf => old-elf}/Inputs/globalconst.o.x86-64 (100%) rename test/{elf => old-elf}/Inputs/gotpcrel.S (100%) rename test/{elf => old-elf}/Inputs/gotpcrel.x86-64 (100%) rename test/{elf => old-elf}/Inputs/group-cmd-search-1.ls (100%) rename test/{elf => old-elf}/Inputs/group-cmd-search-2.ls (100%) rename test/{elf => old-elf}/Inputs/group-cmd-search-3.ls (100%) rename test/{elf => old-elf}/Inputs/ifunc.S (100%) rename test/{elf => old-elf}/Inputs/ifunc.cpp (100%) rename test/{elf => old-elf}/Inputs/ifunc.cpp.x86-64 (100%) rename test/{elf => old-elf}/Inputs/ifunc.x86-64 (100%) rename test/{elf => old-elf}/Inputs/libfnarchive.a (100%) rename test/{elf => old-elf}/Inputs/libifunc.x86-64.so (100%) rename test/{elf => old-elf}/Inputs/libundef.so (100%) rename test/{elf => old-elf}/Inputs/libweaksym.so (100%) rename test/{elf => old-elf}/Inputs/main-with-global-def.o.yaml (92%) rename test/{elf => old-elf}/Inputs/mainobj.x86_64 (100%) create mode 100644 test/old-elf/Inputs/no-unique-section-names.x86-64 rename test/{elf => old-elf}/Inputs/object-test.elf-hexagon (100%) rename test/{elf => old-elf}/Inputs/object-test.elf-i386 (100%) rename test/{elf => old-elf}/Inputs/phdr.i386 (100%) rename test/{elf => old-elf}/Inputs/quickdata-sort-test.o.elf-hexagon (100%) rename test/{elf => old-elf}/Inputs/quickdata-sortcommon-test.o.elf-hexagon (100%) rename test/{elf => old-elf}/Inputs/quickdata-test.elf-hexagon (100%) rename test/{elf => old-elf}/Inputs/reloc-test.elf-i386 (100%) rename test/{elf => old-elf}/Inputs/reloc-xb.x86 (100%) rename test/{elf => old-elf}/Inputs/reloc-xt.x86 (100%) rename test/{elf => old-elf}/Inputs/relocs-dynamic.x86-64 (100%) rename test/{elf => old-elf}/Inputs/relocs.x86-64 (100%) rename test/{elf => old-elf}/Inputs/responsefile (100%) rename test/{elf => old-elf}/Inputs/rodata-test.hexagon (100%) rename test/{elf => old-elf}/Inputs/rodata-test.i386 (100%) rename test/{elf => old-elf}/Inputs/rodata.c (100%) rename test/{elf => old-elf}/Inputs/rodata.o (100%) rename test/{elf => old-elf}/Inputs/section-test.i386 (100%) rename test/{elf => old-elf}/Inputs/shared.c (100%) rename test/{elf => old-elf}/Inputs/shared.so-x86-64 (100%) create mode 100644 test/old-elf/Inputs/shndx.o-x86_64 create mode 100644 test/old-elf/Inputs/stripped-empty.x86_64 rename test/{elf => old-elf}/Inputs/target-test.hexagon (100%) rename test/{elf => old-elf}/Inputs/target-test.ppc (100%) create mode 100644 test/old-elf/Inputs/tls-tbss-size.yaml rename test/{elf => old-elf}/Inputs/tls.S (100%) rename test/{elf => old-elf}/Inputs/tls.c (100%) rename test/{elf => old-elf}/Inputs/tls.x86-64 (100%) rename test/{elf => old-elf}/Inputs/tlsAddr.x86-64 (100%) rename test/{elf => old-elf}/Inputs/tlsaddr.c (100%) rename test/{elf => old-elf}/Inputs/undef-from-main-so.c (100%) rename test/{elf => old-elf}/Inputs/undef-from-main.c (100%) rename test/{elf => old-elf}/Inputs/undef-pc32.o (100%) rename test/{elf => old-elf}/Inputs/undef.o (100%) rename test/{elf => old-elf}/Inputs/undef2-so.o.yaml (98%) rename test/{elf => old-elf}/Inputs/use-shared-32s.c (100%) rename test/{elf => old-elf}/Inputs/use-shared-32s.x86-64 (100%) rename test/{elf => old-elf}/Inputs/use-shared.c (100%) rename test/{elf => old-elf}/Inputs/use-shared.x86-64 (100%) rename test/{elf => old-elf}/Inputs/weaksym.o (100%) rename test/{elf => old-elf}/Inputs/writersyms.o (100%) rename test/{elf => old-elf}/Inputs/x86-64-relocs.S (100%) create mode 100644 test/old-elf/Mips/abi-flags-01.test create mode 100644 test/old-elf/Mips/abi-flags-02.test create mode 100644 test/old-elf/Mips/abi-flags-03.test create mode 100644 test/old-elf/Mips/abi-flags-04.test create mode 100644 test/old-elf/Mips/abi-flags-05.test create mode 100644 test/old-elf/Mips/abi-flags-06.test create mode 100644 test/old-elf/Mips/abi-flags-07.test create mode 100644 test/old-elf/Mips/abi-flags-08.test create mode 100644 test/old-elf/Mips/abi-flags-09.test create mode 100644 test/old-elf/Mips/abi-flags-10.test create mode 100644 test/old-elf/Mips/abi-flags-11.test rename test/{elf => old-elf}/Mips/base-address-64.test (91%) rename test/{elf => old-elf}/Mips/base-address.test (80%) rename test/{elf => old-elf}/Mips/ctors-order.test (91%) create mode 100644 test/old-elf/Mips/driver-hash-style.test rename test/{elf => old-elf}/Mips/dt-textrel-64.test (91%) rename test/{elf => old-elf}/Mips/dt-textrel.test (92%) create mode 100644 test/old-elf/Mips/dynamic-linking.test create mode 100644 test/old-elf/Mips/dynamic-sym.test rename test/{elf => old-elf}/Mips/dynlib-dynamic.test (97%) rename test/{elf => old-elf}/Mips/dynlib-dynsym-micro.test (94%) rename test/{elf => old-elf}/Mips/dynlib-dynsym.test (94%) rename test/{elf => old-elf}/Mips/dynlib-fileheader-64.test (83%) rename test/{elf => old-elf}/Mips/dynlib-fileheader-micro-64.test (85%) rename test/{elf => old-elf}/Mips/dynlib-fileheader-micro.test (82%) rename test/{elf => old-elf}/Mips/dynlib-fileheader.test (81%) rename test/{elf => old-elf}/Mips/dynsym-table-1.test (92%) rename test/{elf => old-elf}/Mips/dynsym-table-2.test (93%) rename test/{elf => old-elf}/Mips/e-flags-merge-1-64.test (88%) rename test/{elf => old-elf}/Mips/e-flags-merge-1.test (88%) rename test/{elf => old-elf}/Mips/e-flags-merge-10.test (94%) rename test/{elf => old-elf}/Mips/e-flags-merge-11.test (93%) create mode 100644 test/old-elf/Mips/e-flags-merge-12.test rename test/{elf => old-elf}/Mips/e-flags-merge-2-64.test (92%) rename test/{elf => old-elf}/Mips/e-flags-merge-2.test (93%) rename test/{elf => old-elf}/Mips/e-flags-merge-3-64.test (91%) rename test/{elf => old-elf}/Mips/e-flags-merge-3.test (92%) rename test/{elf => old-elf}/Mips/e-flags-merge-4-64.test (96%) rename test/{elf => old-elf}/Mips/e-flags-merge-4.test (96%) rename test/{elf => old-elf}/Mips/e-flags-merge-5-64.test (87%) rename test/{elf => old-elf}/Mips/e-flags-merge-5.test (87%) rename test/{elf => old-elf}/Mips/e-flags-merge-6-64.test (96%) rename test/{elf => old-elf}/Mips/e-flags-merge-6.test (96%) rename test/{elf => old-elf}/Mips/e-flags-merge-7-64.test (93%) rename test/{elf => old-elf}/Mips/e-flags-merge-7.test (94%) rename test/{elf => old-elf}/Mips/e-flags-merge-8.test (94%) rename test/{elf => old-elf}/Mips/e-flags-merge-9.test (94%) rename test/{elf => old-elf}/Mips/entry-name.test (80%) rename test/{elf => old-elf}/Mips/exe-dynamic.test (79%) rename test/{elf => old-elf}/Mips/exe-dynsym-micro.test (92%) rename test/{elf => old-elf}/Mips/exe-dynsym.test (92%) create mode 100644 test/old-elf/Mips/exe-fileheader-02.test create mode 100644 test/old-elf/Mips/exe-fileheader-03.test rename test/{elf => old-elf}/Mips/exe-fileheader-64.test (82%) create mode 100644 test/old-elf/Mips/exe-fileheader-be-64.test create mode 100644 test/old-elf/Mips/exe-fileheader-be.test rename test/{elf => old-elf}/Mips/exe-fileheader-micro-64.test (84%) rename test/{elf => old-elf}/Mips/exe-fileheader-micro.test (82%) create mode 100644 test/old-elf/Mips/exe-fileheader-n32.test rename test/{elf => old-elf}/Mips/exe-fileheader.test (83%) rename test/{elf => old-elf}/Mips/exe-got-micro.test (92%) rename test/{elf => old-elf}/Mips/exe-got.test (92%) create mode 100644 test/old-elf/Mips/got-page-32-micro.test rename test/{elf => old-elf}/Mips/got-page-32.test (65%) create mode 100644 test/old-elf/Mips/got-page-64-micro.test rename test/{elf => old-elf}/Mips/got-page-64.test (82%) rename test/{elf => old-elf}/Mips/got16-2.test (96%) rename test/{elf => old-elf}/Mips/got16-micro.test (93%) rename test/{elf => old-elf}/Mips/got16.test (94%) rename test/{elf => old-elf}/Mips/gotsym.test (80%) rename test/{elf => old-elf}/Mips/gp-sym-1-micro.test (93%) rename test/{elf => old-elf}/Mips/gp-sym-1.test (93%) rename test/{elf => old-elf}/Mips/gp-sym-2.test (92%) create mode 100644 test/old-elf/Mips/hilo16-1.test create mode 100644 test/old-elf/Mips/hilo16-2.test create mode 100644 test/old-elf/Mips/hilo16-3-overflow.test create mode 100644 test/old-elf/Mips/hilo16-3.test rename test/{elf => old-elf}/Mips/hilo16-4.test (96%) rename test/{elf => old-elf}/Mips/hilo16-5.test (93%) create mode 100644 test/old-elf/Mips/hilo16-8-micro.test create mode 100644 test/old-elf/Mips/hilo16-9-micro.test rename test/{elf => old-elf}/Mips/initfini-micro.test (94%) rename test/{elf => old-elf}/Mips/interpreter-64.test (91%) create mode 100644 test/old-elf/Mips/interpreter-n32.test rename test/{elf => old-elf}/Mips/interpreter.test (91%) rename test/{elf => old-elf}/Mips/invalid-reginfo.test (89%) rename test/{elf => old-elf}/Mips/jalx-align-err.test (86%) create mode 100644 test/old-elf/Mips/jalx-jalr.test create mode 100644 test/old-elf/Mips/jalx.test rename test/{elf => old-elf}/Mips/jump-fix-err.test (91%) create mode 100644 test/old-elf/Mips/la25-stub-be.test create mode 100644 test/old-elf/Mips/la25-stub-micro-be.test rename test/{elf => old-elf}/Mips/la25-stub-micro.test (76%) create mode 100644 test/old-elf/Mips/la25-stub-npic-01.test create mode 100644 test/old-elf/Mips/la25-stub-npic-02.test create mode 100644 test/old-elf/Mips/la25-stub-npic-shared.test create mode 100644 test/old-elf/Mips/la25-stub-pic.test rename test/{elf => old-elf}/Mips/la25-stub.test (80%) create mode 100644 test/old-elf/Mips/mips-options-01.test create mode 100644 test/old-elf/Mips/mips-options-02.test create mode 100644 test/old-elf/Mips/mips-options-03.test create mode 100644 test/old-elf/Mips/mips-options-04.test create mode 100644 test/old-elf/Mips/mips-options-05.test rename test/{elf => old-elf}/Mips/mips-options-gp0.test (76%) create mode 100644 test/old-elf/Mips/n32-rela-chain.test rename test/{elf => old-elf}/Mips/n64-rel-chain.test (55%) create mode 100644 test/old-elf/Mips/n64-rel-shift.test rename test/{elf => old-elf}/Mips/opt-emulation.test (80%) rename test/{elf => old-elf}/Mips/pc23-range.test (75%) rename test/{elf => old-elf}/Mips/plt-entry-mixed-1.test (93%) rename test/{elf => old-elf}/Mips/plt-entry-mixed-2.test (81%) rename test/{elf => old-elf}/Mips/plt-entry-mixed-3.test (94%) rename test/{elf => old-elf}/Mips/plt-entry-mixed-4.test (82%) create mode 100644 test/old-elf/Mips/plt-entry-r6-be.test rename test/{elf => old-elf}/Mips/plt-entry-r6.test (92%) create mode 100644 test/old-elf/Mips/plt-header-be.test create mode 100644 test/old-elf/Mips/plt-header-micro-be.test rename test/{elf => old-elf}/Mips/plt-header-micro.test (95%) rename test/{elf => old-elf}/Mips/plt-header-mixed.test (94%) rename test/{elf => old-elf}/Mips/plt-header.test (93%) rename test/{elf => old-elf}/Mips/r26-1-micro.test (96%) rename test/{elf => old-elf}/Mips/r26-1.test (96%) create mode 100644 test/old-elf/Mips/r26-2-micro.test create mode 100644 test/old-elf/Mips/r26-2.test create mode 100644 test/old-elf/Mips/reginfo-01.test create mode 100644 test/old-elf/Mips/reginfo-02.test create mode 100644 test/old-elf/Mips/reginfo-03.test create mode 100644 test/old-elf/Mips/reginfo-04.test create mode 100644 test/old-elf/Mips/reginfo-05.test create mode 100644 test/old-elf/Mips/rel-16-overflow.test create mode 100644 test/old-elf/Mips/rel-16.test create mode 100644 test/old-elf/Mips/rel-32-be.test rename test/{elf => old-elf}/Mips/rel-32.test (95%) rename test/{elf => old-elf}/Mips/rel-64.test (96%) create mode 100644 test/old-elf/Mips/rel-call-hilo-01.test create mode 100644 test/old-elf/Mips/rel-call-hilo-micro.test rename test/{elf => old-elf}/Mips/rel-copy-micro.test (92%) rename test/{elf => old-elf}/Mips/rel-copy-pc.test (93%) rename test/{elf => old-elf}/Mips/rel-copy.test (91%) rename test/{elf => old-elf}/Mips/rel-dynamic-01-micro.test (94%) rename test/{elf => old-elf}/Mips/rel-dynamic-01.test (84%) create mode 100644 test/old-elf/Mips/rel-dynamic-02.test rename test/{elf => old-elf}/Mips/rel-dynamic-03-micro.test (96%) rename test/{elf => old-elf}/Mips/rel-dynamic-03.test (94%) rename test/{elf => old-elf}/Mips/rel-dynamic-04-micro.test (90%) rename test/{elf => old-elf}/Mips/rel-dynamic-04.test (90%) rename test/{elf => old-elf}/Mips/rel-dynamic-05-micro.test (97%) rename test/{elf => old-elf}/Mips/rel-dynamic-05.test (88%) create mode 100644 test/old-elf/Mips/rel-dynamic-06-64.test create mode 100644 test/old-elf/Mips/rel-dynamic-06.test rename test/{elf => old-elf}/Mips/rel-dynamic-07-64.test (72%) rename test/{elf => old-elf}/Mips/rel-dynamic-07.test (72%) rename test/{elf => old-elf}/Mips/rel-dynamic-08-64.test (80%) rename test/{elf => old-elf}/Mips/rel-dynamic-08-micro.test (80%) rename test/{elf => old-elf}/Mips/rel-dynamic-08.test (80%) rename test/{elf => old-elf}/Mips/rel-dynamic-09-micro.test (96%) rename test/{elf => old-elf}/Mips/rel-dynamic-09.test (96%) rename test/{elf => old-elf}/Mips/rel-dynamic-10-micro.test (97%) rename test/{elf => old-elf}/Mips/rel-dynamic-10.test (97%) rename test/{elf => old-elf}/Mips/rel-dynamic-11.test (94%) rename test/{elf => old-elf}/Mips/rel-dynamic-12.test (83%) create mode 100644 test/old-elf/Mips/rel-dynamic-13.test create mode 100644 test/old-elf/Mips/rel-dynamic-14.test create mode 100644 test/old-elf/Mips/rel-dynamic-15.test create mode 100644 test/old-elf/Mips/rel-eh-01.test create mode 100644 test/old-elf/Mips/rel-eh-02.test create mode 100644 test/old-elf/Mips/rel-eh-03.test create mode 100644 test/old-elf/Mips/rel-got-hilo-01.test create mode 100644 test/old-elf/Mips/rel-got-hilo-micro.test create mode 100644 test/old-elf/Mips/rel-gprel16-micro-overflow.test create mode 100644 test/old-elf/Mips/rel-gprel16-micro.test create mode 100644 test/old-elf/Mips/rel-gprel16-overflow.test rename test/{elf => old-elf}/Mips/rel-gprel16.test (80%) rename test/{elf => old-elf}/Mips/rel-gprel32-64.test (74%) rename test/{elf => old-elf}/Mips/rel-gprel32.test (86%) create mode 100644 test/old-elf/Mips/rel-gprel7-micro-overflow.test create mode 100644 test/old-elf/Mips/rel-gprel7-micro.test create mode 100644 test/old-elf/Mips/rel-hi0-lo16-micro.test create mode 100644 test/old-elf/Mips/rel-high-01.test create mode 100644 test/old-elf/Mips/rel-high-02.test create mode 100644 test/old-elf/Mips/rel-jalr-01.test create mode 100644 test/old-elf/Mips/rel-jalr-02.test create mode 100644 test/old-elf/Mips/rel-lit-micro.test create mode 100644 test/old-elf/Mips/rel-lit.test rename test/{elf => old-elf}/Mips/rel-pc-hilo.test (60%) create mode 100644 test/old-elf/Mips/rel-pc16-align.test create mode 100644 test/old-elf/Mips/rel-pc16-overflow.test create mode 100644 test/old-elf/Mips/rel-pc16.test create mode 100644 test/old-elf/Mips/rel-pc18-s3-align.test create mode 100644 test/old-elf/Mips/rel-pc18-s3-micro.test rename test/{elf => old-elf}/Mips/rel-pc18-s3.test (69%) create mode 100644 test/old-elf/Mips/rel-pc19-s2-align.test create mode 100644 test/old-elf/Mips/rel-pc19-s2-micro.test rename test/{elf => old-elf}/Mips/rel-pc19-s2.test (71%) create mode 100644 test/old-elf/Mips/rel-pc21-s2-align.test create mode 100644 test/old-elf/Mips/rel-pc21-s2-micro.test create mode 100644 test/old-elf/Mips/rel-pc21-s2-overflow.test rename test/{elf => old-elf}/Mips/rel-pc21-s2.test (71%) create mode 100644 test/old-elf/Mips/rel-pc26-s2-align.test create mode 100644 test/old-elf/Mips/rel-pc26-s2-micro.test rename test/{elf => old-elf}/Mips/rel-pc26-s2.test (71%) rename test/{elf => old-elf}/Mips/rel-pc32.test (74%) rename test/{elf => old-elf}/Mips/rel-pc7-10-16-23.test (56%) create mode 100644 test/old-elf/Mips/rel-sub-micro.test rename test/{elf => old-elf}/Mips/rel-sub.test (96%) create mode 100644 test/old-elf/Mips/rld_map.test create mode 100644 test/old-elf/Mips/sign-rela.test rename test/{elf => old-elf}/Mips/st-other.test (88%) create mode 100644 test/old-elf/Mips/static-01.test rename test/{elf => old-elf}/Mips/tls-1-micro.test (93%) rename test/{elf => old-elf}/Mips/tls-1.test (93%) create mode 100644 test/old-elf/Mips/tls-2-64-static.test rename test/{elf => old-elf}/Mips/tls-2-64.test (96%) rename test/{elf => old-elf}/Mips/tls-2-micro.test (97%) create mode 100644 test/old-elf/Mips/tls-2-static.test rename test/{elf => old-elf}/Mips/tls-2.test (96%) create mode 100644 test/old-elf/Mips/tls-3-64-static.test rename test/{elf => old-elf}/Mips/tls-3-micro.test (97%) create mode 100644 test/old-elf/Mips/tls-3-static.test rename test/{elf => old-elf}/Mips/tls-3.test (97%) create mode 100644 test/old-elf/Mips/tls-4-64-static.test rename test/{elf => old-elf}/Mips/tls-4-micro.test (97%) create mode 100644 test/old-elf/Mips/tls-4-static.test rename test/{elf => old-elf}/Mips/tls-4.test (97%) rename test/{elf => old-elf}/Mips/tls-5-64.test (96%) rename test/{elf => old-elf}/Mips/tls-5-micro.test (96%) rename test/{elf => old-elf}/Mips/tls-5.test (96%) create mode 100644 test/old-elf/Mips/validate-rel-01.test create mode 100644 test/old-elf/Mips/validate-rel-03.test rename test/{elf => old-elf}/X86_64/ExampleTarget/triple.test (92%) rename test/{elf => old-elf}/X86_64/Inputs/constint.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/constint.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/debug0.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/debug0.x86-64 (100%) rename test/{elf => old-elf}/X86_64/Inputs/debug1.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/debug1.x86-64 (100%) rename test/{elf => old-elf}/X86_64/Inputs/externtls.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/externtls.x86-64 (100%) rename test/{elf => old-elf}/X86_64/Inputs/fn.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/fn.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/generaltls-so.o.yaml (98%) rename test/{elf => old-elf}/X86_64/Inputs/group/1.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/1.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn1.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn1.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn2.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/fn2.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/group.sh (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/libfn.a (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/libfn.so (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/libfn1.a (100%) rename test/{elf => old-elf}/X86_64/Inputs/group/libfn2.so (100%) rename test/{elf => old-elf}/X86_64/Inputs/initfini-option.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/initfini-option.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/initfini.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/initfini.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/largebss.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/largebss.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/1.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/1.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/2.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/2.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/3.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/3.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/layoutpass/lib2.a (100%) rename test/{elf => old-elf}/X86_64/Inputs/libfn.a (100%) rename test/{elf => old-elf}/X86_64/Inputs/libfn.so (100%) rename test/{elf => old-elf}/X86_64/Inputs/main.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/main.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/multi-ovrd.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/multi-ovrd.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/multi-weak.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/multi-weak.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/multiweaksyms.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/nmagic.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/nmagic.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/no-interp-section.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/no-interp-section.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/note.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/note.s (100%) rename test/{elf => old-elf}/X86_64/Inputs/note_ro_rw.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/note_ro_rw.s (100%) rename test/{elf => old-elf}/X86_64/Inputs/ovrd.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/ovrd.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/rodata.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/rodata.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/rodata.s (100%) rename test/{elf => old-elf}/X86_64/Inputs/rwint.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/rwint.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/sectionmap.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/sectionmap.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/undefcpp.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/undefcpp.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/weak-zero-sized.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/weak.c (100%) rename test/{elf => old-elf}/X86_64/Inputs/weak.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/weak.s (100%) rename test/{elf => old-elf}/X86_64/Inputs/zerosizedsection.o (100%) rename test/{elf => old-elf}/X86_64/Inputs/zerosizedsection.s (100%) rename test/{elf => old-elf}/X86_64/alignoffset.test (97%) rename test/{elf => old-elf}/X86_64/debug.test (91%) rename test/{elf => old-elf}/X86_64/defsym.test (86%) create mode 100644 test/old-elf/X86_64/demangle.test rename test/{elf => old-elf}/X86_64/dontignorezerosize-sections.test (77%) rename test/{elf => old-elf}/X86_64/dynamicvars.test (97%) create mode 100644 test/old-elf/X86_64/dynlib-nointerp-section.test rename test/{elf => old-elf}/X86_64/dynlib-search.test (67%) rename test/{elf => old-elf}/X86_64/dynsym-weak.test (91%) create mode 100644 test/old-elf/X86_64/extern-tls.test rename test/{elf => old-elf}/X86_64/general-dynamic-tls.test (95%) rename test/{elf => old-elf}/X86_64/imagebase.test (97%) rename test/{elf => old-elf}/X86_64/initfini-order.test (84%) rename test/{elf => old-elf}/X86_64/initfini.test (92%) rename test/{elf => old-elf}/X86_64/largebss.test (85%) rename test/{elf => old-elf}/X86_64/layoutpass-order.test (86%) rename test/{elf => old-elf}/X86_64/maxpagesize.test (91%) rename test/{elf => old-elf}/X86_64/mergesimilarstrings.test (89%) rename test/{elf => old-elf}/X86_64/multi-weak-layout.test (88%) rename test/{elf => old-elf}/X86_64/multi-weak-override.test (80%) rename test/{elf => old-elf}/X86_64/multi-weak-syms-order.test (64%) rename test/{elf => old-elf}/X86_64/nmagic.test (97%) rename test/{elf => old-elf}/X86_64/noalignsegments.test (97%) rename test/{elf => old-elf}/X86_64/note-sections-ro_plus_rw.test (94%) rename test/{elf => old-elf}/X86_64/note-sections.test (91%) rename test/{elf => old-elf}/X86_64/omagic.test (98%) rename test/{elf => old-elf}/X86_64/outputsegments.test (97%) rename test/{elf => old-elf}/X86_64/reloc_r_x86_64_16.test (94%) rename test/{elf => old-elf}/X86_64/reloc_r_x86_64_pc16.test (94%) rename test/{elf => old-elf}/X86_64/reloc_r_x86_64_pc64.test (94%) rename test/{elf => old-elf}/X86_64/rodata.test (77%) rename test/{elf => old-elf}/X86_64/sectionchoice.test (72%) rename test/{elf => old-elf}/X86_64/sectionmap.test (91%) rename test/{elf => old-elf}/X86_64/startGroupEndGroup.test (74%) rename test/{elf => old-elf}/X86_64/startGroupEndGroupWithDynlib.test (81%) rename test/{elf => old-elf}/X86_64/staticlib-search.test (68%) rename test/{elf => old-elf}/X86_64/undef.test (77%) rename test/{elf => old-elf}/X86_64/underscore-end.test (95%) rename test/{elf => old-elf}/X86_64/weak-override.test (93%) rename test/{elf => old-elf}/X86_64/weak-zero-sized.test (77%) rename test/{elf => old-elf}/X86_64/weaksym.test (96%) rename test/{elf => old-elf}/X86_64/yamlinput.test (97%) rename test/{elf => old-elf}/abs-dup.objtxt (91%) rename test/{elf => old-elf}/abs.test (79%) rename test/{elf => old-elf}/allowduplicates.objtxt (58%) rename test/{elf => old-elf}/archive-elf-forceload.test (93%) rename test/{elf => old-elf}/archive-elf.test (92%) rename test/{elf => old-elf}/as-needed.test (80%) rename test/{elf => old-elf}/branch.test (91%) rename test/{elf => old-elf}/check.test (89%) rename test/{elf => old-elf}/checkrodata.test (58%) rename test/{elf => old-elf}/common.test (72%) rename test/{elf => old-elf}/consecutive-weak-sym-defs.test (96%) rename test/{elf => old-elf}/defsym.objtxt (73%) create mode 100644 test/old-elf/discard-all.test create mode 100644 test/old-elf/discard-locals.test rename test/{elf => old-elf}/dynamic-segorder.test (82%) rename test/{elf => old-elf}/dynamic-undef.test (71%) rename test/{elf => old-elf}/dynamic.test (93%) rename test/{elf => old-elf}/eh_frame_hdr.test (89%) rename test/{elf => old-elf}/entry.objtxt (88%) rename test/{elf => old-elf}/export-dynamic.test (97%) rename test/{elf => old-elf}/filenotfound.test (60%) rename test/{elf => old-elf}/gnulinkonce/gnulinkonce-report-discarded-reference.test (96%) rename test/{elf => old-elf}/gnulinkonce/gnulinkonce-report-undef.test (95%) rename test/{elf => old-elf}/gnulinkonce/gnulinkonce.test (96%) rename test/{elf => old-elf}/gotpcrel.test (86%) rename test/{elf => old-elf}/gottpoff.test (95%) rename test/{elf => old-elf}/group-cmd-search.test (87%) rename test/{elf => old-elf}/hexagon-quickdata-sort.test (73%) rename test/{elf => old-elf}/hexagon-quickdata-sortcommon.test (89%) rename test/{elf => old-elf}/ifunc.test (85%) rename test/{elf => old-elf}/ignore-unknownoption.test (72%) rename test/{elf => old-elf}/init_array-order.test (95%) create mode 100644 test/old-elf/init_array.test rename test/{elf => old-elf}/initfini-options.test-1.test (90%) rename test/{elf => old-elf}/initfini-options.test-2.test (94%) rename test/{elf => old-elf}/initfini-options.test-3.test (95%) rename test/{elf => old-elf}/librarynotfound.test (72%) rename test/{elf => old-elf}/linker-as-ld.test (84%) rename test/{elf => old-elf}/linkerscript/Inputs/externs.ls (100%) rename test/{elf => old-elf}/linkerscript/Inputs/invalid.ls (100%) rename test/{elf => old-elf}/linkerscript/Inputs/prog1.o.yaml (95%) rename test/{elf => old-elf}/linkerscript/Inputs/prog2.o.yaml (95%) rename test/{elf => old-elf}/linkerscript/Inputs/prog3.o.yaml (91%) create mode 100644 test/old-elf/linkerscript/Inputs/simple-pic.o.yaml rename test/{elf => old-elf}/linkerscript/Inputs/simple.o.yaml (91%) rename test/{elf => old-elf}/linkerscript/Inputs/valid.ls (100%) rename test/{elf => old-elf}/linkerscript/externs.objtxt (86%) create mode 100644 test/old-elf/linkerscript/filename-with-wildcards.test rename test/{elf => old-elf}/linkerscript/invalid-script-cli-1.test (59%) rename test/{elf => old-elf}/linkerscript/invalid-script-cli-2.test (64%) rename test/{elf => old-elf}/linkerscript/invalid.test (63%) create mode 100644 test/old-elf/linkerscript/phdrs-all-none.test create mode 100644 test/old-elf/linkerscript/phdrs-custom-none.test create mode 100644 test/old-elf/linkerscript/phdrs-default.test create mode 100644 test/old-elf/linkerscript/phdrs-different.test create mode 100644 test/old-elf/linkerscript/phdrs-extra-program.test create mode 100644 test/old-elf/linkerscript/phdrs-flags.test create mode 100644 test/old-elf/linkerscript/phdrs-has-program.test create mode 100644 test/old-elf/linkerscript/phdrs-invalid.test create mode 100644 test/old-elf/linkerscript/phdrs-misplaced-program.test create mode 100644 test/old-elf/linkerscript/phdrs-no-program.test create mode 100644 test/old-elf/linkerscript/phdrs-one-none.test create mode 100644 test/old-elf/linkerscript/phdrs-program-flags.test create mode 100644 test/old-elf/linkerscript/phdrs-program-good-phdrs.test create mode 100644 test/old-elf/linkerscript/phdrs-program-no-phdrs.test create mode 100644 test/old-elf/linkerscript/phdrs-program-wrong-phdrs.test create mode 100644 test/old-elf/linkerscript/phdrs-same-flags.test create mode 100644 test/old-elf/linkerscript/phdrs-same.test create mode 100644 test/old-elf/linkerscript/phdrs/sections-empty-phdrs.script create mode 100644 test/old-elf/linkerscript/phdrs/sections-no-phdrs.script create mode 100644 test/old-elf/linkerscript/phdrs/sections-none-phdrs.script create mode 100644 test/old-elf/linkerscript/phdrs/undef-empty-phdrs.script create mode 100644 test/old-elf/linkerscript/phdrs/undef-id-phdrs.script create mode 100644 test/old-elf/linkerscript/phdrs/undef-no-phdrs.script rename test/{elf => old-elf}/linkerscript/sections-order.test (75%) rename test/{elf => old-elf}/linkerscript/sections-with-wildcards.test (96%) create mode 100644 test/old-elf/linkerscript/symbol-definition-so.test rename test/{elf => old-elf}/linkerscript/symbol-definition.test (92%) rename test/{elf => old-elf}/linkerscript/valid-script-cli.objtxt (61%) rename test/{elf => old-elf}/loginputfiles.test (90%) rename test/{elf => old-elf}/mergeatoms.test (77%) rename test/{elf => old-elf}/mergeconstants.test (87%) rename test/{elf => old-elf}/mergeglobalatoms.test (84%) create mode 100644 test/old-elf/no-unique-section-names.test rename test/{elf => old-elf}/note.test (87%) rename test/{elf => old-elf}/options/dynamic-linker.test (76%) create mode 100644 test/old-elf/options/target-specific-args.test rename test/{elf => old-elf}/phdr.test (94%) rename test/{elf => old-elf}/quickdata.test (82%) rename test/{elf => old-elf}/reloc.test (91%) rename test/{elf => old-elf}/responsefile.test (70%) rename test/{elf => old-elf}/rodata.test (51%) rename test/{elf => old-elf}/rosegment.test (84%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-new-members.test (96%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-simple.test (96%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-undef-member-other.test (97%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-undef-member.test (97%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-with-globalsymbols.test (96%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-with-undef-external-reference.test (97%) rename test/{elf => old-elf}/sectionGroups/sectiongroup-with-undef-signature.test (97%) rename test/{elf => old-elf}/sections.test (97%) rename test/{elf => old-elf}/sh_addralign.test (90%) create mode 100644 test/old-elf/shndx.test rename test/{elf => old-elf}/soname.test (67%) create mode 100644 test/old-elf/start-stop-sym.test rename test/{elf => old-elf}/strip-all.test (88%) rename test/{elf => old-elf}/stripped-empty.test (69%) rename test/{elf => old-elf}/symbols.test (84%) create mode 100644 test/old-elf/tls-tbss-size.test rename test/{elf => old-elf}/tls.test (82%) rename test/{elf => old-elf}/tlsAddr.test (77%) rename test/{elf => old-elf}/undef-from-dso-to-main.test (89%) rename test/{elf => old-elf}/undef-from-main-dso.test (87%) rename test/{elf => old-elf}/weaksym.test (66%) rename test/{elf => old-elf}/wrap.test (97%) rename test/{elf => old-elf}/x86-64-dynamic-relocs.test (83%) rename test/{elf => old-elf}/x86-64-dynamic.test (92%) rename test/{elf => old-elf}/x86.test (85%) rename test/{elf => old-elf}/x86_64-kinds.test (69%) create mode 100644 test/old-elf/zoption_dtflags.test delete mode 100644 test/pecoff/Inputs/abs.obj.yaml delete mode 100644 test/pecoff/Inputs/alignment.obj.yaml delete mode 100644 test/pecoff/Inputs/alternatename1.obj.yaml delete mode 100644 test/pecoff/Inputs/armnt-ImageBase.obj.yaml delete mode 100644 test/pecoff/Inputs/armnt-ImageBase.s delete mode 100644 test/pecoff/Inputs/armnt-addr32-exec.s delete mode 100644 test/pecoff/Inputs/armnt-addr32.obj.yaml delete mode 100644 test/pecoff/Inputs/armnt-addr32.s delete mode 100644 test/pecoff/Inputs/armnt-blx23t.s delete mode 100644 test/pecoff/Inputs/armnt-branch24t.s delete mode 100644 test/pecoff/Inputs/armnt-exports.def delete mode 100644 test/pecoff/Inputs/armnt-import.s delete mode 100644 test/pecoff/Inputs/armnt-mov32t-exec.s delete mode 100644 test/pecoff/Inputs/armnt-mov32t.s delete mode 100644 test/pecoff/Inputs/armnt-obj.s delete mode 100644 test/pecoff/Inputs/basereloc.obj.yaml delete mode 100644 test/pecoff/Inputs/bss.asm delete mode 100644 test/pecoff/Inputs/bss.obj delete mode 100644 test/pecoff/Inputs/drectve.obj.yaml delete mode 100644 test/pecoff/Inputs/drectve3.lib delete mode 100644 test/pecoff/Inputs/entry.obj.yaml delete mode 100644 test/pecoff/Inputs/exports.def delete mode 100644 test/pecoff/Inputs/exports2.def delete mode 100644 test/pecoff/Inputs/grouped-sections.asm delete mode 100644 test/pecoff/Inputs/grouped-sections.obj.yaml delete mode 100644 test/pecoff/Inputs/hello.asm delete mode 100644 test/pecoff/Inputs/hello.obj.yaml delete mode 100644 test/pecoff/Inputs/hello64.asm delete mode 100644 test/pecoff/Inputs/hello64.obj.yaml delete mode 100644 test/pecoff/Inputs/hello64lib.asm delete mode 100644 test/pecoff/Inputs/hello64lib.lib delete mode 100644 test/pecoff/Inputs/machine-type-unknown.obj.yaml delete mode 100644 test/pecoff/Inputs/merge-largest1.obj.yaml delete mode 100644 test/pecoff/Inputs/merge-largest2.obj.yaml delete mode 100644 test/pecoff/Inputs/merge-same-size1.obj.yaml delete mode 100644 test/pecoff/Inputs/merge-same-size2.obj.yaml delete mode 100644 test/pecoff/Inputs/merge-same-size3.obj.yaml delete mode 100644 test/pecoff/Inputs/nonstandard-sections.obj.yaml delete mode 100644 test/pecoff/Inputs/nop.asm delete mode 100644 test/pecoff/Inputs/reloc64.obj.yaml delete mode 100644 test/pecoff/Inputs/resource.rc delete mode 100644 test/pecoff/Inputs/responsefile.txt delete mode 100644 test/pecoff/Inputs/secrel2.obj.yaml delete mode 100644 test/pecoff/Inputs/seh.c delete mode 100644 test/pecoff/Inputs/seh.obj.yaml delete mode 100644 test/pecoff/Inputs/static-data1.obj.yaml delete mode 100644 test/pecoff/Inputs/static-data2.obj.yaml delete mode 100644 test/pecoff/Inputs/static.lib delete mode 100644 test/pecoff/Inputs/vars-main-x86.obj.yaml delete mode 100644 test/pecoff/Inputs/vars-main.c delete mode 100644 test/pecoff/Inputs/vars.c delete mode 100644 test/pecoff/Inputs/vars.dll.yaml delete mode 100644 test/pecoff/Inputs/vars.lib delete mode 100644 test/pecoff/Inputs/vars64.lib delete mode 100644 test/pecoff/Inputs/weak-externals.asm delete mode 100644 test/pecoff/Inputs/weak-externals.obj.yaml delete mode 100644 test/pecoff/alignment.test delete mode 100644 test/pecoff/alternatename.test delete mode 100644 test/pecoff/armnt-ImageBase.test delete mode 100644 test/pecoff/armnt-addr32-exec.test delete mode 100644 test/pecoff/armnt-addr32.test delete mode 100644 test/pecoff/armnt-address-of-entry-point.test delete mode 100644 test/pecoff/armnt-blx23t.test delete mode 100644 test/pecoff/armnt-branch24t.test delete mode 100644 test/pecoff/armnt-exports.s delete mode 100644 test/pecoff/armnt-exports.test delete mode 100644 test/pecoff/armnt-imports.test delete mode 100644 test/pecoff/armnt-mov32t-exec.test delete mode 100644 test/pecoff/armnt-movt32t.test delete mode 100644 test/pecoff/armnt.test delete mode 100644 test/pecoff/associative.test delete mode 100644 test/pecoff/base-reloc.test delete mode 100644 test/pecoff/baseaddr.test delete mode 100644 test/pecoff/bss-section.test delete mode 100644 test/pecoff/comdat.test delete mode 100644 test/pecoff/common-symbol.test delete mode 100644 test/pecoff/conflicting-machine.test delete mode 100644 test/pecoff/delayimport.test delete mode 100644 test/pecoff/dll.test delete mode 100644 test/pecoff/dosstub.test delete mode 100644 test/pecoff/drectve.test delete mode 100644 test/pecoff/dynamic.test delete mode 100644 test/pecoff/dynamicbase.test delete mode 100644 test/pecoff/entry.test delete mode 100644 test/pecoff/export-warning.test delete mode 100644 test/pecoff/export.test delete mode 100644 test/pecoff/exportlib.test delete mode 100644 test/pecoff/exportlib2.test delete mode 100644 test/pecoff/grouped-sections.test delete mode 100644 test/pecoff/hello.test delete mode 100644 test/pecoff/hello64.test delete mode 100644 test/pecoff/help.test delete mode 100644 test/pecoff/imagebase.test delete mode 100644 test/pecoff/importlib.test delete mode 100644 test/pecoff/include.test delete mode 100644 test/pecoff/lib.test delete mode 100644 test/pecoff/libarg.test delete mode 100644 test/pecoff/localyimported.test delete mode 100644 test/pecoff/long-section-name.test delete mode 100644 test/pecoff/machinetype.test delete mode 100644 test/pecoff/merge-largest.test delete mode 100644 test/pecoff/merge-same-size.test delete mode 100644 test/pecoff/multi.test delete mode 100644 test/pecoff/noentry.test delete mode 100644 test/pecoff/nonstandard-sections.test delete mode 100644 test/pecoff/options.test delete mode 100644 test/pecoff/pe32plus.test delete mode 100644 test/pecoff/reloc.test delete mode 100644 test/pecoff/reloc64.test delete mode 100644 test/pecoff/resource.test delete mode 100644 test/pecoff/responsefile.test delete mode 100644 test/pecoff/safeseh.test delete mode 100644 test/pecoff/secrel.test delete mode 100644 test/pecoff/section-attribute.test delete mode 100644 test/pecoff/section-renaming.test delete mode 100644 test/pecoff/seh.test delete mode 100644 test/pecoff/seh64.test delete mode 100644 test/pecoff/subsystem.test delete mode 100644 test/pecoff/tls.test delete mode 100644 test/pecoff/trivial.test delete mode 100644 test/pecoff/unknown-drectve.test delete mode 100644 test/pecoff/weak-external.test delete mode 100644 tools/Makefile delete mode 100644 tools/linker-script-test/Makefile delete mode 100644 tools/lld/Makefile delete mode 100644 unittests/CoreTests/Makefile delete mode 100644 unittests/DriverTests/Makefile delete mode 100644 unittests/DriverTests/WinLinkDriverTest.cpp delete mode 100644 unittests/DriverTests/WinLinkModuleDefTest.cpp delete mode 100644 unittests/Makefile delete mode 100644 utils/astyle-options diff --git a/CMakeLists.txt b/CMakeLists.txt index 30ef47a692d..6b64301d1ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,10 +89,11 @@ endif() add_subdirectory(lib) add_subdirectory(tools) -add_subdirectory(test) - if (LLVM_INCLUDE_TESTS) + add_subdirectory(test) add_subdirectory(unittests) endif() add_subdirectory(docs) +add_subdirectory(COFF) +add_subdirectory(ELF) diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT new file mode 100644 index 00000000000..292967e588f --- /dev/null +++ b/CODE_OWNERS.TXT @@ -0,0 +1,19 @@ +This file is a list of the people responsible for ensuring that patches for a +particular part of LLD are reviewed, either by themself or by someone else. +They are also the gatekeepers for their part of LLD, with the final word on +what goes in or not. + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). Each entry should contain at least the (N), (E) and (D) fields. + + +N: Rui Ueyama +E: ruiu@google.com +D: COFF, ELF backends (COFF/* ELF/*) + +N: Lang Hames, Nick Kledzik +E: lhames@gmail.com, kledzik@apple.com +D: Mach-O backend + diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt new file mode 100644 index 00000000000..78dc34eff96 --- /dev/null +++ b/COFF/CMakeLists.txt @@ -0,0 +1,33 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(COFFOptionsTableGen) + +add_llvm_library(lldCOFF + Chunks.cpp + DLL.cpp + Driver.cpp + DriverUtils.cpp + Error.cpp + ICF.cpp + InputFiles.cpp + MarkLive.cpp + ModuleDef.cpp + PDB.cpp + SymbolTable.cpp + Symbols.cpp + Writer.cpp + + LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Core + LTO + LibDriver + Object + MC + MCDisassembler + Target + Option + Support + ) + +add_dependencies(lldCOFF COFFOptionsTableGen) diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp new file mode 100644 index 00000000000..50bf55be269 --- /dev/null +++ b/COFF/Chunks.cpp @@ -0,0 +1,340 @@ +//===- Chunks.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::COFF; +using llvm::support::ulittle32_t; + +namespace lld { +namespace coff { + +SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H) + : Chunk(SectionKind), Repl(this), File(F), Header(H), + Relocs(File->getCOFFObj()->getRelocations(Header)), + NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { + // Initialize SectionName. + File->getCOFFObj()->getSectionName(Header, SectionName); + + // Bit [20:24] contains section alignment. Both 0 and 1 mean alignment 1. + unsigned Shift = (Header->Characteristics >> 20) & 0xF; + if (Shift > 0) + Align = uint32_t(1) << (Shift - 1); + + // Only COMDAT sections are subject of dead-stripping. + Live = !isCOMDAT(); +} + +static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } +static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } +static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } +static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } + +void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, + uint64_t P) const { + uint64_t S = Sym->getRVA(); + switch (Type) { + case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; + case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; + case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; + case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; + case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; + case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; + case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; + case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; + default: + error("Unsupported relocation type"); + } +} + +void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, + uint64_t P) const { + uint64_t S = Sym->getRVA(); + switch (Type) { + case IMAGE_REL_I386_ABSOLUTE: break; + case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; + case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; + case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; + default: + error("Unsupported relocation type"); + } +} + +static void applyMOV(uint8_t *Off, uint16_t V) { + or16(Off, ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); + or16(Off + 2, ((V & 0x700) << 4) | (V & 0xff)); +} + +static void applyMOV32T(uint8_t *Off, uint32_t V) { + applyMOV(Off, V); // set MOVW operand + applyMOV(Off + 4, V >> 16); // set MOVT operand +} + +static void applyBranch20T(uint8_t *Off, int32_t V) { + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = (V >> 19) & 1; + uint32_t J2 = (V >> 18) & 1; + or16(Off, (S << 10) | ((V >> 12) & 0x3f)); + or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); +} + +static void applyBranch24T(uint8_t *Off, int32_t V) { + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = ((~V >> 23) & 1) ^ S; + uint32_t J2 = ((~V >> 22) & 1) ^ S; + or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); + or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); +} + +void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, + uint64_t P) const { + uint64_t S = Sym->getRVA(); + // Pointer to thumb code must have the LSB set. + if (Sym->isExecutable()) + S |= 1; + switch (Type) { + case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; + case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; + case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; + case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; + default: + error("Unsupported relocation type"); + } +} + +void SectionChunk::writeTo(uint8_t *Buf) const { + if (!hasData()) + return; + // Copy section contents from source object file to output file. + ArrayRef A = getContents(); + memcpy(Buf + OutputSectionOff, A.data(), A.size()); + + // Apply relocations. + for (const coff_relocation &Rel : Relocs) { + uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); + Defined *Sym = cast(Body); + uint64_t P = RVA + Rel.VirtualAddress; + switch (Config->Machine) { + case AMD64: + applyRelX64(Off, Rel.Type, Sym, P); + break; + case I386: + applyRelX86(Off, Rel.Type, Sym, P); + break; + case ARMNT: + applyRelARM(Off, Rel.Type, Sym, P); + break; + default: + llvm_unreachable("unknown machine type"); + } + } +} + +void SectionChunk::addAssociative(SectionChunk *Child) { + AssocChildren.push_back(Child); +} + +static uint8_t getBaserelType(const coff_relocation &Rel) { + switch (Config->Machine) { + case AMD64: + if (Rel.Type == IMAGE_REL_AMD64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; + case I386: + if (Rel.Type == IMAGE_REL_I386_DIR32) + return IMAGE_REL_BASED_HIGHLOW; + return IMAGE_REL_BASED_ABSOLUTE; + case ARMNT: + if (Rel.Type == IMAGE_REL_ARM_ADDR32) + return IMAGE_REL_BASED_HIGHLOW; + if (Rel.Type == IMAGE_REL_ARM_MOV32T) + return IMAGE_REL_BASED_ARM_MOV32T; + return IMAGE_REL_BASED_ABSOLUTE; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Windows-specific. +// Collect all locations that contain absolute addresses, which need to be +// fixed by the loader if load-time relocation is needed. +// Only called when base relocation is enabled. +void SectionChunk::getBaserels(std::vector *Res) { + for (const coff_relocation &Rel : Relocs) { + uint8_t Ty = getBaserelType(Rel); + if (Ty == IMAGE_REL_BASED_ABSOLUTE) + continue; + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); + if (isa(Body)) + continue; + Res->emplace_back(RVA + Rel.VirtualAddress, Ty); + } +} + +bool SectionChunk::hasData() const { + return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); +} + +uint32_t SectionChunk::getPermissions() const { + return Header->Characteristics & PermMask; +} + +bool SectionChunk::isCOMDAT() const { + return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; +} + +void SectionChunk::printDiscardedMessage() const { + // Removed by dead-stripping. If it's removed by ICF, ICF already + // printed out the name, so don't repeat that here. + if (Sym && this == Repl) + llvm::outs() << "Discarded " << Sym->getName() << "\n"; +} + +StringRef SectionChunk::getDebugName() { + if (Sym) + return Sym->getName(); + return ""; +} + +ArrayRef SectionChunk::getContents() const { + ArrayRef A; + File->getCOFFObj()->getSectionContents(Header, A); + return A; +} + +void SectionChunk::replace(SectionChunk *Other) { + Other->Repl = Repl; + Other->Live = false; +} + +CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { + // Common symbols are aligned on natural boundaries up to 32 bytes. + // This is what MSVC link.exe does. + Align = std::min(uint64_t(32), NextPowerOf2(Sym.getValue())); +} + +uint32_t CommonChunk::getPermissions() const { + return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | + IMAGE_SCN_MEM_WRITE; +} + +void StringChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); +} + +ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { + // Intel Optimization Manual says that all branch targets + // should be 16-byte aligned. MSVC linker does this too. + Align = 16; +} + +void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); + // The first two bytes is a JMP instruction. Fill its operand. + write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); +} + +void ImportThunkChunkX86::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA() + 2); +} + +void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); + // The first two bytes is a JMP instruction. Fill its operand. + write32le(Buf + OutputSectionOff + 2, + ImpSymbol->getRVA() + Config->ImageBase); +} + +void ImportThunkChunkARM::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); +} + +void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); + // Fix mov.w and mov.t operands. + applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); +} + +void LocalImportChunk::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA()); +} + +size_t LocalImportChunk::getSize() const { + return Config->is64() ? 8 : 4; +} + +void LocalImportChunk::writeTo(uint8_t *Buf) const { + if (Config->is64()) { + write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + } else { + write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + } +} + +void SEHTableChunk::writeTo(uint8_t *Buf) const { + ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); + size_t Cnt = 0; + for (Defined *D : Syms) + Begin[Cnt++] = D->getRVA(); + std::sort(Begin, Begin + Cnt); +} + +// Windows-specific. +// This class represents a block in .reloc section. +BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { + // Block header consists of 4 byte page RVA and 4 byte block size. + // Each entry is 2 byte. Last entry may be padding. + Data.resize(RoundUpToAlignment((End - Begin) * 2 + 8, 4)); + uint8_t *P = Data.data(); + write32le(P, Page); + write32le(P + 4, Data.size()); + P += 8; + for (Baserel *I = Begin; I != End; ++I) { + write16le(P, (I->Type << 12) | (I->RVA - Page)); + P += 2; + } +} + +void BaserelChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); +} + +uint8_t Baserel::getDefaultType() { + switch (Config->Machine) { + case AMD64: + return IMAGE_REL_BASED_DIR64; + case I386: + return IMAGE_REL_BASED_HIGHLOW; + default: + llvm_unreachable("unknown machine type"); + } +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Chunks.h b/COFF/Chunks.h new file mode 100644 index 00000000000..60b8e76f823 --- /dev/null +++ b/COFF/Chunks.h @@ -0,0 +1,332 @@ +//===- Chunks.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_CHUNKS_H +#define LLD_COFF_CHUNKS_H + +#include "Config.h" +#include "InputFiles.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/COFF.h" +#include +#include + +namespace lld { +namespace coff { + +using llvm::COFF::ImportDirectoryTableEntry; +using llvm::object::COFFSymbolRef; +using llvm::object::SectionRef; +using llvm::object::coff_relocation; +using llvm::object::coff_section; +using llvm::sys::fs::file_magic; + +class Baserel; +class Defined; +class DefinedImportData; +class DefinedRegular; +class ObjectFile; +class OutputSection; +class SymbolBody; + +// Mask for section types (code, data, bss, disacardable, etc.) +// and permissions (writable, readable or executable). +const uint32_t PermMask = 0xFF0000F0; + +// A Chunk represents a chunk of data that will occupy space in the +// output (if the resolver chose that). It may or may not be backed by +// a section of an input file. It could be linker-created data, or +// doesn't even have actual data (if common or bss). +class Chunk { +public: + enum Kind { SectionKind, OtherKind }; + Kind kind() const { return ChunkKind; } + virtual ~Chunk() = default; + + // Returns the size of this chunk (even if this is a common or BSS.) + virtual size_t getSize() const = 0; + + // Write this chunk to a mmap'ed file, assuming Buf is pointing to + // beginning of the file. Because this function may use RVA values + // of other chunks for relocations, you need to set them properly + // before calling this function. + virtual void writeTo(uint8_t *Buf) const {} + + // The writer sets and uses the addresses. + uint64_t getRVA() const { return RVA; } + uint32_t getAlign() const { return Align; } + void setRVA(uint64_t V) { RVA = V; } + void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; } + + // Returns true if this has non-zero data. BSS chunks return + // false. If false is returned, the space occupied by this chunk + // will be filled with zeros. + virtual bool hasData() const { return true; } + + // Returns readable/writable/executable bits. + virtual uint32_t getPermissions() const { return 0; } + + // Returns the section name if this is a section chunk. + // It is illegal to call this function on non-section chunks. + virtual StringRef getSectionName() const { + llvm_unreachable("unimplemented getSectionName"); + } + + // An output section has pointers to chunks in the section, and each + // chunk has a back pointer to an output section. + void setOutputSection(OutputSection *O) { Out = O; } + OutputSection *getOutputSection() { return Out; } + + // Windows-specific. + // Collect all locations that contain absolute addresses for base relocations. + virtual void getBaserels(std::vector *Res) {} + + // Returns a human-readable name of this chunk. Chunks are unnamed chunks of + // bytes, so this is used only for logging or debugging. + virtual StringRef getDebugName() { return ""; } + +protected: + Chunk(Kind K = OtherKind) : ChunkKind(K) {} + const Kind ChunkKind; + + // The RVA of this chunk in the output. The writer sets a value. + uint64_t RVA = 0; + + // The offset from beginning of the output section. The writer sets a value. + uint64_t OutputSectionOff = 0; + + // The output section for this chunk. + OutputSection *Out = nullptr; + + // The alignment of this chunk. The writer uses the value. + uint32_t Align = 1; +}; + +// A chunk corresponding a section of an input file. +class SectionChunk : public Chunk { + // Identical COMDAT Folding feature accesses section internal data. + friend class ICF; + +public: + class symbol_iterator : public llvm::iterator_adaptor_base< + symbol_iterator, const coff_relocation *, + std::random_access_iterator_tag, SymbolBody *> { + friend SectionChunk; + + ObjectFile *File; + + symbol_iterator(ObjectFile *File, const coff_relocation *I) + : symbol_iterator::iterator_adaptor_base(I), File(File) {} + + public: + symbol_iterator() = default; + + SymbolBody *operator*() const { + return File->getSymbolBody(I->SymbolTableIndex); + } + }; + + SectionChunk(ObjectFile *File, const coff_section *Header); + static bool classof(const Chunk *C) { return C->kind() == SectionKind; } + size_t getSize() const override { return Header->SizeOfRawData; } + void writeTo(uint8_t *Buf) const override; + bool hasData() const override; + uint32_t getPermissions() const override; + StringRef getSectionName() const override { return SectionName; } + void getBaserels(std::vector *Res) override; + bool isCOMDAT() const; + void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; + void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; + void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; + + // Called if the garbage collector decides to not include this chunk + // in a final output. It's supposed to print out a log message to stdout. + void printDiscardedMessage() const; + + // Adds COMDAT associative sections to this COMDAT section. A chunk + // and its children are treated as a group by the garbage collector. + void addAssociative(SectionChunk *Child); + + StringRef getDebugName() override; + void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; } + + // Used by the garbage collector. + bool isLive() { return !Config->DoGC || Live; } + void markLive() { + assert(!isLive() && "Cannot mark an already live section!"); + Live = true; + } + + // Allow iteration over the bodies of this chunk's relocated symbols. + llvm::iterator_range symbols() const { + return llvm::make_range(symbol_iterator(File, Relocs.begin()), + symbol_iterator(File, Relocs.end())); + } + + // Allow iteration over the associated child chunks for this section. + ArrayRef children() const { return AssocChildren; } + + // A pointer pointing to a replacement for this chunk. + // Initially it points to "this" object. If this chunk is merged + // with other chunk by ICF, it points to another chunk, + // and this chunk is considrered as dead. + SectionChunk *Repl; + + // The CRC of the contents as described in the COFF spec 4.5.5. + // Auxiliary Format 5: Section Definitions. Used for ICF. + uint32_t Checksum = 0; + +private: + ArrayRef getContents() const; + + // A file this chunk was created from. + ObjectFile *File; + + const coff_section *Header; + StringRef SectionName; + std::vector AssocChildren; + llvm::iterator_range Relocs; + size_t NumRelocs; + + // Used by the garbage collector. + bool Live; + + // Used for ICF (Identical COMDAT Folding) + void replace(SectionChunk *Other); + std::atomic GroupID = { 0 }; + + // Sym points to a section symbol if this is a COMDAT chunk. + DefinedRegular *Sym = nullptr; +}; + +// A chunk for common symbols. Common chunks don't have actual data. +class CommonChunk : public Chunk { +public: + CommonChunk(const COFFSymbolRef Sym); + size_t getSize() const override { return Sym.getValue(); } + bool hasData() const override { return false; } + uint32_t getPermissions() const override; + StringRef getSectionName() const override { return ".bss"; } + +private: + const COFFSymbolRef Sym; +}; + +// A chunk for linker-created strings. +class StringChunk : public Chunk { +public: + explicit StringChunk(StringRef S) : Str(S) {} + size_t getSize() const override { return Str.size() + 1; } + void writeTo(uint8_t *Buf) const override; + +private: + StringRef Str; +}; + +static const uint8_t ImportThunkX86[] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 +}; + +static const uint8_t ImportThunkARM[] = { + 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 + 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 + 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] +}; + +// Windows-specific. +// A chunk for DLL import jump table entry. In a final output, it's +// contents will be a JMP instruction to some __imp_ symbol. +class ImportThunkChunkX64 : public Chunk { +public: + explicit ImportThunkChunkX64(Defined *S); + size_t getSize() const override { return sizeof(ImportThunkX86); } + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +class ImportThunkChunkX86 : public Chunk { +public: + explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkX86); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +class ImportThunkChunkARM : public Chunk { +public: + explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +// Windows-specific. +// See comments for DefinedLocalImport class. +class LocalImportChunk : public Chunk { +public: + explicit LocalImportChunk(Defined *S) : Sym(S) {} + size_t getSize() const override; + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *Sym; +}; + +// Windows-specific. +// A chunk for SEH table which contains RVAs of safe exception handler +// functions. x86-only. +class SEHTableChunk : public Chunk { +public: + explicit SEHTableChunk(std::set S) : Syms(S) {} + size_t getSize() const override { return Syms.size() * 4; } + void writeTo(uint8_t *Buf) const override; + +private: + std::set Syms; +}; + +// Windows-specific. +// This class represents a block in .reloc section. +// See the PE/COFF spec 5.6 for details. +class BaserelChunk : public Chunk { +public: + BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); + size_t getSize() const override { return Data.size(); } + void writeTo(uint8_t *Buf) const override; + +private: + std::vector Data; +}; + +class Baserel { +public: + Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} + explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} + uint8_t getDefaultType(); + + uint32_t RVA; + uint8_t Type; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Config.h b/COFF/Config.h new file mode 100644 index 00000000000..409ede64863 --- /dev/null +++ b/COFF/Config.h @@ -0,0 +1,140 @@ +//===- Config.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_CONFIG_H +#define LLD_COFF_CONFIG_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFF.h" +#include +#include +#include +#include + +namespace lld { +namespace coff { + +using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; +using llvm::COFF::WindowsSubsystem; +using llvm::StringRef; +class DefinedAbsolute; +class DefinedRelative; +class Undefined; + +// Short aliases. +static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; +static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; +static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; + +// Represents an /export option. +struct Export { + StringRef Name; // N in /export:N or /export:E=N + StringRef ExtName; // E in /export:E=N + Undefined *Sym = nullptr; + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + + // True if this /export option was in .drectves section. + bool Directives = false; + StringRef SymbolName; + StringRef ExportName; // Name in DLL + + bool operator==(const Export &E) { + return (Name == E.Name && ExtName == E.ExtName && + Ordinal == E.Ordinal && Noname == E.Noname && + Data == E.Data && Private == E.Private); + } +}; + +// Global configuration. +struct Configuration { + enum ManifestKind { SideBySide, Embed, No }; + bool is64() { return Machine == AMD64; } + + llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; + bool Verbose = false; + WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; + Undefined *Entry = nullptr; + bool NoEntry = false; + std::string OutputFile; + bool DoGC = true; + bool DoICF = true; + bool Relocatable = true; + bool Force = false; + bool Debug = false; + bool WriteSymtab = true; + + // Symbols in this set are considered as live by the garbage collector. + std::set GCRoot; + + std::set NoDefaultLibs; + bool NoDefaultLibAll = false; + + // True if we are creating a DLL. + bool DLL = false; + StringRef Implib; + std::vector Exports; + std::set DelayLoads; + std::map DLLOrder; + Undefined *DelayLoadHelper = nullptr; + + // Used for SafeSEH. + DefinedRelative *SEHTable = nullptr; + DefinedAbsolute *SEHCount = nullptr; + + // Used for /opt:lldlto=N + unsigned LTOOptLevel = 2; + + // Used for /opt:lldltojobs=N + unsigned LTOJobs = 1; + + // Used for /merge:from=to (e.g. /merge:.rdata=.text) + std::map Merge; + + // Options for manifest files. + ManifestKind Manifest = SideBySide; + int ManifestID = 1; + StringRef ManifestDependency; + bool ManifestUAC = true; + StringRef ManifestLevel = "'asInvoker'"; + StringRef ManifestUIAccess = "'false'"; + StringRef ManifestFile; + + // Used for /failifmismatch. + std::map MustMatch; + + // Used for /alternatename. + std::map AlternateNames; + + uint64_t ImageBase = -1; + uint64_t StackReserve = 1024 * 1024; + uint64_t StackCommit = 4096; + uint64_t HeapReserve = 1024 * 1024; + uint64_t HeapCommit = 4096; + uint32_t MajorImageVersion = 0; + uint32_t MinorImageVersion = 0; + uint32_t MajorOSVersion = 6; + uint32_t MinorOSVersion = 0; + bool DynamicBase = true; + bool AllowBind = true; + bool NxCompat = true; + bool AllowIsolation = true; + bool TerminalServerAware = true; + bool LargeAddressAware = false; + bool HighEntropyVA = false; +}; + +extern Configuration *Config; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp new file mode 100644 index 00000000000..40ca5cf61dc --- /dev/null +++ b/COFF/DLL.cpp @@ -0,0 +1,556 @@ +//===- DLL.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines various types of chunks for the DLL import or export +// descriptor tables. They are inherently Windows-specific. +// You need to read Microsoft PE/COFF spec to understand details +// about the data structures. +// +// If you are not particularly interested in linking against Windows +// DLL, you can skip this file, and you should still be able to +// understand the rest of the linker. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "DLL.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Path.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::COFF; + +namespace lld { +namespace coff { +namespace { + +// Import table + +static int ptrSize() { return Config->is64() ? 8 : 4; } + +// A chunk for the import descriptor table. +class HintNameChunk : public Chunk { +public: + HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} + + size_t getSize() const override { + // Starts with 2 byte Hint field, followed by a null-terminated string, + // ends with 0 or 1 byte padding. + return RoundUpToAlignment(Name.size() + 3, 2); + } + + void writeTo(uint8_t *Buf) const override { + write16le(Buf + OutputSectionOff, Hint); + memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); + } + +private: + StringRef Name; + uint16_t Hint; +}; + +// A chunk for the import descriptor table. +class LookupChunk : public Chunk { +public: + explicit LookupChunk(Chunk *C) : HintName(C) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + write32le(Buf + OutputSectionOff, HintName->getRVA()); + } + + Chunk *HintName; +}; + +// A chunk for the import descriptor table. +// This chunk represent import-by-ordinal symbols. +// See Microsoft PE/COFF spec 7.1. Import Header for details. +class OrdinalOnlyChunk : public Chunk { +public: + explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + // An import-by-ordinal slot has MSB 1 to indicate that + // this is import-by-ordinal (and not import-by-name). + if (Config->is64()) { + write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); + } else { + write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); + } + } + + uint16_t Ordinal; +}; + +// A chunk for the import descriptor table. +class ImportDirectoryChunk : public Chunk { +public: + explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} + size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } + + void writeTo(uint8_t *Buf) const override { + auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); + E->ImportLookupTableRVA = LookupTab->getRVA(); + E->NameRVA = DLLName->getRVA(); + E->ImportAddressTableRVA = AddressTab->getRVA(); + } + + Chunk *DLLName; + Chunk *LookupTab; + Chunk *AddressTab; +}; + +// A chunk representing null terminator in the import table. +// Contents of this chunk is always null bytes. +class NullChunk : public Chunk { +public: + explicit NullChunk(size_t N) : Size(N) {} + bool hasData() const override { return false; } + size_t getSize() const override { return Size; } + void setAlign(size_t N) { Align = N; } + +private: + size_t Size; +}; + +static std::vector> +binImports(const std::vector &Imports) { + // Group DLL-imported symbols by DLL name because that's how + // symbols are layed out in the import descriptor table. + auto Less = [](const std::string &A, const std::string &B) { + return Config->DLLOrder[A] < Config->DLLOrder[B]; + }; + std::map, + bool(*)(const std::string &, const std::string &)> M(Less); + for (DefinedImportData *Sym : Imports) + M[Sym->getDLLName().lower()].push_back(Sym); + + std::vector> V; + for (auto &P : M) { + // Sort symbols by name for each group. + std::vector &Syms = P.second; + std::sort(Syms.begin(), Syms.end(), + [](DefinedImportData *A, DefinedImportData *B) { + return A->getName() < B->getName(); + }); + V.push_back(std::move(Syms)); + } + return V; +} + +// Export table +// See Microsoft PE/COFF spec 4.3 for details. + +// A chunk for the delay import descriptor table etnry. +class DelayDirectoryChunk : public Chunk { +public: + explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} + + size_t getSize() const override { + return sizeof(delay_import_directory_table_entry); + } + + void writeTo(uint8_t *Buf) const override { + auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); + E->Attributes = 1; + E->Name = DLLName->getRVA(); + E->ModuleHandle = ModuleHandle->getRVA(); + E->DelayImportAddressTable = AddressTab->getRVA(); + E->DelayImportNameTable = NameTab->getRVA(); + } + + Chunk *DLLName; + Chunk *ModuleHandle; + Chunk *AddressTab; + Chunk *NameTab; +}; + +// Initial contents for delay-loaded functions. +// This code calls __delayLoadHelper2 function to resolve a symbol +// and then overwrites its jump table slot with the result +// for subsequent function calls. +static const uint8_t ThunkX64[] = { + 0x51, // push rcx + 0x52, // push rdx + 0x41, 0x50, // push r8 + 0x41, 0x51, // push r9 + 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h + 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 + 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 + 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 + 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 + 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] + 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] + 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 + 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] + 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] + 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] + 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] + 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h + 0x41, 0x59, // pop r9 + 0x41, 0x58, // pop r8 + 0x5A, // pop rdx + 0x59, // pop rcx + 0xFF, 0xE0, // jmp rax +}; + +static const uint8_t ThunkX86[] = { + 0x51, // push ecx + 0x52, // push edx + 0x68, 0, 0, 0, 0, // push offset ___imp__ + 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll + 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 + 0x5A, // pop edx + 0x59, // pop ecx + 0xFF, 0xE0, // jmp eax +}; + +// A chunk for the delay import thunk. +class ThunkChunkX64 : public Chunk { +public: + ThunkChunkX64(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkX64); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); + write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); + write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); + write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); + } + + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; +}; + +class ThunkChunkX86 : public Chunk { +public: + ThunkChunkX86(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkX86); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); + write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); + } + + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA + 3); + Res->emplace_back(RVA + 8); + } + + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; +}; + +// A chunk for the import descriptor table. +class DelayAddressChunk : public Chunk { +public: + explicit DelayAddressChunk(Chunk *C) : Thunk(C) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + if (Config->is64()) { + write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + } else { + write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + } + } + + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA); + } + + Chunk *Thunk; +}; + +// Export table +// Read Microsoft PE/COFF spec 5.3 for details. + +// A chunk for the export descriptor table. +class ExportDirectoryChunk : public Chunk { +public: + ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) + : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), + OrdinalTab(O) {} + + size_t getSize() const override { + return sizeof(export_directory_table_entry); + } + + void writeTo(uint8_t *Buf) const override { + auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); + E->NameRVA = DLLName->getRVA(); + E->OrdinalBase = 0; + E->AddressTableEntries = MaxOrdinal + 1; + E->NumberOfNamePointers = NameTabSize; + E->ExportAddressTableRVA = AddressTab->getRVA(); + E->NamePointerRVA = NameTab->getRVA(); + E->OrdinalTableRVA = OrdinalTab->getRVA(); + } + + uint16_t MaxOrdinal; + uint16_t NameTabSize; + Chunk *DLLName; + Chunk *AddressTab; + Chunk *NameTab; + Chunk *OrdinalTab; +}; + +class AddressTableChunk : public Chunk { +public: + explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} + size_t getSize() const override { return Size * 4; } + + void writeTo(uint8_t *Buf) const override { + for (Export &E : Config->Exports) { + auto *D = cast(E.Sym->repl()); + write32le(Buf + OutputSectionOff + E.Ordinal * 4, D->getRVA()); + } + } + +private: + size_t Size; +}; + +class NamePointersChunk : public Chunk { +public: + explicit NamePointersChunk(std::vector &V) : Chunks(V) {} + size_t getSize() const override { return Chunks.size() * 4; } + + void writeTo(uint8_t *Buf) const override { + uint8_t *P = Buf + OutputSectionOff; + for (Chunk *C : Chunks) { + write32le(P, C->getRVA()); + P += 4; + } + } + +private: + std::vector Chunks; +}; + +class ExportOrdinalChunk : public Chunk { +public: + explicit ExportOrdinalChunk(size_t I) : Size(I) {} + size_t getSize() const override { return Size * 2; } + + void writeTo(uint8_t *Buf) const override { + uint8_t *P = Buf + OutputSectionOff; + for (Export &E : Config->Exports) { + if (E.Noname) + continue; + write16le(P, E.Ordinal); + P += 2; + } + } + +private: + size_t Size; +}; + +} // anonymous namespace + +uint64_t IdataContents::getDirSize() { + return Dirs.size() * sizeof(ImportDirectoryTableEntry); +} + +uint64_t IdataContents::getIATSize() { + return Addresses.size() * ptrSize(); +} + +// Returns a list of .idata contents. +// See Microsoft PE/COFF spec 5.4 for details. +std::vector IdataContents::getChunks() { + create(); + std::vector V; + // The loader assumes a specific order of data. + // Add each type in the correct order. + for (std::unique_ptr &C : Dirs) + V.push_back(C.get()); + for (std::unique_ptr &C : Lookups) + V.push_back(C.get()); + for (std::unique_ptr &C : Addresses) + V.push_back(C.get()); + for (std::unique_ptr &C : Hints) + V.push_back(C.get()); + for (auto &P : DLLNames) { + std::unique_ptr &C = P.second; + V.push_back(C.get()); + } + return V; +} + +void IdataContents::create() { + std::vector> V = binImports(Imports); + + // Create .idata contents for each DLL. + for (std::vector &Syms : V) { + StringRef Name = Syms[0]->getDLLName(); + + // Create lookup and address tables. If they have external names, + // we need to create HintName chunks to store the names. + // If they don't (if they are import-by-ordinals), we store only + // ordinal values to the table. + size_t Base = Lookups.size(); + for (DefinedImportData *S : Syms) { + uint16_t Ord = S->getOrdinal(); + if (S->getExternalName().empty()) { + Lookups.push_back(make_unique(Ord)); + Addresses.push_back(make_unique(Ord)); + continue; + } + auto C = make_unique(S->getExternalName(), Ord); + Lookups.push_back(make_unique(C.get())); + Addresses.push_back(make_unique(C.get())); + Hints.push_back(std::move(C)); + } + // Terminate with null values. + Lookups.push_back(make_unique(ptrSize())); + Addresses.push_back(make_unique(ptrSize())); + + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I].get()); + + // Create the import table header. + if (!DLLNames.count(Name)) + DLLNames[Name] = make_unique(Name); + auto Dir = make_unique(DLLNames[Name].get()); + Dir->LookupTab = Lookups[Base].get(); + Dir->AddressTab = Addresses[Base].get(); + Dirs.push_back(std::move(Dir)); + } + // Add null terminator. + Dirs.push_back(make_unique(sizeof(ImportDirectoryTableEntry))); +} + +std::vector DelayLoadContents::getChunks() { + std::vector V; + for (std::unique_ptr &C : Dirs) + V.push_back(C.get()); + for (std::unique_ptr &C : Names) + V.push_back(C.get()); + for (std::unique_ptr &C : HintNames) + V.push_back(C.get()); + for (auto &P : DLLNames) { + std::unique_ptr &C = P.second; + V.push_back(C.get()); + } + return V; +} + +std::vector DelayLoadContents::getDataChunks() { + std::vector V; + for (std::unique_ptr &C : ModuleHandles) + V.push_back(C.get()); + for (std::unique_ptr &C : Addresses) + V.push_back(C.get()); + return V; +} + +uint64_t DelayLoadContents::getDirSize() { + return Dirs.size() * sizeof(delay_import_directory_table_entry); +} + +void DelayLoadContents::create(Defined *H) { + Helper = H; + std::vector> V = binImports(Imports); + + // Create .didat contents for each DLL. + for (std::vector &Syms : V) { + StringRef Name = Syms[0]->getDLLName(); + + // Create the delay import table header. + if (!DLLNames.count(Name)) + DLLNames[Name] = make_unique(Name); + auto Dir = make_unique(DLLNames[Name].get()); + + size_t Base = Addresses.size(); + for (DefinedImportData *S : Syms) { + Chunk *T = newThunkChunk(S, Dir.get()); + auto A = make_unique(T); + Addresses.push_back(std::move(A)); + Thunks.push_back(std::unique_ptr(T)); + StringRef ExtName = S->getExternalName(); + if (ExtName.empty()) { + Names.push_back(make_unique(S->getOrdinal())); + } else { + auto C = make_unique(ExtName, 0); + Names.push_back(make_unique(C.get())); + HintNames.push_back(std::move(C)); + } + } + // Terminate with null values. + Addresses.push_back(make_unique(8)); + Names.push_back(make_unique(8)); + + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I].get()); + auto *MH = new NullChunk(8); + MH->setAlign(8); + ModuleHandles.push_back(std::unique_ptr(MH)); + + // Fill the delay import table header fields. + Dir->ModuleHandle = MH; + Dir->AddressTab = Addresses[Base].get(); + Dir->NameTab = Names[Base].get(); + Dirs.push_back(std::move(Dir)); + } + // Add null terminator. + Dirs.push_back( + make_unique(sizeof(delay_import_directory_table_entry))); +} + +Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { + switch (Config->Machine) { + case AMD64: + return new ThunkChunkX64(S, Dir, Helper); + case I386: + return new ThunkChunkX86(S, Dir, Helper); + default: + llvm_unreachable("unsupported machine type"); + } +} + +EdataContents::EdataContents() { + uint16_t MaxOrdinal = 0; + for (Export &E : Config->Exports) + MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); + + auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile)); + auto *AddressTab = new AddressTableChunk(MaxOrdinal); + std::vector Names; + for (Export &E : Config->Exports) + if (!E.Noname) + Names.push_back(new StringChunk(E.ExportName)); + auto *NameTab = new NamePointersChunk(Names); + auto *OrdinalTab = new ExportOrdinalChunk(Names.size()); + auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName, + AddressTab, NameTab, OrdinalTab); + Chunks.push_back(std::unique_ptr(Dir)); + Chunks.push_back(std::unique_ptr(DLLName)); + Chunks.push_back(std::unique_ptr(AddressTab)); + Chunks.push_back(std::unique_ptr(NameTab)); + Chunks.push_back(std::unique_ptr(OrdinalTab)); + for (Chunk *C : Names) + Chunks.push_back(std::unique_ptr(C)); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/DLL.h b/COFF/DLL.h new file mode 100644 index 00000000000..83a12df185c --- /dev/null +++ b/COFF/DLL.h @@ -0,0 +1,84 @@ +//===- DLL.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DLL_H +#define LLD_COFF_DLL_H + +#include "Chunks.h" +#include "Symbols.h" + +namespace lld { +namespace coff { + +// Windows-specific. +// IdataContents creates all chunks for the DLL import table. +// You are supposed to call add() to add symbols and then +// call getChunks() to get a list of chunks. +class IdataContents { +public: + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } + std::vector getChunks(); + + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } + uint64_t getDirSize(); + uint64_t getIATRVA() { return Addresses[0]->getRVA(); } + uint64_t getIATSize(); + +private: + void create(); + + std::vector Imports; + std::vector> Dirs; + std::vector> Lookups; + std::vector> Addresses; + std::vector> Hints; + std::map> DLLNames; +}; + +// Windows-specific. +// DelayLoadContents creates all chunks for the delay-load DLL import table. +class DelayLoadContents { +public: + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } + void create(Defined *Helper); + std::vector getChunks(); + std::vector getDataChunks(); + std::vector> &getCodeChunks() { return Thunks; } + + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } + uint64_t getDirSize(); + +private: + Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); + + Defined *Helper; + std::vector Imports; + std::vector> Dirs; + std::vector> ModuleHandles; + std::vector> Addresses; + std::vector> Names; + std::vector> HintNames; + std::vector> Thunks; + std::map> DLLNames; +}; + +// Windows-specific. +// EdataContents creates all chunks for the DLL export table. +class EdataContents { +public: + EdataContents(); + std::vector> Chunks; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp new file mode 100644 index 00000000000..f528dafd985 --- /dev/null +++ b/COFF/Driver.cpp @@ -0,0 +1,677 @@ +//===- Driver.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "InputFiles.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "Writer.h" +#include "llvm/ADT/Optional.h" +#include "llvm/LibDriver/LibDriver.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +using namespace llvm; +using namespace llvm::COFF; +using llvm::sys::Process; +using llvm::sys::fs::OpenFlags; +using llvm::sys::fs::file_magic; +using llvm::sys::fs::identify_magic; + +namespace lld { +namespace coff { + +Configuration *Config; +LinkerDriver *Driver; + +void link(llvm::ArrayRef Args) { + Configuration C; + LinkerDriver D; + Config = &C; + Driver = &D; + return Driver->link(Args); +} + +// Drop directory components and replace extension with ".exe". +static std::string getOutputPath(StringRef Path) { + auto P = Path.find_last_of("\\/"); + StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); + return (S.substr(0, S.rfind('.')) + ".exe").str(); +} + +// Opens a file. Path has to be resolved already. +// Newly created memory buffers are owned by this driver. +MemoryBufferRef LinkerDriver::openFile(StringRef Path) { + auto MBOrErr = MemoryBuffer::getFile(Path); + error(MBOrErr, Twine("Could not open ") + Path); + std::unique_ptr &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take ownership + return MBRef; +} + +static std::unique_ptr createFile(MemoryBufferRef MB) { + // File type is detected by contents, not by file extension. + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::archive) + return std::unique_ptr(new ArchiveFile(MB)); + if (Magic == file_magic::bitcode) + return std::unique_ptr(new BitcodeFile(MB)); + if (Config->OutputFile == "") + Config->OutputFile = getOutputPath(MB.getBufferIdentifier()); + return std::unique_ptr(new ObjectFile(MB)); +} + +static bool isDecorated(StringRef Sym) { + return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); +} + +// Parses .drectve section contents and returns a list of files +// specified by /defaultlib. +void LinkerDriver::parseDirectives(StringRef S) { + llvm::opt::InputArgList Args = Parser.parse(S); + + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_alternatename: + parseAlternateName(Arg->getValue()); + break; + case OPT_defaultlib: + if (Optional Path = findLib(Arg->getValue())) { + MemoryBufferRef MB = openFile(*Path); + Symtab.addFile(createFile(MB)); + } + break; + case OPT_export: { + Export E = parseExport(Arg->getValue()); + E.Directives = true; + Config->Exports.push_back(E); + break; + } + case OPT_failifmismatch: + checkFailIfMismatch(Arg->getValue()); + break; + case OPT_incl: + addUndefined(Arg->getValue()); + break; + case OPT_merge: + parseMerge(Arg->getValue()); + break; + case OPT_nodefaultlib: + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); + break; + case OPT_editandcontinue: + case OPT_guardsym: + case OPT_throwingnew: + break; + default: + error(Twine(Arg->getSpelling()) + " is not allowed in .drectve"); + } + } +} + +// Find file from search paths. You can omit ".obj", this function takes +// care of that. Note that the returned path is not guaranteed to exist. +StringRef LinkerDriver::doFindFile(StringRef Filename) { + bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); + if (hasPathSep) + return Filename; + bool hasExt = (Filename.find('.') != StringRef::npos); + for (StringRef Dir : SearchPaths) { + SmallString<128> Path = Dir; + llvm::sys::path::append(Path, Filename); + if (llvm::sys::fs::exists(Path.str())) + return Alloc.save(Path.str()); + if (!hasExt) { + Path.append(".obj"); + if (llvm::sys::fs::exists(Path.str())) + return Alloc.save(Path.str()); + } + } + return Filename; +} + +// Resolves a file path. This never returns the same path +// (in that case, it returns None). +Optional LinkerDriver::findFile(StringRef Filename) { + StringRef Path = doFindFile(Filename); + bool Seen = !VisitedFiles.insert(Path.lower()).second; + if (Seen) + return None; + return Path; +} + +// Find library file from search path. +StringRef LinkerDriver::doFindLib(StringRef Filename) { + // Add ".lib" to Filename if that has no file extension. + bool hasExt = (Filename.find('.') != StringRef::npos); + if (!hasExt) + Filename = Alloc.save(Filename + ".lib"); + return doFindFile(Filename); +} + +// Resolves a library path. /nodefaultlib options are taken into +// consideration. This never returns the same path (in that case, +// it returns None). +Optional LinkerDriver::findLib(StringRef Filename) { + if (Config->NoDefaultLibAll) + return None; + StringRef Path = doFindLib(Filename); + if (Config->NoDefaultLibs.count(Path)) + return None; + bool Seen = !VisitedFiles.insert(Path.lower()).second; + if (Seen) + return None; + return Path; +} + +// Parses LIB environment which contains a list of search paths. +void LinkerDriver::addLibSearchPaths() { + Optional EnvOpt = Process::GetEnv("LIB"); + if (!EnvOpt.hasValue()) + return; + StringRef Env = Alloc.save(*EnvOpt); + while (!Env.empty()) { + StringRef Path; + std::tie(Path, Env) = Env.split(';'); + SearchPaths.push_back(Path); + } +} + +Undefined *LinkerDriver::addUndefined(StringRef Name) { + Undefined *U = Symtab.addUndefined(Name); + Config->GCRoot.insert(U); + return U; +} + +// Symbol names are mangled by appending "_" prefix on x86. +StringRef LinkerDriver::mangle(StringRef Sym) { + assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); + if (Config->Machine == I386) + return Alloc.save("_" + Sym); + return Sym; +} + +// Windows specific -- find default entry point name. +StringRef LinkerDriver::findDefaultEntry() { + // User-defined main functions and their corresponding entry points. + static const char *Entries[][2] = { + {"main", "mainCRTStartup"}, + {"wmain", "wmainCRTStartup"}, + {"WinMain", "WinMainCRTStartup"}, + {"wWinMain", "wWinMainCRTStartup"}, + }; + for (auto E : Entries) { + StringRef Entry = Symtab.findMangle(mangle(E[0])); + if (!Entry.empty() && !isa(Symtab.find(Entry)->Body)) + return mangle(E[1]); + } + return ""; +} + +WindowsSubsystem LinkerDriver::inferSubsystem() { + if (Config->DLL) + return IMAGE_SUBSYSTEM_WINDOWS_GUI; + if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain")) + return IMAGE_SUBSYSTEM_WINDOWS_CUI; + if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain")) + return IMAGE_SUBSYSTEM_WINDOWS_GUI; + return IMAGE_SUBSYSTEM_UNKNOWN; +} + +static uint64_t getDefaultImageBase() { + if (Config->is64()) + return Config->DLL ? 0x180000000 : 0x140000000; + return Config->DLL ? 0x10000000 : 0x400000; +} + +void LinkerDriver::link(llvm::ArrayRef ArgsArr) { + // If the first command line argument is "/lib", link.exe acts like lib.exe. + // We call our own implementation of lib.exe that understands bitcode files. + if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { + if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) + error("lib failed"); + return; + } + + // Needed for LTO. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllDisassemblers(); + + // Parse command line options. + llvm::opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); + + // Handle /help + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); + return; + } + + if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) + error("no input files."); + + // Construct search path list. + SearchPaths.push_back(""); + for (auto *Arg : Args.filtered(OPT_libpath)) + SearchPaths.push_back(Arg->getValue()); + addLibSearchPaths(); + + // Handle /out + if (auto *Arg = Args.getLastArg(OPT_out)) + Config->OutputFile = Arg->getValue(); + + // Handle /verbose + if (Args.hasArg(OPT_verbose)) + Config->Verbose = true; + + // Handle /force or /force:unresolved + if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) + Config->Force = true; + + // Handle /debug + if (Args.hasArg(OPT_debug)) + Config->Debug = true; + + // Handle /noentry + if (Args.hasArg(OPT_noentry)) { + if (!Args.hasArg(OPT_dll)) + error("/noentry must be specified with /dll"); + Config->NoEntry = true; + } + + // Handle /dll + if (Args.hasArg(OPT_dll)) { + Config->DLL = true; + Config->ManifestID = 2; + } + + // Handle /fixed + if (Args.hasArg(OPT_fixed)) { + if (Args.hasArg(OPT_dynamicbase)) + error("/fixed must not be specified with /dynamicbase"); + Config->Relocatable = false; + Config->DynamicBase = false; + } + + // Handle /machine + if (auto *Arg = Args.getLastArg(OPT_machine)) + Config->Machine = getMachineType(Arg->getValue()); + + // Handle /nodefaultlib: + for (auto *Arg : Args.filtered(OPT_nodefaultlib)) + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); + + // Handle /nodefaultlib + if (Args.hasArg(OPT_nodefaultlib_all)) + Config->NoDefaultLibAll = true; + + // Handle /base + if (auto *Arg = Args.getLastArg(OPT_base)) + parseNumbers(Arg->getValue(), &Config->ImageBase); + + // Handle /stack + if (auto *Arg = Args.getLastArg(OPT_stack)) + parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); + + // Handle /heap + if (auto *Arg = Args.getLastArg(OPT_heap)) + parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); + + // Handle /version + if (auto *Arg = Args.getLastArg(OPT_version)) + parseVersion(Arg->getValue(), &Config->MajorImageVersion, + &Config->MinorImageVersion); + + // Handle /subsystem + if (auto *Arg = Args.getLastArg(OPT_subsystem)) + parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, + &Config->MinorOSVersion); + + // Handle /alternatename + for (auto *Arg : Args.filtered(OPT_alternatename)) + parseAlternateName(Arg->getValue()); + + // Handle /include + for (auto *Arg : Args.filtered(OPT_incl)) + addUndefined(Arg->getValue()); + + // Handle /implib + if (auto *Arg = Args.getLastArg(OPT_implib)) + Config->Implib = Arg->getValue(); + + // Handle /opt + for (auto *Arg : Args.filtered(OPT_opt)) { + std::string Str = StringRef(Arg->getValue()).lower(); + SmallVector Vec; + StringRef(Str).split(Vec, ','); + for (StringRef S : Vec) { + if (S == "noref") { + Config->DoGC = false; + Config->DoICF = false; + continue; + } + if (S == "icf" || StringRef(S).startswith("icf=")) { + Config->DoICF = true; + continue; + } + if (S == "noicf") { + Config->DoICF = false; + continue; + } + if (StringRef(S).startswith("lldlto=")) { + StringRef OptLevel = StringRef(S).substr(7); + if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || + Config->LTOOptLevel > 3) + error("/opt:lldlto: invalid optimization level: " + OptLevel); + continue; + } + if (StringRef(S).startswith("lldltojobs=")) { + StringRef Jobs = StringRef(S).substr(11); + if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) + error("/opt:lldltojobs: invalid job count: " + Jobs); + continue; + } + if (S != "ref" && S != "lbr" && S != "nolbr") + error(Twine("/opt: unknown option: ") + S); + } + } + + // Handle /failifmismatch + for (auto *Arg : Args.filtered(OPT_failifmismatch)) + checkFailIfMismatch(Arg->getValue()); + + // Handle /merge + for (auto *Arg : Args.filtered(OPT_merge)) + parseMerge(Arg->getValue()); + + // Handle /manifest + if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) + parseManifest(Arg->getValue()); + + // Handle /manifestuac + if (auto *Arg = Args.getLastArg(OPT_manifestuac)) + parseManifestUAC(Arg->getValue()); + + // Handle /manifestdependency + if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) + Config->ManifestDependency = Arg->getValue(); + + // Handle /manifestfile + if (auto *Arg = Args.getLastArg(OPT_manifestfile)) + Config->ManifestFile = Arg->getValue(); + + // Handle miscellaneous boolean flags. + if (Args.hasArg(OPT_allowbind_no)) + Config->AllowBind = false; + if (Args.hasArg(OPT_allowisolation_no)) + Config->AllowIsolation = false; + if (Args.hasArg(OPT_dynamicbase_no)) + Config->DynamicBase = false; + if (Args.hasArg(OPT_nxcompat_no)) + Config->NxCompat = false; + if (Args.hasArg(OPT_tsaware_no)) + Config->TerminalServerAware = false; + if (Args.hasArg(OPT_nosymtab)) + Config->WriteSymtab = false; + + // Create a list of input files. Files can be given as arguments + // for /defaultlib option. + std::vector Paths; + std::vector MBs; + for (auto *Arg : Args.filtered(OPT_INPUT)) + if (Optional Path = findFile(Arg->getValue())) + Paths.push_back(*Path); + for (auto *Arg : Args.filtered(OPT_defaultlib)) + if (Optional Path = findLib(Arg->getValue())) + Paths.push_back(*Path); + for (StringRef Path : Paths) + MBs.push_back(openFile(Path)); + + // Windows specific -- Create a resource file containing a manifest file. + if (Config->Manifest == Configuration::Embed) { + std::unique_ptr MB = createManifestRes(); + MBs.push_back(MB->getMemBufferRef()); + OwningMBs.push_back(std::move(MB)); // take ownership + } + + // Windows specific -- Input files can be Windows resource files (.res files). + // We invoke cvtres.exe to convert resource files to a regular COFF file + // then link the result file normally. + std::vector Resources; + auto NotResource = [](MemoryBufferRef MB) { + return identify_magic(MB.getBuffer()) != file_magic::windows_resource; + }; + auto It = std::stable_partition(MBs.begin(), MBs.end(), NotResource); + if (It != MBs.end()) { + Resources.insert(Resources.end(), It, MBs.end()); + MBs.erase(It, MBs.end()); + } + + // Read all input files given via the command line. Note that step() + // doesn't read files that are specified by directive sections. + for (MemoryBufferRef MB : MBs) + Symtab.addFile(createFile(MB)); + Symtab.step(); + + // Determine machine type and check if all object files are + // for the same CPU type. Note that this needs to be done before + // any call to mangle(). + for (std::unique_ptr &File : Symtab.getFiles()) { + MachineTypes MT = File->getMachineType(); + if (MT == IMAGE_FILE_MACHINE_UNKNOWN) + continue; + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + Config->Machine = MT; + continue; + } + if (Config->Machine != MT) + error(Twine(File->getShortName()) + ": machine type " + machineToStr(MT) + + " conflicts with " + machineToStr(Config->Machine)); + } + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n"; + Config->Machine = AMD64; + } + + // Windows specific -- Convert Windows resource files to a COFF file. + if (!Resources.empty()) { + std::unique_ptr MB = convertResToCOFF(Resources); + Symtab.addFile(createFile(MB->getMemBufferRef())); + OwningMBs.push_back(std::move(MB)); // take ownership + } + + // Handle /largeaddressaware + if (Config->is64() || Args.hasArg(OPT_largeaddressaware)) + Config->LargeAddressAware = true; + + // Handle /highentropyva + if (Config->is64() && !Args.hasArg(OPT_highentropyva_no)) + Config->HighEntropyVA = true; + + // Handle /entry and /dll + if (auto *Arg = Args.getLastArg(OPT_entry)) { + Config->Entry = addUndefined(mangle(Arg->getValue())); + } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) { + StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" + : "_DllMainCRTStartup"; + Config->Entry = addUndefined(S); + } else if (!Config->NoEntry) { + // Windows specific -- If entry point name is not given, we need to + // infer that from user-defined entry name. + StringRef S = findDefaultEntry(); + if (S.empty()) + error("entry point must be defined"); + Config->Entry = addUndefined(S); + if (Config->Verbose) + llvm::outs() << "Entry name inferred: " << S << "\n"; + } + + // Handle /export + for (auto *Arg : Args.filtered(OPT_export)) { + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386) { + if (!isDecorated(E.Name)) + E.Name = Alloc.save("_" + E.Name); + if (!E.ExtName.empty() && !isDecorated(E.ExtName)) + E.ExtName = Alloc.save("_" + E.ExtName); + } + Config->Exports.push_back(E); + } + + // Handle /def + if (auto *Arg = Args.getLastArg(OPT_deffile)) { + MemoryBufferRef MB = openFile(Arg->getValue()); + // parseModuleDefs mutates Config object. + parseModuleDefs(MB, &Alloc); + } + + // Handle /delayload + for (auto *Arg : Args.filtered(OPT_delayload)) { + Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); + if (Config->Machine == I386) { + Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); + } else { + Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); + } + } + + // Set default image base if /base is not given. + if (Config->ImageBase == uint64_t(-1)) + Config->ImageBase = getDefaultImageBase(); + + Symtab.addRelative(mangle("__ImageBase"), 0); + if (Config->Machine == I386) { + Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); + Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); + } + + // We do not support /guard:cf (control flow protection) yet. + // Define CFG symbols anyway so that we can link MSVC 2015 CRT. + Symtab.addAbsolute(mangle("__guard_fids_table"), 0); + Symtab.addAbsolute(mangle("__guard_fids_count"), 0); + Symtab.addAbsolute(mangle("__guard_flags"), 0x100); + + // Read as much files as we can from directives sections. + Symtab.run(); + + // Resolve auxiliary symbols until we get a convergence. + // (Trying to resolve a symbol may trigger a Lazy symbol to load a new file. + // A new file may contain a directive section to add new command line options. + // That's why we have to repeat until converge.) + for (;;) { + // Windows specific -- if entry point is not found, + // search for its mangled names. + if (Config->Entry) + Symtab.mangleMaybe(Config->Entry); + + // Windows specific -- Make sure we resolve all dllexported symbols. + for (Export &E : Config->Exports) { + E.Sym = addUndefined(E.Name); + if (!E.Directives) + Symtab.mangleMaybe(E.Sym); + } + + // Add weak aliases. Weak aliases is a mechanism to give remaining + // undefined symbols final chance to be resolved successfully. + for (auto Pair : Config->AlternateNames) { + StringRef From = Pair.first; + StringRef To = Pair.second; + Symbol *Sym = Symtab.find(From); + if (!Sym) + continue; + if (auto *U = dyn_cast(Sym->Body)) + if (!U->WeakAlias) + U->WeakAlias = Symtab.addUndefined(To); + } + + // Windows specific -- if __load_config_used can be resolved, resolve it. + if (Symtab.findUnderscore("_load_config_used")) + addUndefined(mangle("_load_config_used")); + + if (Symtab.queueEmpty()) + break; + Symtab.run(); + } + + // Do LTO by compiling bitcode input files to a set of native COFF files then + // link those files. + Symtab.addCombinedLTOObjects(); + + // Make sure we have resolved all symbols. + Symtab.reportRemainingUndefines(/*Resolve=*/true); + + // Windows specific -- if no /subsystem is given, we need to infer + // that from entry point name. + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { + Config->Subsystem = inferSubsystem(); + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) + error("subsystem must be defined"); + } + + // Handle /safeseh. + if (Args.hasArg(OPT_safeseh)) + for (ObjectFile *File : Symtab.ObjectFiles) + if (!File->SEHCompat) + error("/safeseh: " + File->getName() + " is not compatible with SEH"); + + // Windows specific -- when we are creating a .dll file, we also + // need to create a .lib file. + if (!Config->Exports.empty() || Config->DLL) { + fixupExports(); + writeImportLibrary(); + assignExportOrdinals(); + } + + // Windows specific -- Create a side-by-side manifest file. + if (Config->Manifest == Configuration::SideBySide) + createSideBySideManifest(); + + // Create a dummy PDB file to satisfy build sytem rules. + if (auto *Arg = Args.getLastArg(OPT_pdb)) + createPDB(Arg->getValue()); + + // Identify unreferenced COMDAT sections. + if (Config->DoGC) + markLive(Symtab.getChunks()); + + // Identify identical COMDAT sections to merge them. + if (Config->DoICF) + doICF(Symtab.getChunks()); + + // Write the result. + writeResult(&Symtab); + + // Create a symbol map file containing symbol VAs and their names + // to help debugging. + if (auto *Arg = Args.getLastArg(OPT_lldmap)) { + std::error_code EC; + llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text); + error(EC, "Could not create the symbol map"); + Symtab.printMap(Out); + } + // Call exit to avoid calling destructors. + exit(0); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Driver.h b/COFF/Driver.h new file mode 100644 index 00000000000..e50da20cbb0 --- /dev/null +++ b/COFF/Driver.h @@ -0,0 +1,180 @@ +//===- Driver.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DRIVER_H +#define LLD_COFF_DRIVER_H + +#include "Config.h" +#include "SymbolTable.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFF.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/StringSaver.h" +#include +#include +#include + +namespace lld { +namespace coff { + +class LinkerDriver; +extern LinkerDriver *Driver; + +using llvm::COFF::MachineTypes; +using llvm::COFF::WindowsSubsystem; +using llvm::Optional; +class InputFile; + +// Entry point of the COFF linker. +void link(llvm::ArrayRef Args); + +// Implemented in MarkLive.cpp. +void markLive(const std::vector &Chunks); + +// Implemented in ICF.cpp. +void doICF(const std::vector &Chunks); + +class ArgParser { +public: + ArgParser() : Alloc(AllocAux) {} + // Parses command line options. + llvm::opt::InputArgList parse(llvm::ArrayRef Args); + + // Concatenate LINK environment varirable and given arguments and parse them. + llvm::opt::InputArgList parseLINK(llvm::ArrayRef Args); + + // Tokenizes a given string and then parses as command line options. + llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } + +private: + std::vector tokenize(StringRef S); + + std::vector replaceResponseFiles(std::vector); + + llvm::BumpPtrAllocator AllocAux; + llvm::StringSaver Alloc; +}; + +class LinkerDriver { +public: + LinkerDriver() : Alloc(AllocAux) {} + void link(llvm::ArrayRef Args); + + // Used by the resolver to parse .drectve section contents. + void parseDirectives(StringRef S); + +private: + llvm::BumpPtrAllocator AllocAux; + llvm::StringSaver Alloc; + ArgParser Parser; + SymbolTable Symtab; + + // Opens a file. Path has to be resolved already. + MemoryBufferRef openFile(StringRef Path); + + // Searches a file from search paths. + Optional findFile(StringRef Filename); + Optional findLib(StringRef Filename); + StringRef doFindFile(StringRef Filename); + StringRef doFindLib(StringRef Filename); + + // Parses LIB environment which contains a list of search paths. + void addLibSearchPaths(); + + // Library search path. The first element is always "" (current directory). + std::vector SearchPaths; + std::set VisitedFiles; + + Undefined *addUndefined(StringRef Sym); + StringRef mangle(StringRef Sym); + + // Windows specific -- "main" is not the only main function in Windows. + // You can choose one from these four -- {w,}{WinMain,main}. + // There are four different entry point functions for them, + // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to + // choose the right one depending on which "main" function is defined. + // This function looks up the symbol table and resolve corresponding + // entry point name. + StringRef findDefaultEntry(); + WindowsSubsystem inferSubsystem(); + + // Driver is the owner of all opened files. + // InputFiles have MemoryBufferRefs to them. + std::vector> OwningMBs; +}; + +void parseModuleDefs(MemoryBufferRef MB, llvm::StringSaver *Alloc); +void writeImportLibrary(); + +// Functions below this line are defined in DriverUtils.cpp. + +void printHelp(const char *Argv0); + +// For /machine option. +MachineTypes getMachineType(StringRef Arg); +StringRef machineToStr(MachineTypes MT); + +// Parses a string in the form of "[,]". +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); + +// Parses a string in the form of "[.]". +// Minor's default value is 0. +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); + +// Parses a string in the form of "[,[.]]". +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor); + +void parseAlternateName(StringRef); +void parseMerge(StringRef); + +// Parses a string in the form of "EMBED[,=]|NO". +void parseManifest(StringRef Arg); + +// Parses a string in the form of "level=|uiAccess=" +void parseManifestUAC(StringRef Arg); + +// Create a resource file containing a manifest XML. +std::unique_ptr createManifestRes(); +void createSideBySideManifest(); + +// Used for dllexported symbols. +Export parseExport(StringRef Arg); +void fixupExports(); +void assignExportOrdinals(); + +// Parses a string in the form of "key=value" and check +// if value matches previous values for the key. +// This feature used in the directive section to reject +// incompatible objects. +void checkFailIfMismatch(StringRef Arg); + +// Convert Windows resource files (.res files) to a .obj file +// using cvtres.exe. +std::unique_ptr +convertResToCOFF(const std::vector &MBs); + +void touchFile(StringRef Path); +void createPDB(StringRef Path); + +// Create enum with OPT_xxx values for each option in Options.td +enum { + OPT_INVALID = 0, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp new file mode 100644 index 00000000000..391a8ab6642 --- /dev/null +++ b/COFF/DriverUtils.cpp @@ -0,0 +1,718 @@ +//===- DriverUtils.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains utility functions for the driver. Because there +// are so many small functions, we created this separate file to make +// Driver.cpp less cluttered. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "Symbols.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm::COFF; +using namespace llvm; +using llvm::cl::ExpandResponseFiles; +using llvm::cl::TokenizeWindowsCommandLine; +using llvm::sys::Process; + +namespace lld { +namespace coff { +namespace { + +class Executor { +public: + explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {} + void add(StringRef S) { Args.push_back(Saver.save(S)); } + void add(std::string &S) { Args.push_back(Saver.save(S)); } + void add(Twine S) { Args.push_back(Saver.save(S)); } + void add(const char *S) { Args.push_back(Saver.save(S)); } + + void run() { + ErrorOr ExeOrErr = llvm::sys::findProgramByName(Prog); + error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: "); + const char *Exe = Saver.save(*ExeOrErr); + Args.insert(Args.begin(), Exe); + Args.push_back(nullptr); + if (llvm::sys::ExecuteAndWait(Args[0], Args.data()) != 0) { + for (const char *S : Args) + if (S) + llvm::errs() << S << " "; + error("failed"); + } + } + +private: + llvm::BumpPtrAllocator Alloc; + llvm::StringSaver Saver; + StringRef Prog; + std::vector Args; +}; + +} // anonymous namespace + +// Returns /machine's value. +MachineTypes getMachineType(StringRef S) { + MachineTypes MT = StringSwitch(S.lower()) + .Case("x64", AMD64) + .Case("amd64", AMD64) + .Case("x86", I386) + .Case("i386", I386) + .Case("arm", ARMNT) + .Default(IMAGE_FILE_MACHINE_UNKNOWN); + if (MT != IMAGE_FILE_MACHINE_UNKNOWN) + return MT; + error(Twine("unknown /machine argument: ") + S); +} + +StringRef machineToStr(MachineTypes MT) { + switch (MT) { + case ARMNT: + return "arm"; + case AMD64: + return "x64"; + case I386: + return "x86"; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Parses a string in the form of "[,]". +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split(','); + if (S1.getAsInteger(0, *Addr)) + error(Twine("invalid number: ") + S1); + if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) + error(Twine("invalid number: ") + S2); +} + +// Parses a string in the form of "[.]". +// If second number is not present, Minor is set to 0. +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split('.'); + if (S1.getAsInteger(0, *Major)) + error(Twine("invalid number: ") + S1); + *Minor = 0; + if (!S2.empty() && S2.getAsInteger(0, *Minor)) + error(Twine("invalid number: ") + S2); +} + +// Parses a string in the form of "[,[.]]". +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor) { + StringRef SysStr, Ver; + std::tie(SysStr, Ver) = Arg.split(','); + *Sys = StringSwitch(SysStr.lower()) + .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) + .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) + .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) + .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) + .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) + .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) + .Case("native", IMAGE_SUBSYSTEM_NATIVE) + .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) + .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) + .Default(IMAGE_SUBSYSTEM_UNKNOWN); + if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) + error(Twine("unknown subsystem: ") + SysStr); + if (!Ver.empty()) + parseVersion(Ver, Major, Minor); +} + +// Parse a string of the form of "=". +// Results are directly written to Config. +void parseAlternateName(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + error(Twine("/alternatename: invalid argument: ") + S); + auto It = Config->AlternateNames.find(From); + if (It != Config->AlternateNames.end() && It->second != To) + error(Twine("/alternatename: conflicts: ") + S); + Config->AlternateNames.insert(It, std::make_pair(From, To)); +} + +// Parse a string of the form of "=". +// Results are directly written to Config. +void parseMerge(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + error(Twine("/merge: invalid argument: ") + S); + auto Pair = Config->Merge.insert(std::make_pair(From, To)); + bool Inserted = Pair.second; + if (!Inserted) { + StringRef Existing = Pair.first->second; + if (Existing != To) + llvm::errs() << "warning: " << S << ": already merged into " + << Existing << "\n"; + } +} + +// Parses a string in the form of "EMBED[,=]|NO". +// Results are directly written to Config. +void parseManifest(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->Manifest = Configuration::No; + return; + } + if (!Arg.startswith_lower("embed")) + error(Twine("Invalid option ") + Arg); + Config->Manifest = Configuration::Embed; + Arg = Arg.substr(strlen("embed")); + if (Arg.empty()) + return; + if (!Arg.startswith_lower(",id=")) + error(Twine("Invalid option ") + Arg); + Arg = Arg.substr(strlen(",id=")); + if (Arg.getAsInteger(0, Config->ManifestID)) + error(Twine("Invalid option ") + Arg); +} + +// Parses a string in the form of "level=|uiAccess=|NO". +// Results are directly written to Config. +void parseManifestUAC(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->ManifestUAC = false; + return; + } + for (;;) { + Arg = Arg.ltrim(); + if (Arg.empty()) + return; + if (Arg.startswith_lower("level=")) { + Arg = Arg.substr(strlen("level=")); + std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); + continue; + } + if (Arg.startswith_lower("uiaccess=")) { + Arg = Arg.substr(strlen("uiaccess=")); + std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); + continue; + } + error(Twine("Invalid option ") + Arg); + } +} + +// Quote each line with "". Existing double-quote is converted +// to two double-quotes. +static void quoteAndPrint(raw_ostream &Out, StringRef S) { + while (!S.empty()) { + StringRef Line; + std::tie(Line, S) = S.split("\n"); + if (Line.empty()) + continue; + Out << '\"'; + for (int I = 0, E = Line.size(); I != E; ++I) { + if (Line[I] == '\"') { + Out << "\"\""; + } else { + Out << Line[I]; + } + } + Out << "\"\n"; + } +} + +// Create a manifest file contents. +static std::string createManifestXml() { + std::string S; + llvm::raw_string_ostream OS(S); + // Emit the XML. Note that we do *not* verify that the XML attributes are + // syntactically correct. This is intentional for link.exe compatibility. + OS << "\n" + << "\n"; + if (Config->ManifestUAC) { + OS << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n"; + if (!Config->ManifestDependency.empty()) { + OS << " \n" + << " \n" + << " ManifestDependency << " />\n" + << " \n" + << " \n"; + } + } + OS << "\n"; + OS.flush(); + return S; +} + +// Create a resource file containing a manifest XML. +std::unique_ptr createManifestRes() { + // Create a temporary file for the resource script file. + SmallString<128> RCPath; + std::error_code EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath); + error(EC, "cannot create a temporary file"); + FileRemover RCRemover(RCPath); + + // Open the temporary file for writing. + llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text); + error(EC, Twine("failed to open ") + RCPath); + + // Write resource script to the RC file. + Out << "#define LANG_ENGLISH 9\n" + << "#define SUBLANG_DEFAULT 1\n" + << "#define APP_MANIFEST " << Config->ManifestID << "\n" + << "#define RT_MANIFEST 24\n" + << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n" + << "APP_MANIFEST RT_MANIFEST {\n"; + quoteAndPrint(Out, createManifestXml()); + Out << "}\n"; + Out.close(); + + // Create output resource file. + SmallString<128> ResPath; + EC = sys::fs::createTemporaryFile("tmp", "res", ResPath); + error(EC, "cannot create a temporary file"); + + Executor E("rc.exe"); + E.add("/fo"); + E.add(ResPath.str()); + E.add("/nologo"); + E.add(RCPath.str()); + E.run(); + ErrorOr> Ret = MemoryBuffer::getFile(ResPath); + error(Ret, Twine("Could not open ") + ResPath); + return std::move(*Ret); +} + +void createSideBySideManifest() { + std::string Path = Config->ManifestFile; + if (Path == "") + Path = (Twine(Config->OutputFile) + ".manifest").str(); + std::error_code EC; + llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text); + error(EC, "failed to create manifest"); + Out << createManifestXml(); +} + +// Parse a string in the form of +// "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]". +// Used for parsing /export arguments. +Export parseExport(StringRef Arg) { + Export E; + StringRef Rest; + std::tie(E.Name, Rest) = Arg.split(","); + if (E.Name.empty()) + goto err; + if (E.Name.find('=') != StringRef::npos) { + std::tie(E.ExtName, E.Name) = E.Name.split("="); + if (E.Name.empty()) + goto err; + } + + while (!Rest.empty()) { + StringRef Tok; + std::tie(Tok, Rest) = Rest.split(","); + if (Tok.equals_lower("noname")) { + if (E.Ordinal == 0) + goto err; + E.Noname = true; + continue; + } + if (Tok.equals_lower("data")) { + E.Data = true; + continue; + } + if (Tok.equals_lower("private")) { + E.Private = true; + continue; + } + if (Tok.startswith("@")) { + int32_t Ord; + if (Tok.substr(1).getAsInteger(0, Ord)) + goto err; + if (Ord <= 0 || 65535 < Ord) + goto err; + E.Ordinal = Ord; + continue; + } + goto err; + } + return E; + +err: + error(Twine("invalid /export: ") + Arg); +} + +static StringRef undecorate(StringRef Sym) { + if (Config->Machine != I386) + return Sym; + return Sym.startswith("_") ? Sym.substr(1) : Sym; +} + +// Performs error checking on all /export arguments. +// It also sets ordinals. +void fixupExports() { + // Symbol ordinals must be unique. + std::set Ords; + for (Export &E : Config->Exports) { + if (E.Ordinal == 0) + continue; + if (!Ords.insert(E.Ordinal).second) + error("duplicate export ordinal: " + E.Name); + } + + for (Export &E : Config->Exports) { + if (Undefined *U = cast_or_null(E.Sym->WeakAlias)) { + E.SymbolName = U->getName(); + } else { + E.SymbolName = E.Sym->getName(); + } + } + + for (Export &E : Config->Exports) + E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); + + // Uniquefy by name. + std::map Map; + std::vector V; + for (Export &E : Config->Exports) { + auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); + bool Inserted = Pair.second; + if (Inserted) { + V.push_back(E); + continue; + } + Export *Existing = Pair.first->second; + if (E == *Existing || E.Name != Existing->Name) + continue; + llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n"; + } + Config->Exports = std::move(V); + + // Sort by name. + std::sort(Config->Exports.begin(), Config->Exports.end(), + [](const Export &A, const Export &B) { + return A.ExportName < B.ExportName; + }); +} + +void assignExportOrdinals() { + // Assign unique ordinals if default (= 0). + uint16_t Max = 0; + for (Export &E : Config->Exports) + Max = std::max(Max, E.Ordinal); + for (Export &E : Config->Exports) + if (E.Ordinal == 0) + E.Ordinal = ++Max; +} + +// Parses a string in the form of "key=value" and check +// if value matches previous values for the same key. +void checkFailIfMismatch(StringRef Arg) { + StringRef K, V; + std::tie(K, V) = Arg.split('='); + if (K.empty() || V.empty()) + error(Twine("/failifmismatch: invalid argument: ") + Arg); + StringRef Existing = Config->MustMatch[K]; + if (!Existing.empty() && V != Existing) + error(Twine("/failifmismatch: mismatch detected: ") + Existing + " and " + + V + " for key " + K); + Config->MustMatch[K] = V; +} + +// Convert Windows resource files (.res files) to a .obj file +// using cvtres.exe. +std::unique_ptr +convertResToCOFF(const std::vector &MBs) { + // Create an output file path. + SmallString<128> Path; + if (llvm::sys::fs::createTemporaryFile("resource", "obj", Path)) + error("Could not create temporary file"); + + // Execute cvtres.exe. + Executor E("cvtres.exe"); + E.add("/machine:" + machineToStr(Config->Machine)); + E.add("/readonly"); + E.add("/nologo"); + E.add("/out:" + Path); + for (MemoryBufferRef MB : MBs) + E.add(MB.getBufferIdentifier()); + E.run(); + ErrorOr> Ret = MemoryBuffer::getFile(Path); + error(Ret, Twine("Could not open ") + Path); + return std::move(*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 a temporary file\n"; + return ""; + } + llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true); + OS << Contents; + return Path.str(); +} + +void touchFile(StringRef Path) { + int FD; + std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append); + error(EC, "failed to create a file"); + sys::Process::SafelyCloseFileDescriptor(FD); +} + +static std::string getImplibPath() { + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); +} + +static std::unique_ptr createEmptyImportLibrary() { + std::string S = (Twine("LIBRARY \"") + + llvm::sys::path::filename(Config->OutputFile) + "\"\n") + .str(); + std::string Path1 = writeToTempFile(S); + std::string Path2 = getImplibPath(); + llvm::FileRemover Remover1(Path1); + llvm::FileRemover Remover2(Path2); + + Executor E("lib.exe"); + E.add("/nologo"); + E.add("/machine:" + machineToStr(Config->Machine)); + E.add(Twine("/def:") + Path1); + E.add(Twine("/out:") + Path2); + E.run(); + + ErrorOr> BufOrErr = + MemoryBuffer::getFile(Path2, -1, false); + error(BufOrErr, Twine("Failed to open ") + Path2); + return MemoryBuffer::getMemBufferCopy((*BufOrErr)->getBuffer()); +} + +static std::vector +readMembers(const object::Archive &Archive) { + std::vector V; + for (const auto &ChildOrErr : Archive.children()) { + error(ChildOrErr, "Archive::Child::getName failed"); + const object::Archive::Child C(*ChildOrErr); + ErrorOr NameOrErr = C.getName(); + error(NameOrErr, "Archive::Child::getName failed"); + V.emplace_back(C, *NameOrErr); + } + return V; +} + +// This class creates short import files which is described in +// PE/COFF spec 7. Import Library Format. +class ShortImportCreator { +public: + ShortImportCreator(object::Archive *A, StringRef S) : Parent(A), DLLName(S) {} + + NewArchiveIterator create(StringRef Sym, uint16_t Ordinal, + ImportNameType NameType, bool isData) { + size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs + size_t Size = sizeof(object::ArchiveMemberHeader) + + sizeof(coff_import_header) + ImpSize; + char *Buf = Alloc.Allocate(Size); + memset(Buf, 0, Size); + char *P = Buf; + + // Write archive member header + auto *Hdr = reinterpret_cast(P); + P += sizeof(*Hdr); + sprintf(Hdr->Name, "%-12s", "dummy"); + sprintf(Hdr->LastModified, "%-12d", 0); + sprintf(Hdr->UID, "%-6d", 0); + sprintf(Hdr->GID, "%-6d", 0); + sprintf(Hdr->AccessMode, "%-8d", 0644); + sprintf(Hdr->Size, "%-10d", int(sizeof(coff_import_header) + ImpSize)); + + // Write short import library. + auto *Imp = reinterpret_cast(P); + P += sizeof(*Imp); + Imp->Sig2 = 0xFFFF; + Imp->Machine = Config->Machine; + Imp->SizeOfData = ImpSize; + if (Ordinal > 0) + Imp->OrdinalHint = Ordinal; + Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE); + Imp->TypeInfo |= NameType << 2; + + // Write symbol name and DLL name. + memcpy(P, Sym.data(), Sym.size()); + P += Sym.size() + 1; + memcpy(P, DLLName.data(), DLLName.size()); + + std::error_code EC; + object::Archive::Child C(Parent, Buf, &EC); + assert(!EC && "We created an invalid buffer"); + return NewArchiveIterator(C, DLLName); + } + +private: + BumpPtrAllocator Alloc; + object::Archive *Parent; + StringRef DLLName; +}; + +static ImportNameType getNameType(StringRef Sym, StringRef ExtName) { + if (Sym != ExtName) + return IMPORT_NAME_UNDECORATE; + if (Config->Machine == I386 && Sym.startswith("_")) + return IMPORT_NAME_NOPREFIX; + return IMPORT_NAME; +} + +static std::string replace(StringRef S, StringRef From, StringRef To) { + size_t Pos = S.find(From); + assert(Pos != StringRef::npos); + return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); +} + +// Creates an import library for a DLL. In this function, we first +// create an empty import library using lib.exe and then adds short +// import files to that file. +void writeImportLibrary() { + std::unique_ptr Buf = createEmptyImportLibrary(); + std::error_code EC; + object::Archive Archive(Buf->getMemBufferRef(), EC); + error(EC, "Error reading an empty import file"); + std::vector Members = readMembers(Archive); + + std::string DLLName = llvm::sys::path::filename(Config->OutputFile); + ShortImportCreator ShortImport(&Archive, DLLName); + for (Export &E : Config->Exports) { + if (E.Private) + continue; + if (E.ExtName.empty()) { + Members.push_back(ShortImport.create( + E.SymbolName, E.Ordinal, getNameType(E.SymbolName, E.Name), E.Data)); + } else { + Members.push_back(ShortImport.create( + replace(E.SymbolName, E.Name, E.ExtName), E.Ordinal, + getNameType(E.SymbolName, E.Name), E.Data)); + } + } + + std::string Path = getImplibPath(); + std::pair Result = + writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, + /*Deterministic*/ true, /*Thin*/ false); + error(Result.second, Twine("Failed to write ") + Path); +} + +// Create OptTable + +// Create prefix string literals used in Options.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +// Create table mapping all options defined in Options.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ + { \ + X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ + OPT_##GROUP, OPT_##ALIAS, X6 \ + }, +#include "Options.inc" +#undef OPTION +}; + +class COFFOptTable : public llvm::opt::OptTable { +public: + COFFOptTable() : OptTable(infoTable, true) {} +}; + +// Parses a given list of options. +llvm::opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { + // First, replace respnose files (@-style options). + std::vector Argv = replaceResponseFiles(ArgsArr); + + // Make InputArgList from string vectors. + COFFOptTable Table; + unsigned MissingIndex; + unsigned MissingCount; + llvm::opt::InputArgList Args = + Table.ParseArgs(Argv, MissingIndex, MissingCount); + + // Print the real command line if response files are expanded. + if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) { + llvm::outs() << "Command line:"; + for (const char *S : Argv) + llvm::outs() << " " << S; + llvm::outs() << "\n"; + } + + if (MissingCount) + error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + + "\", expected " + Twine(MissingCount) + + (MissingCount == 1 ? " argument." : " arguments.")); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) + llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; + return Args; +} + +llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef Args) { + // Concatenate LINK env and given arguments and parse them. + Optional Env = Process::GetEnv("LINK"); + if (!Env) + return parse(Args); + std::vector V = tokenize(*Env); + V.insert(V.end(), Args.begin(), Args.end()); + return parse(V); +} + +std::vector ArgParser::tokenize(StringRef S) { + SmallVector Tokens; + StringSaver Saver(AllocAux); + llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +// Creates a new command line by replacing options starting with '@' +// character. '@' is replaced by the file's contents. +std::vector +ArgParser::replaceResponseFiles(std::vector Argv) { + SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); + StringSaver Saver(AllocAux); + ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +void printHelp(const char *Argv0) { + COFFOptTable Table; + Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Error.cpp b/COFF/Error.cpp new file mode 100644 index 00000000000..255d9bbad9d --- /dev/null +++ b/COFF/Error.cpp @@ -0,0 +1,30 @@ +//===- Error.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace lld { +namespace coff { + +void error(const Twine &Msg) { + llvm::errs() << Msg << "\n"; + exit(1); +} + +void error(std::error_code EC, const Twine &Prefix) { + if (!EC) + return; + error(Prefix + ": " + EC.message()); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Error.h b/COFF/Error.h new file mode 100644 index 00000000000..cb0a185f091 --- /dev/null +++ b/COFF/Error.h @@ -0,0 +1,28 @@ +//===- Error.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_ERROR_H +#define LLD_COFF_ERROR_H + +#include "lld/Core/LLVM.h" + +namespace lld { +namespace coff { + +LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg); +void error(std::error_code EC, const Twine &Prefix); + +template void error(const ErrorOr &V, const Twine &Prefix) { + error(V.getError(), Prefix); +} + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp new file mode 100644 index 00000000000..f99b41624a8 --- /dev/null +++ b/COFF/ICF.cpp @@ -0,0 +1,244 @@ +//===- ICF.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Identical COMDAT Folding is a feature to merge COMDAT sections not by +// name (which is regular COMDAT handling) but by contents. If two COMDAT +// sections have the same data, relocations, attributes, etc., then the two +// are considered identical and merged by the linker. This optimization +// makes outputs smaller. +// +// ICF is theoretically a problem of reducing graphs by merging as many +// identical subgraphs as possible, if we consider sections as vertices and +// relocations as edges. This may be a bit more complicated problem than you +// might think. The order of processing sections matters since merging two +// sections can make other sections, whose relocations now point to the same +// section, mergeable. Graphs may contain cycles, which is common in COFF. +// We need a sophisticated algorithm to do this properly and efficiently. +// +// What we do in this file is this. We split sections into groups. Sections +// in the same group are considered identical. +// +// First, all sections are grouped by their "constant" values. Constant +// values are values that are never changed by ICF, such as section contents, +// section name, number of relocations, type and offset of each relocation, +// etc. Because we do not care about some relocation targets in this step, +// two sections in the same group may not be identical, but at least two +// sections in different groups can never be identical. +// +// Then, we try to split each group by relocation targets. Relocations are +// considered identical if and only if the relocation targets are in the +// same group. Splitting a group may make more groups to be splittable, +// because two relocations that were previously considered identical might +// now point to different groups. We repeat this step until the convergence +// is obtained. +// +// This algorithm is so-called "optimistic" algorithm described in +// http://research.google.com/pubs/pub36912.html. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Symbols.h" +#include "lld/Core/Parallel.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; + +namespace lld { +namespace coff { + +typedef std::vector::iterator ChunkIterator; +typedef bool (*Comparator)(const SectionChunk *, const SectionChunk *); + +class ICF { +public: + void run(const std::vector &V); + +private: + static uint64_t getHash(SectionChunk *C); + static bool equalsConstant(const SectionChunk *A, const SectionChunk *B); + static bool equalsVariable(const SectionChunk *A, const SectionChunk *B); + bool forEachGroup(std::vector &Chunks, Comparator Eq); + bool partition(ChunkIterator Begin, ChunkIterator End, Comparator Eq); + + std::atomic NextID = { 1 }; +}; + +// Entry point to ICF. +void doICF(const std::vector &Chunks) { + ICF().run(Chunks); +} + +uint64_t ICF::getHash(SectionChunk *C) { + return hash_combine(C->getPermissions(), + hash_value(C->SectionName), + C->NumRelocs, + C->getAlign(), + uint32_t(C->Header->SizeOfRawData), + C->Checksum); +} + +bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { + if (A->AssocChildren.size() != B->AssocChildren.size() || + A->NumRelocs != B->NumRelocs) { + return false; + } + + // Compare associative sections. + for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I) + if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID) + return false; + + // Compare relocations. + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + if (R1.Type != R2.Type || + R1.VirtualAddress != R2.VirtualAddress) { + return false; + } + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); + if (B1 == B2) + return true; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getValue() == D2->getValue() && + D1->getChunk()->GroupID == D2->getChunk()->GroupID; + return false; + }; + if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) + return false; + + // Compare section attributes and contents. + return A->getPermissions() == B->getPermissions() && + A->SectionName == B->SectionName && + A->getAlign() == B->getAlign() && + A->Header->SizeOfRawData == B->Header->SizeOfRawData && + A->Checksum == B->Checksum && + A->getContents() == B->getContents(); +} + +bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { + // Compare associative sections. + for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I) + if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID) + return false; + + // Compare relocations. + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); + if (B1 == B2) + return true; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getChunk()->GroupID == D2->getChunk()->GroupID; + return false; + }; + return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); +} + +bool ICF::partition(ChunkIterator Begin, ChunkIterator End, Comparator Eq) { + bool R = false; + for (auto It = Begin;;) { + SectionChunk *Head = *It; + auto Bound = std::partition(It + 1, End, [&](SectionChunk *SC) { + return Eq(Head, SC); + }); + if (Bound == End) + return R; + uint64_t ID = NextID++; + std::for_each(It, Bound, [&](SectionChunk *SC) { SC->GroupID = ID; }); + It = Bound; + R = true; + } +} + +bool ICF::forEachGroup(std::vector &Chunks, Comparator Eq) { + bool R = false; + for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) { + SectionChunk *Head = *It; + auto Bound = std::find_if(It + 1, End, [&](SectionChunk *SC) { + return SC->GroupID != Head->GroupID; + }); + if (partition(It, Bound, Eq)) + R = true; + It = Bound; + } + return R; +} + +// Merge identical COMDAT sections. +// Two sections are considered the same if their section headers, +// contents and relocations are all the same. +void ICF::run(const std::vector &Vec) { + // Collect only mergeable sections and group by hash value. + parallel_for_each(Vec.begin(), Vec.end(), [&](Chunk *C) { + if (auto *SC = dyn_cast(C)) { + bool Global = SC->Sym && SC->Sym->isExternal(); + bool Writable = SC->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + if (SC->isCOMDAT() && SC->isLive() && Global && !Writable) + SC->GroupID = getHash(SC) | (uint64_t(1) << 63); + } + }); + std::vector Chunks; + for (Chunk *C : Vec) { + if (auto *SC = dyn_cast(C)) { + if (SC->GroupID) { + Chunks.push_back(SC); + } else { + SC->GroupID = NextID++; + } + } + } + + // From now on, sections in Chunks are ordered so that sections in + // the same group are consecutive in the vector. + std::sort(Chunks.begin(), Chunks.end(), + [](SectionChunk *A, SectionChunk *B) { + return A->GroupID < B->GroupID; + }); + + // Split groups until we get a convergence. + int Cnt = 1; + forEachGroup(Chunks, equalsConstant); + + for (;;) { + if (!forEachGroup(Chunks, equalsVariable)) + break; + ++Cnt; + } + if (Config->Verbose) + llvm::outs() << "\nICF needed " << Cnt << " iterations.\n"; + + // Merge sections in the same group. + for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) { + SectionChunk *Head = *It++; + auto Bound = std::find_if(It, End, [&](SectionChunk *SC) { + return Head->GroupID != SC->GroupID; + }); + if (It == Bound) + continue; + if (Config->Verbose) + llvm::outs() << "Selected " << Head->getDebugName() << "\n"; + while (It != Bound) { + SectionChunk *SC = *It++; + if (Config->Verbose) + llvm::outs() << " Removed " << SC->getDebugName() << "\n"; + Head->replace(SC); + } + } +} + +} // namespace coff +} // namespace lld diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp new file mode 100644 index 00000000000..23fc2a08512 --- /dev/null +++ b/COFF/InputFiles.cpp @@ -0,0 +1,367 @@ +//===- InputFiles.cpp -----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/LTO/LTOModule.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm::support::endian; +using llvm::RoundUpToAlignment; +using llvm::Triple; +using llvm::support::ulittle32_t; +using llvm::sys::fs::file_magic; +using llvm::sys::fs::identify_magic; + +namespace lld { +namespace coff { + +int InputFile::NextIndex = 0; + +// Returns the last element of a path, which is supposed to be a filename. +static StringRef getBasename(StringRef Path) { + size_t Pos = Path.find_last_of("\\/"); + if (Pos == StringRef::npos) + return Path; + return Path.substr(Pos + 1); +} + +// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". +std::string InputFile::getShortName() { + if (ParentName == "") + return getName().lower(); + std::string Res = (getBasename(ParentName) + "(" + + getBasename(getName()) + ")").str(); + return StringRef(Res).lower(); +} + +void ArchiveFile::parse() { + // Parse a MemoryBufferRef as an archive file. + auto ArchiveOrErr = Archive::create(MB); + error(ArchiveOrErr, "Failed to parse static library"); + File = std::move(*ArchiveOrErr); + + // Allocate a buffer for Lazy objects. + size_t NumSyms = File->getNumberOfSymbols(); + LazySymbols.reserve(NumSyms); + + // Read the symbol table to construct Lazy objects. + for (const Archive::Symbol &Sym : File->symbols()) + LazySymbols.emplace_back(this, Sym); + + // Seen is a map from member files to boolean values. Initially + // all members are mapped to false, which indicates all these files + // are not read yet. + for (auto &ChildOrErr : File->children()) { + error(ChildOrErr, "Failed to parse static library"); + const Archive::Child &Child = *ChildOrErr; + Seen[Child.getChildOffset()].clear(); + } +} + +// Returns a buffer pointing to a member file containing a given symbol. +// This function is thread-safe. +MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { + auto COrErr = Sym->getMember(); + error(COrErr, Twine("Could not get the member for symbol ") + Sym->getName()); + const Archive::Child &C = *COrErr; + + // Return an empty buffer if we have already returned the same buffer. + if (Seen[C.getChildOffset()].test_and_set()) + return MemoryBufferRef(); + ErrorOr Ret = C.getMemoryBufferRef(); + error(Ret, Twine("Could not get the buffer for the member defining symbol ") + + Sym->getName()); + return *Ret; +} + +void ObjectFile::parse() { + // Parse a memory buffer as a COFF file. + auto BinOrErr = createBinary(MB); + error(BinOrErr, "Failed to parse object file"); + std::unique_ptr Bin = std::move(*BinOrErr); + + if (auto *Obj = dyn_cast(Bin.get())) { + Bin.release(); + COFFObj.reset(Obj); + } else { + error(Twine(getName()) + " is not a COFF file."); + } + + // Read section and symbol tables. + initializeChunks(); + initializeSymbols(); + initializeSEH(); +} + +void ObjectFile::initializeChunks() { + uint32_t NumSections = COFFObj->getNumberOfSections(); + Chunks.reserve(NumSections); + SparseChunks.resize(NumSections + 1); + for (uint32_t I = 1; I < NumSections + 1; ++I) { + const coff_section *Sec; + StringRef Name; + std::error_code EC = COFFObj->getSection(I, Sec); + error(EC, Twine("getSection failed: #") + Twine(I)); + EC = COFFObj->getSectionName(Sec, Name); + error(EC, Twine("getSectionName failed: #") + Twine(I)); + if (Name == ".sxdata") { + SXData = Sec; + continue; + } + if (Name == ".drectve") { + ArrayRef Data; + COFFObj->getSectionContents(Sec, Data); + Directives = std::string((const char *)Data.data(), Data.size()); + continue; + } + // Skip non-DWARF debug info. MSVC linker converts the sections into + // a PDB file, but we don't support that. + if (Name == ".debug" || Name.startswith(".debug$")) + continue; + // We want to preserve DWARF debug sections only when /debug is on. + if (!Config->Debug && Name.startswith(".debug")) + continue; + if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) + continue; + auto *C = new (Alloc) SectionChunk(this, Sec); + Chunks.push_back(C); + SparseChunks[I] = C; + } +} + +void ObjectFile::initializeSymbols() { + uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); + SymbolBodies.reserve(NumSymbols); + SparseSymbolBodies.resize(NumSymbols); + llvm::SmallVector WeakAliases; + int32_t LastSectionNumber = 0; + for (uint32_t I = 0; I < NumSymbols; ++I) { + // Get a COFFSymbolRef object. + auto SymOrErr = COFFObj->getSymbol(I); + error(SymOrErr, Twine("broken object file: ") + getName()); + + COFFSymbolRef Sym = *SymOrErr; + + const void *AuxP = nullptr; + if (Sym.getNumberOfAuxSymbols()) + AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); + bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); + + SymbolBody *Body = nullptr; + if (Sym.isUndefined()) { + Body = createUndefined(Sym); + } else if (Sym.isWeakExternal()) { + Body = createWeakExternal(Sym, AuxP); + WeakAliases.push_back((Undefined *)Body); + } else { + Body = createDefined(Sym, AuxP, IsFirst); + } + if (Body) { + SymbolBodies.push_back(Body); + SparseSymbolBodies[I] = Body; + } + I += Sym.getNumberOfAuxSymbols(); + LastSectionNumber = Sym.getSectionNumber(); + } + for (Undefined *U : WeakAliases) + U->WeakAlias = SparseSymbolBodies[(uintptr_t)U->WeakAlias]; +} + +Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + return new (Alloc) Undefined(Name); +} + +Undefined *ObjectFile::createWeakExternal(COFFSymbolRef Sym, const void *AuxP) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + auto *U = new (Alloc) Undefined(Name); + auto *Aux = (const coff_aux_weak_external *)AuxP; + U->WeakAlias = (Undefined *)(uintptr_t)Aux->TagIndex; + return U; +} + +Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, + bool IsFirst) { + StringRef Name; + if (Sym.isCommon()) { + auto *C = new (Alloc) CommonChunk(Sym); + Chunks.push_back(C); + return new (Alloc) DefinedCommon(this, Sym, C); + } + if (Sym.isAbsolute()) { + COFFObj->getSymbolName(Sym, Name); + // Skip special symbols. + if (Name == "@comp.id") + return nullptr; + // COFF spec 5.10.1. The .sxdata section. + if (Name == "@feat.00") { + if (Sym.getValue() & 1) + SEHCompat = true; + return nullptr; + } + return new (Alloc) DefinedAbsolute(Name, Sym); + } + if (Sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG) + return nullptr; + + // Nothing else to do without a section chunk. + auto *SC = cast_or_null(SparseChunks[Sym.getSectionNumber()]); + if (!SC) + return nullptr; + + // Handle section definitions + if (IsFirst && AuxP) { + auto *Aux = reinterpret_cast(AuxP); + if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) + if (auto *ParentSC = cast_or_null( + SparseChunks[Aux->getNumber(Sym.isBigObj())])) + ParentSC->addAssociative(SC); + SC->Checksum = Aux->CheckSum; + } + + auto *B = new (Alloc) DefinedRegular(this, Sym, SC); + if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) + SC->setSymbol(B); + + return B; +} + +void ObjectFile::initializeSEH() { + if (!SEHCompat || !SXData) + return; + ArrayRef A; + COFFObj->getSectionContents(SXData, A); + if (A.size() % 4 != 0) + error(".sxdata must be an array of symbol table indices"); + auto *I = reinterpret_cast(A.data()); + auto *E = reinterpret_cast(A.data() + A.size()); + for (; I != E; ++I) + SEHandlers.insert(SparseSymbolBodies[*I]); +} + +MachineTypes ObjectFile::getMachineType() { + if (COFFObj) + return static_cast(COFFObj->getMachine()); + return IMAGE_FILE_MACHINE_UNKNOWN; +} + +StringRef ltrim1(StringRef S, const char *Chars) { + if (!S.empty() && strchr(Chars, S[0])) + return S.substr(1); + return S; +} + +void ImportFile::parse() { + const char *Buf = MB.getBufferStart(); + const char *End = MB.getBufferEnd(); + const auto *Hdr = reinterpret_cast(Buf); + + // Check if the total size is valid. + if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) + error("broken import library"); + + // Read names and create an __imp_ symbol. + StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); + StringRef ImpName = StringAlloc.save(Twine("__imp_") + Name); + const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; + DLLName = StringRef(NameStart); + StringRef ExtName; + switch (Hdr->getNameType()) { + case IMPORT_ORDINAL: + ExtName = ""; + break; + case IMPORT_NAME: + ExtName = Name; + break; + case IMPORT_NAME_NOPREFIX: + ExtName = ltrim1(Name, "?@_"); + break; + case IMPORT_NAME_UNDECORATE: + ExtName = ltrim1(Name, "?@_"); + ExtName = ExtName.substr(0, ExtName.find('@')); + break; + } + ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExtName, Hdr); + SymbolBodies.push_back(ImpSym); + + // If type is function, we need to create a thunk which jump to an + // address pointed by the __imp_ symbol. (This allows you to call + // DLL functions just like regular non-DLL functions.) + if (Hdr->getType() != llvm::COFF::IMPORT_CODE) + return; + ThunkSym = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine); + SymbolBodies.push_back(ThunkSym); +} + +void BitcodeFile::parse() { + // Usually parse() is thread-safe, but bitcode file is an exception. + std::lock_guard Lock(Mu); + + ErrorOr> ModOrErr = + LTOModule::createFromBuffer(llvm::getGlobalContext(), MB.getBufferStart(), + MB.getBufferSize(), llvm::TargetOptions()); + error(ModOrErr, "Could not create lto module"); + M = std::move(*ModOrErr); + + llvm::StringSaver Saver(Alloc); + for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) { + lto_symbol_attributes Attrs = M->getSymbolAttributes(I); + if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) + continue; + + StringRef SymName = Saver.save(M->getSymbolName(I)); + int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK; + if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) { + SymbolBodies.push_back(new (Alloc) Undefined(SymName)); + } else { + bool Replaceable = + (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common + (Attrs & LTO_SYMBOL_COMDAT) || // comdat + (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external + (Attrs & LTO_SYMBOL_ALIAS))); + SymbolBodies.push_back(new (Alloc) DefinedBitcode(this, SymName, + Replaceable)); + } + } + + Directives = M->getLinkerOpts(); +} + +MachineTypes BitcodeFile::getMachineType() { + if (!M) + return IMAGE_FILE_MACHINE_UNKNOWN; + switch (Triple(M->getTargetTriple()).getArch()) { + case Triple::x86_64: + return AMD64; + case Triple::x86: + return I386; + case Triple::arm: + return ARMNT; + default: + return IMAGE_FILE_MACHINE_UNKNOWN; + } +} + +std::mutex BitcodeFile::Mu; + +} // namespace coff +} // namespace lld diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h new file mode 100644 index 00000000000..6a263fbaddf --- /dev/null +++ b/COFF/InputFiles.h @@ -0,0 +1,222 @@ +//===- InputFiles.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_INPUT_FILES_H +#define LLD_COFF_INPUT_FILES_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/LTO/LTOModule.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/StringSaver.h" +#include +#include +#include +#include + +namespace lld { +namespace coff { + +using llvm::LTOModule; +using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; +using llvm::COFF::MachineTypes; +using llvm::object::Archive; +using llvm::object::COFFObjectFile; +using llvm::object::COFFSymbolRef; +using llvm::object::coff_section; + +class Chunk; +class Defined; +class DefinedImportData; +class DefinedImportThunk; +class Lazy; +class SymbolBody; +class Undefined; + +// The root class of input files. +class InputFile { +public: + enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; + Kind kind() const { return FileKind; } + virtual ~InputFile() {} + + // Returns the filename. + StringRef getName() { return MB.getBufferIdentifier(); } + + // Returns symbols defined by this file. + virtual std::vector &getSymbols() = 0; + + // Reads a file (the constructor doesn't do that). + virtual void parse() = 0; + + // Returns the CPU type this file was compiled to. + virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + + // Returns a short, human-friendly filename. If this is a member of + // an archive file, a returned value includes parent's filename. + // Used for logging or debugging. + std::string getShortName(); + + // Sets a parent filename if this file is created from an archive. + void setParentName(StringRef N) { ParentName = N; } + + // Returns .drectve section contents if exist. + StringRef getDirectives() { return StringRef(Directives).trim(); } + + // Each file has a unique index. The index number is used to + // resolve ties in symbol resolution. + int Index; + static int NextIndex; + +protected: + InputFile(Kind K, MemoryBufferRef M) + : Index(NextIndex++), MB(M), FileKind(K) {} + + MemoryBufferRef MB; + std::string Directives; + +private: + const Kind FileKind; + StringRef ParentName; +}; + +// .lib or .a file. +class ArchiveFile : public InputFile { +public: + explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } + void parse() override; + + // Returns a memory buffer for a given symbol. An empty memory buffer + // is returned if we have already returned the same memory buffer. + // (So that we don't instantiate same members more than once.) + MemoryBufferRef getMember(const Archive::Symbol *Sym); + + llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + + // All symbols returned by ArchiveFiles are of Lazy type. + std::vector &getSymbols() override { + llvm_unreachable("internal error"); + } + +private: + std::unique_ptr File; + std::string Filename; + std::vector LazySymbols; + std::map Seen; +}; + +// .obj or .o file. This may be a member of an archive file. +class ObjectFile : public InputFile { +public: + explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } + void parse() override; + MachineTypes getMachineType() override; + std::vector &getChunks() { return Chunks; } + std::vector &getSymbols() override { return SymbolBodies; } + + // Returns a SymbolBody object for the SymbolIndex'th symbol in the + // underlying object file. + SymbolBody *getSymbolBody(uint32_t SymbolIndex) { + return SparseSymbolBodies[SymbolIndex]; + } + + // Returns the underying COFF file. + COFFObjectFile *getCOFFObj() { return COFFObj.get(); } + + // True if this object file is compatible with SEH. + // COFF-specific and x86-only. + bool SEHCompat = false; + + // The list of safe exception handlers listed in .sxdata section. + // COFF-specific and x86-only. + std::set SEHandlers; + +private: + void initializeChunks(); + void initializeSymbols(); + void initializeSEH(); + + Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst); + Undefined *createUndefined(COFFSymbolRef Sym); + Undefined *createWeakExternal(COFFSymbolRef Sym, const void *Aux); + + std::unique_ptr COFFObj; + llvm::BumpPtrAllocator Alloc; + const coff_section *SXData = nullptr; + + // List of all chunks defined by this file. This includes both section + // chunks and non-section chunks for common symbols. + std::vector Chunks; + + // This vector contains the same chunks as Chunks, but they are + // indexed such that you can get a SectionChunk by section index. + // Nonexistent section indices are filled with null pointers. + // (Because section number is 1-based, the first slot is always a + // null pointer.) + std::vector SparseChunks; + + // List of all symbols referenced or defined by this file. + std::vector SymbolBodies; + + // This vector contains the same symbols as SymbolBodies, but they + // are indexed such that you can get a SymbolBody by symbol + // index. Nonexistent indices (which are occupied by auxiliary + // symbols in the real symbol table) are filled with null pointers. + std::vector SparseSymbolBodies; +}; + +// This type represents import library members that contain DLL names +// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7 +// for details about the format. +class ImportFile : public InputFile { +public: + explicit ImportFile(MemoryBufferRef M) + : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {} + static bool classof(const InputFile *F) { return F->kind() == ImportKind; } + std::vector &getSymbols() override { return SymbolBodies; } + + DefinedImportData *ImpSym = nullptr; + DefinedImportThunk *ThunkSym = nullptr; + std::string DLLName; + +private: + void parse() override; + + std::vector SymbolBodies; + llvm::BumpPtrAllocator Alloc; + llvm::BumpPtrAllocator StringAllocAux; + llvm::StringSaver StringAlloc; +}; + +// Used for LTO. +class BitcodeFile : public InputFile { +public: + explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } + std::vector &getSymbols() override { return SymbolBodies; } + MachineTypes getMachineType() override; + + std::unique_ptr takeModule() { return std::move(M); } + +private: + void parse() override; + + std::vector SymbolBodies; + llvm::BumpPtrAllocator Alloc; + std::unique_ptr M; + static std::mutex Mu; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp new file mode 100644 index 00000000000..0870986ad81 --- /dev/null +++ b/COFF/MarkLive.cpp @@ -0,0 +1,61 @@ +//===- MarkLive.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include + +namespace lld { +namespace coff { + +// Set live bit on for each reachable chunk. Unmarked (unreachable) +// COMDAT chunks will be ignored by Writer, so they will be excluded +// from the final output. +void markLive(const std::vector &Chunks) { + // We build up a worklist of sections which have been marked as live. We only + // push into the worklist when we discover an unmarked section, and we mark + // as we push, so sections never appear twice in the list. + SmallVector Worklist; + + // COMDAT section chunks are dead by default. Add non-COMDAT chunks. + for (Chunk *C : Chunks) + if (auto *SC = dyn_cast(C)) + if (SC->isLive()) + Worklist.push_back(SC); + + auto Enqueue = [&](SectionChunk *C) { + if (C->isLive()) + return; + C->markLive(); + Worklist.push_back(C); + }; + + // Add GC root chunks. + for (Undefined *U : Config->GCRoot) + if (auto *D = dyn_cast(U->repl())) + Enqueue(D->getChunk()); + + while (!Worklist.empty()) { + SectionChunk *SC = Worklist.pop_back_val(); + assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); + + // Mark all symbols listed in the relocation table for this section. + for (SymbolBody *S : SC->symbols()) + if (auto *D = dyn_cast(S->repl())) + Enqueue(D->getChunk()); + + // Mark associative sections if any. + for (SectionChunk *C : SC->children()) + Enqueue(C); + } +} + +} +} diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp new file mode 100644 index 00000000000..d117e961f89 --- /dev/null +++ b/COFF/ModuleDef.cpp @@ -0,0 +1,291 @@ +//===- COFF/ModuleDef.cpp -------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Windows-specific. +// A parser for the module-definition file (.def file). +// Parsed results are directly written to Config global variable. +// +// The format of module-definition files are described in this document: +// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Error.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +namespace lld { +namespace coff { +namespace { + +enum Kind { + Unknown, + Eof, + Identifier, + Comma, + Equal, + KwBase, + KwData, + KwExports, + KwHeapsize, + KwLibrary, + KwName, + KwNoname, + KwPrivate, + KwStacksize, + KwVersion, +}; + +struct Token { + explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {} + Kind K; + StringRef Value; +}; + +static bool isDecorated(StringRef Sym) { + return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); +} + +class Lexer { +public: + explicit Lexer(StringRef S) : Buf(S) {} + + Token lex() { + Buf = Buf.trim(); + if (Buf.empty()) + return Token(Eof); + + switch (Buf[0]) { + case '\0': + return Token(Eof); + case ';': { + size_t End = Buf.find('\n'); + Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); + return lex(); + } + case '=': + Buf = Buf.drop_front(); + return Token(Equal, "="); + case ',': + Buf = Buf.drop_front(); + return Token(Comma, ","); + case '"': { + StringRef S; + std::tie(S, Buf) = Buf.substr(1).split('"'); + return Token(Identifier, S); + } + default: { + size_t End = Buf.find_first_of("=,\r\n \t\v"); + StringRef Word = Buf.substr(0, End); + Kind K = llvm::StringSwitch(Word) + .Case("BASE", KwBase) + .Case("DATA", KwData) + .Case("EXPORTS", KwExports) + .Case("HEAPSIZE", KwHeapsize) + .Case("LIBRARY", KwLibrary) + .Case("NAME", KwName) + .Case("NONAME", KwNoname) + .Case("PRIVATE", KwPrivate) + .Case("STACKSIZE", KwStacksize) + .Case("VERSION", KwVersion) + .Default(Identifier); + Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); + return Token(K, Word); + } + } + } + +private: + StringRef Buf; +}; + +class Parser { +public: + explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {} + + void parse() { + do { + parseOne(); + } while (Tok.K != Eof); + } + +private: + void read() { + if (Stack.empty()) { + Tok = Lex.lex(); + return; + } + Tok = Stack.back(); + Stack.pop_back(); + } + + void readAsInt(uint64_t *I) { + read(); + if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) + error("integer expected"); + } + + void expect(Kind Expected, StringRef Msg) { + read(); + if (Tok.K != Expected) + error(Msg); + } + + void unget() { Stack.push_back(Tok); } + + void parseOne() { + read(); + switch (Tok.K) { + case Eof: + return; + case KwExports: + for (;;) { + read(); + if (Tok.K != Identifier) { + unget(); + return; + } + parseExport(); + } + case KwHeapsize: + parseNumbers(&Config->HeapReserve, &Config->HeapCommit); + return; + case KwLibrary: + parseName(&Config->OutputFile, &Config->ImageBase); + if (!StringRef(Config->OutputFile).endswith_lower(".dll")) + Config->OutputFile += ".dll"; + return; + case KwStacksize: + parseNumbers(&Config->StackReserve, &Config->StackCommit); + return; + case KwName: + parseName(&Config->OutputFile, &Config->ImageBase); + return; + case KwVersion: + parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion); + return; + default: + error(Twine("unknown directive: ") + Tok.Value); + } + } + + void parseExport() { + Export E; + E.Name = Tok.Value; + read(); + if (Tok.K == Equal) { + read(); + if (Tok.K != Identifier) + error(Twine("identifier expected, but got ") + Tok.Value); + E.ExtName = E.Name; + E.Name = Tok.Value; + } else { + unget(); + } + + if (Config->Machine == I386) { + if (!isDecorated(E.Name)) + E.Name = Alloc->save("_" + E.Name); + if (!E.ExtName.empty() && !isDecorated(E.ExtName)) + E.ExtName = Alloc->save("_" + E.ExtName); + } + + for (;;) { + read(); + if (Tok.K == Identifier && Tok.Value[0] == '@') { + Tok.Value.drop_front().getAsInteger(10, E.Ordinal); + read(); + if (Tok.K == KwNoname) { + E.Noname = true; + } else { + unget(); + } + continue; + } + if (Tok.K == KwData) { + E.Data = true; + continue; + } + if (Tok.K == KwPrivate) { + E.Private = true; + continue; + } + unget(); + Config->Exports.push_back(E); + return; + } + } + + // HEAPSIZE/STACKSIZE reserve[,commit] + void parseNumbers(uint64_t *Reserve, uint64_t *Commit) { + readAsInt(Reserve); + read(); + if (Tok.K != Comma) { + unget(); + Commit = nullptr; + return; + } + readAsInt(Commit); + } + + // NAME outputPath [BASE=address] + void parseName(std::string *Out, uint64_t *Baseaddr) { + read(); + if (Tok.K == Identifier) { + *Out = Tok.Value; + } else { + *Out = ""; + unget(); + return; + } + read(); + if (Tok.K == KwBase) { + expect(Equal, "'=' expected"); + readAsInt(Baseaddr); + } else { + unget(); + *Baseaddr = 0; + } + } + + // VERSION major[.minor] + void parseVersion(uint32_t *Major, uint32_t *Minor) { + read(); + if (Tok.K != Identifier) + error(Twine("identifier expected, but got ") + Tok.Value); + StringRef V1, V2; + std::tie(V1, V2) = Tok.Value.split('.'); + if (V1.getAsInteger(10, *Major)) + error(Twine("integer expected, but got ") + Tok.Value); + if (V2.empty()) + *Minor = 0; + else if (V2.getAsInteger(10, *Minor)) + error(Twine("integer expected, but got ") + Tok.Value); + } + + Lexer Lex; + Token Tok; + std::vector Stack; + StringSaver *Alloc; +}; + +} // anonymous namespace + +void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) { + Parser(MB.getBuffer(), Alloc).parse(); +} + +} // namespace coff +} // namespace lld diff --git a/lib/Driver/WinLinkOptions.td b/COFF/Options.td similarity index 91% rename from lib/Driver/WinLinkOptions.td rename to COFF/Options.td index a545639b5bb..a21b8de76af 100644 --- a/lib/Driver/WinLinkOptions.td +++ b/COFF/Options.td @@ -15,31 +15,32 @@ multiclass B { def _no : F, HelpText; } +def align : P<"align", "Section alignment">; 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; +def delayload : P<"delayload", "Delay loaded DLL name">; 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">; +// No help text because /failifmismatch is not intended to be used by the user. 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 libpath : P<"libpath", "Additional library search path">; +def machine : P<"machine", "Specify target platform">; +def merge : P<"merge", "Combine sections">; +def mllvm : P<"mllvm", "Options to pass to LLVM">; +def nodefaultlib : P<"nodefaultlib", "Remove a default library">; +def opt : P<"opt", "Control optimizations">; +def out : P<"out", "Path to file to write output">; def pdb : P<"pdb", "PDB file path">; +def section : P<"section", "Specify section attributes">; +def stack : P<"stack", "Size of the stack">; +def stub : P<"stub", "Specify DOS stub file">; +def subsystem : P<"subsystem", "Specify subsystem">; +def version : P<"version", "Specify a version number in the PE header">; + +def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; def manifest : F<"manifest">; def manifest_colon : P<"manifest", "Create manifest file">; @@ -58,37 +59,38 @@ def incl : Joined<["/", "-"], "include:">, def deffile : Joined<["/", "-"], "def:">, HelpText<"Use module-definition file">; +def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; +def dll : F<"dll">, HelpText<"Create a DLL">; def nodefaultlib_all : F<"nodefaultlib">; def noentry : F<"noentry">; -def dll : F<"dll">; -def verbose : F<"verbose">; -def debug : F<"debug">; +def profile : F<"profile">; def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; -def profile : F<"profile">; +def verbose : F<"verbose">; 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">; + "Disable address space layout randomization">; +defm fixed : B<"fixed", "Enable base relocations">; defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">; +defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">; +defm nxcompat : B<"nxcompat", "Disable data execution provention">; +defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">; +defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">; def help : F<"help">; def help_q : Flag<["/?", "-?"], "">, Alias; -def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>; +// LLD extensions +def nosymtab : F<"nosymtab">; -// Flag for debug -def lldmoduledeffile : Joined<["/", "-"], "lldmoduledeffile:">; +// Flags for debugging +def lldmap : Joined<["/", "-"], "lldmap:">; //============================================================================== // The flags below do nothing. They are defined only for link.exe compatibility. @@ -106,6 +108,8 @@ def ignoreidl : F<"ignoreidl">; def incremental : F<"incremental">; def no_incremental : F<"incremental:no">; def nologo : F<"nologo">; +def throwingnew : F<"throwingnew">; +def editandcontinue : F<"editandcontinue">; def delay : QF<"delay">; def errorreport : QF<"errorreport">; @@ -116,5 +120,6 @@ def pdbaltpath : QF<"pdbaltpath">; def tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; def verbose_all : QF<"verbose">; +def guardsym : QF<"guardsym">; defm wx : QB<"wx">; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp new file mode 100644 index 00000000000..786d28798ba --- /dev/null +++ b/COFF/PDB.cpp @@ -0,0 +1,60 @@ +//===- PDB.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Driver.h" +#include "Error.h" +#include "Symbols.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FileOutputBuffer.h" +#include + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::support::endian; + +const int PageSize = 4096; +const uint8_t Magic[32] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; + +namespace { +struct PDBHeader { + uint8_t Magic[32]; + ulittle32_t PageSize; + ulittle32_t FpmPage; + ulittle32_t PageCount; + ulittle32_t RootSize; + ulittle32_t Reserved; + ulittle32_t RootPointer; +}; +} + +void lld::coff::createPDB(StringRef Path) { + // Create a file. + size_t FileSize = PageSize * 3; + ErrorOr> BufferOrErr = + FileOutputBuffer::create(Path, FileSize); + error(BufferOrErr, Twine("failed to open ") + Path); + std::unique_ptr Buffer = std::move(*BufferOrErr); + + // Write the file header. + uint8_t *Buf = Buffer->getBufferStart(); + auto *Hdr = reinterpret_cast(Buf); + memcpy(Hdr->Magic, Magic, sizeof(Magic)); + Hdr->PageSize = PageSize; + // I don't know what FpmPage field means, but it must not be 0. + Hdr->FpmPage = 1; + Hdr->PageCount = FileSize / PageSize; + // Root directory is empty, containing only the length field. + Hdr->RootSize = 4; + // Root directory is on page 1. + Hdr->RootPointer = 1; + + // Write the root directory. Root stream is on page 2. + write32le(Buf + PageSize, 2); + Buffer->commit(); +} diff --git a/COFF/README.md b/COFF/README.md new file mode 100644 index 00000000000..c1be560f440 --- /dev/null +++ b/COFF/README.md @@ -0,0 +1,265 @@ +The PE/COFF Linker +================== + +This directory contains a linker for Windows operating system. +Because the fundamental design of this port is different from +the other ports of LLD, this port is separated to this directory. + +The linker is command-line compatible with MSVC linker and is +generally 2x faster than that. It can be used to link real-world +programs such as LLD itself or Clang, or even web browsers which +are probably the largest open-source programs for Windows. + +This document is also applicable to ELF linker because the linker +shares the same design as this COFF linker. + +Overall Design +-------------- + +This is a list of important data types in this linker. + +* SymbolBody + + SymbolBody is a class for symbols. They may be created for symbols + in object files or in archive file headers. The linker may create + them out of nothing. + + There are mainly three types of SymbolBodies: Defined, Undefined, or + Lazy. Defined symbols are for all symbols that are considered as + "resolved", including real defined symbols, COMDAT symbols, common + symbols, absolute symbols, linker-created symbols, etc. Undefined + symbols are for undefined symbols, which need to be replaced by + Defined symbols by the resolver. Lazy symbols represent symbols we + found in archive file headers -- which can turn into Defined symbols + if we read archieve members, but we haven't done that yet. + +* Symbol + + Symbol is a pointer to a SymbolBody. There's only one Symbol for + each unique symbol name (this uniqueness is guaranteed by the symbol + table). Because SymbolBodies are created for each file + independently, there can be many SymbolBodies for the same + name. Thus, the relationship between Symbols and SymbolBodies is 1:N. + + The resolver keeps the Symbol's pointer to always point to the "best" + SymbolBody. Pointer mutation is the resolve operation in this + linker. + + SymbolBodies have pointers to their Symbols. That means you can + always find the best SymbolBody from any SymbolBody by following + pointers twice. This structure makes it very easy to find + replacements for symbols. For example, if you have an Undefined + SymbolBody, you can find a Defined SymbolBody for that symbol just + by going to its Symbol and then to SymbolBody, assuming the resolver + have successfully resolved all undefined symbols. + +* Chunk + + Chunk represents a chunk of data that will occupy space in an + output. Each regular section becomes a chunk. + Chunks created for common or BSS symbols are not backed by sections. + The linker may create chunks out of nothing to append additional + data to an output. + + Chunks know about their size, how to copy their data to mmap'ed + outputs, and how to apply relocations to them. Specifically, + section-based chunks know how to read relocation tables and how to + apply them. + +* SymbolTable + + SymbolTable is basically a hash table from strings to Symbols, with + a logic to resolve symbol conflicts. It resolves conflicts by symbol + type. For example, if we add Undefined and Defined symbols, the + symbol table will keep the latter. If we add Defined and Lazy + symbols, it will keep the former. If we add Lazy and Undefined, it + will keep the former, but it will also trigger the Lazy symbol to + load the archive member to actually resolve the symbol. + +* OutputSection + + OutputSection is a container of Chunks. A Chunk belongs to at most + one OutputSection. + +There are mainly three actors in this linker. + +* InputFile + + InputFile is a superclass of file readers. We have a different + subclass for each input file type, such as regular object file, + archive file, etc. They are responsible for creating and owning + SymbolBodies and Chunks. + +* Writer + + The writer is responsible for writing file headers and Chunks to a + file. It creates OutputSections, put all Chunks into them, assign + unique, non-overlapping addresses and file offsets to them, and then + write them down to a file. + +* Driver + + The linking process is drived by the driver. The driver + + - processes command line options, + - creates a symbol table, + - creates an InputFile for each input file and put all symbols in it + into the symbol table, + - checks if there's no remaining undefined symbols, + - creates a writer, + - and passes the symbol table to the writer to write the result to a + file. + +Performance +----------- + +It's generally 2x faster than MSVC link.exe. It takes 3.5 seconds to +self-host on my Xeon 2580 machine. MSVC linker takes 7.0 seconds to +link the same executable. The resulting output is 65MB. +The old LLD is buggy that it produces 120MB executable for some reason, +and it takes 30 seconds to do that. + +We believe the performance difference comes from simplification and +optimizations we made to the new port. Notable differences are listed +below. + +* Reduced number of relocation table reads + + In the old design, relocation tables are read from beginning to + construct graphs because they consist of graph edges. In the new + design, they are not read until we actually apply relocations. + + This simplification has two benefits. One is that we don't create + additional objects for relocations but instead consume relocation + tables directly. The other is that it reduces number of relocation + entries we have to read, because we won't read relocations for + dead-stripped COMDAT sections. Large C++ programs tend to consist of + lots of COMDAT sections. In the old design, the time to process + relocation table is linear to size of input. In this new model, it's + linear to size of output. + +* Reduced number of symbol table lookup + + Symbol table lookup can be a heavy operation because number of + symbols can be very large and each symbol name can be very long + (think of C++ mangled symbols -- time to compute a hash value for a + string is linear to the length.) + + We look up the symbol table exactly only once for each symbol in the + new design. This is I believe the minimum possible number. This is + achieved by the separation of Symbol and SymbolBody. Once you get a + pointer to a Symbol by looking up the symbol table, you can always + get the latest symbol resolution result by just dereferencing a + pointer. (I'm not sure if the idea is new to the linker. At least, + all other linkers I've investigated so far seem to look up hash + tables or sets more than once for each new symbol, but I may be + wrong.) + +* Reduced number of file visits + + The symbol table implements the Windows linker semantics. We treat + the symbol table as a bucket of all known symbols, including symbols + in archive file headers. We put all symbols into one bucket as we + visit new files. That means we visit each file only once. + + This is different from the Unix linker semantics, in which we only + keep undefined symbols and visit each file one by one until we + resolve all undefined symbols. In the Unix model, we have to visit + archive files many times if there are circular dependencies between + archives. + +* Avoiding creating additional objects or copying data + + The data structures described in the previous section are all thin + wrappers for classes that LLVM libObject provides. We avoid copying + data from libObject's objects to our objects. We read much less data + than before. For example, we don't read symbol values until we apply + relocations because these values are not relevant to symbol + resolution. Again, COMDAT symbols may be discarded during symbol + resolution, so reading their attributes too early could result in a + waste. We use underlying objects directly where doing so makes + sense. + +Parallelism +----------- + +The abovementioned data structures are also chosen with +multi-threading in mind. It should relatively be easy to make the +symbol table a concurrent hash map, so that we let multiple workers +work on symbol table concurrently. Symbol resolution in this design is +a single pointer mutation, which allows the resolver work concurrently +in a lock-free manner using atomic pointer compare-and-swap. + +It should also be easy to apply relocations and write chunks concurrently. + +We created an experimental multi-threaded linker using the Microsoft +ConcRT concurrency library, and it was able to link itself in 0.5 +seconds, so we think the design is promising. + +Link-Time Optimization +---------------------- + +LTO is implemented by handling LLVM bitcode files as object files. +The linker resolves symbols in bitcode files normally. If all symbols +are successfully resolved, it then calls an LLVM libLTO function +with all bitcode files to convert them to one big regular COFF file. +Finally, the linker replaces bitcode symbols with COFF symbols, +so that we can link the input files as if they were in the native +format from the beginning. + +The details are described in this document. +http://llvm.org/docs/LinkTimeOptimization.html + +Glossary +-------- + +* RVA + + Short for Relative Virtual Address. + + Windows executables or DLLs are not position-independent; they are + linked against a fixed address called an image base. RVAs are + offsets from an image base. + + Default image bases are 0x140000000 for executables and 0x18000000 + for DLLs. For example, when we are creating an executable, we assume + that the executable will be loaded at address 0x140000000 by the + loader, so we apply relocations accordingly. Result texts and data + will contain raw absolute addresses. + +* VA + + Short for Virtual Address. Equivalent to RVA + image base. It is + rarely used. We almost always use RVAs instead. + +* Base relocations + + Relocation information for the loader. If the loader decides to map + an executable or a DLL to a different address than their image + bases, it fixes up binaries using information contained in the base + relocation table. A base relocation table consists of a list of + locations containing addresses. The loader adds a difference between + RVA and actual load address to all locations listed there. + + Note that this run-time relocation mechanism is much simpler than ELF. + There's no PLT or GOT. Images are relocated as a whole just + by shifting entire images in memory by some offsets. Although doing + this breaks text sharing, I think this mechanism is not actually bad + on today's computers. + +* ICF + + Short for Identical COMDAT Folding. + + ICF is an optimization to reduce output size by merging COMDAT sections + by not only their names but by their contents. If two COMDAT sections + happen to have the same metadata, actual contents and relocations, + they are merged by ICF. It is known as an effective technique, + and it usually reduces C++ program's size by a few percent or more. + + Note that this is not entirely sound optimization. C/C++ require + different functions have different addresses. If a program depends on + that property, it would fail at runtime. However, that's not really an + issue on Windows because MSVC link.exe enabled the optimization by + default. As long as your program works with the linker's default + settings, your program should be safe with ICF. diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp new file mode 100644 index 00000000000..5b7b89cd360 --- /dev/null +++ b/COFF/SymbolTable.cpp @@ -0,0 +1,445 @@ +//===- SymbolTable.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "lld/Core/Parallel.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +namespace lld { +namespace coff { + +void SymbolTable::addFile(std::unique_ptr FileP) { +#if LLVM_ENABLE_THREADS + std::launch Policy = std::launch::async; +#else + std::launch Policy = std::launch::deferred; +#endif + + InputFile *File = FileP.get(); + Files.push_back(std::move(FileP)); + if (auto *F = dyn_cast(File)) { + ArchiveQueue.push_back( + std::async(Policy, [=]() { F->parse(); return F; })); + return; + } + ObjectQueue.push_back( + std::async(Policy, [=]() { File->parse(); return File; })); + if (auto *F = dyn_cast(File)) { + ObjectFiles.push_back(F); + } else if (auto *F = dyn_cast(File)) { + BitcodeFiles.push_back(F); + } else { + ImportFiles.push_back(cast(File)); + } +} + +void SymbolTable::step() { + if (queueEmpty()) + return; + readObjects(); + readArchives(); +} + +void SymbolTable::run() { + while (!queueEmpty()) + step(); +} + +void SymbolTable::readArchives() { + if (ArchiveQueue.empty()) + return; + + // Add lazy symbols to the symbol table. Lazy symbols that conflict + // with existing undefined symbols are accumulated in LazySyms. + std::vector LazySyms; + for (std::future &Future : ArchiveQueue) { + ArchiveFile *File = Future.get(); + if (Config->Verbose) + llvm::outs() << "Reading " << File->getShortName() << "\n"; + for (Lazy &Sym : File->getLazySymbols()) + addLazy(&Sym, &LazySyms); + } + ArchiveQueue.clear(); + + // Add archive member files to ObjectQueue that should resolve + // existing undefined symbols. + for (Symbol *Sym : LazySyms) + addMemberFile(cast(Sym->Body)); +} + +void SymbolTable::readObjects() { + if (ObjectQueue.empty()) + return; + + // Add defined and undefined symbols to the symbol table. + std::vector Directives; + for (size_t I = 0; I < ObjectQueue.size(); ++I) { + InputFile *File = ObjectQueue[I].get(); + if (Config->Verbose) + llvm::outs() << "Reading " << File->getShortName() << "\n"; + // Adding symbols may add more files to ObjectQueue + // (but not to ArchiveQueue). + for (SymbolBody *Sym : File->getSymbols()) + if (Sym->isExternal()) + addSymbol(Sym); + StringRef S = File->getDirectives(); + if (!S.empty()) { + Directives.push_back(S); + if (Config->Verbose) + llvm::outs() << "Directives: " << File->getShortName() + << ": " << S << "\n"; + } + } + ObjectQueue.clear(); + + // Parse directive sections. This may add files to + // ArchiveQueue and ObjectQueue. + for (StringRef S : Directives) + Driver->parseDirectives(S); +} + +bool SymbolTable::queueEmpty() { + return ArchiveQueue.empty() && ObjectQueue.empty(); +} + +void SymbolTable::reportRemainingUndefines(bool Resolve) { + llvm::SmallPtrSet Undefs; + for (auto &I : Symtab) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym->Body); + if (!Undef) + continue; + StringRef Name = Undef->getName(); + // A weak alias may have been resolved, so check for that. + if (Defined *D = Undef->getWeakAlias()) { + if (Resolve) + Sym->Body = D; + continue; + } + // If we can resolve a symbol by removing __imp_ prefix, do that. + // This odd rule is for compatibility with MSVC linker. + if (Name.startswith("__imp_")) { + Symbol *Imp = find(Name.substr(strlen("__imp_"))); + if (Imp && isa(Imp->Body)) { + if (!Resolve) + continue; + auto *D = cast(Imp->Body); + auto *S = new (Alloc) DefinedLocalImport(Name, D); + LocalImportChunks.push_back(S->getChunk()); + Sym->Body = S; + continue; + } + } + // Remaining undefined symbols are not fatal if /force is specified. + // They are replaced with dummy defined symbols. + if (Config->Force && Resolve) + Sym->Body = new (Alloc) DefinedAbsolute(Name, 0); + Undefs.insert(Sym->Body); + } + if (Undefs.empty()) + return; + for (Undefined *U : Config->GCRoot) + if (Undefs.count(U->repl())) + llvm::errs() << ": undefined symbol: " << U->getName() << "\n"; + for (std::unique_ptr &File : Files) + if (!isa(File.get())) + for (SymbolBody *Sym : File->getSymbols()) + if (Undefs.count(Sym->repl())) + llvm::errs() << File->getShortName() << ": undefined symbol: " + << Sym->getName() << "\n"; + if (!Config->Force) + error("Link failed"); +} + +void SymbolTable::addLazy(Lazy *New, std::vector *Accum) { + Symbol *Sym = insert(New); + if (Sym->Body == New) + return; + SymbolBody *Existing = Sym->Body; + if (isa(Existing)) + return; + if (Lazy *L = dyn_cast(Existing)) + if (L->getFileIndex() < New->getFileIndex()) + return; + Sym->Body = New; + New->setBackref(Sym); + if (isa(Existing)) + Accum->push_back(Sym); +} + +void SymbolTable::addSymbol(SymbolBody *New) { + // Find an existing symbol or create and insert a new one. + assert(isa(New) || isa(New)); + Symbol *Sym = insert(New); + if (Sym->Body == New) + return; + SymbolBody *Existing = Sym->Body; + + // If we have an undefined symbol and a lazy symbol, + // let the lazy symbol to read a member file. + if (auto *L = dyn_cast(Existing)) { + // Undefined symbols with weak aliases need not to be resolved, + // since they would be replaced with weak aliases if they remain + // undefined. + if (auto *U = dyn_cast(New)) { + if (!U->WeakAlias) { + addMemberFile(L); + return; + } + } + Sym->Body = New; + return; + } + + // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, + // equivalent (conflicting), or more preferable, respectively. + int Comp = Existing->compare(New); + if (Comp == 0) + error(Twine("duplicate symbol: ") + Existing->getDebugName() + " and " + + New->getDebugName()); + if (Comp < 0) + Sym->Body = New; +} + +Symbol *SymbolTable::insert(SymbolBody *New) { + Symbol *&Sym = Symtab[New->getName()]; + if (Sym) { + New->setBackref(Sym); + return Sym; + } + Sym = new (Alloc) Symbol(New); + New->setBackref(Sym); + return Sym; +} + +// Reads an archive member file pointed by a given symbol. +void SymbolTable::addMemberFile(Lazy *Body) { + std::unique_ptr File = Body->getMember(); + + // getMember returns an empty buffer if the member was already + // read from the library. + if (!File) + return; + if (Config->Verbose) + llvm::outs() << "Loaded " << File->getShortName() << " for " + << Body->getName() << "\n"; + addFile(std::move(File)); +} + +std::vector SymbolTable::getChunks() { + std::vector Res; + for (ObjectFile *File : ObjectFiles) { + std::vector &V = File->getChunks(); + Res.insert(Res.end(), V.begin(), V.end()); + } + return Res; +} + +Symbol *SymbolTable::find(StringRef Name) { + auto It = Symtab.find(Name); + if (It == Symtab.end()) + return nullptr; + return It->second; +} + +Symbol *SymbolTable::findUnderscore(StringRef Name) { + if (Config->Machine == I386) + return find(("_" + Name).str()); + return find(Name); +} + +StringRef SymbolTable::findByPrefix(StringRef Prefix) { + for (auto Pair : Symtab) { + StringRef Name = Pair.first; + if (Name.startswith(Prefix)) + return Name; + } + return ""; +} + +StringRef SymbolTable::findMangle(StringRef Name) { + if (Symbol *Sym = find(Name)) + if (!isa(Sym->Body)) + return Name; + if (Config->Machine != I386) + return findByPrefix(("?" + Name + "@@Y").str()); + if (!Name.startswith("_")) + return ""; + // Search for x86 C function. + StringRef S = findByPrefix((Name + "@").str()); + if (!S.empty()) + return S; + // Search for x86 C++ non-member function. + return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); +} + +void SymbolTable::mangleMaybe(Undefined *U) { + if (U->WeakAlias) + return; + if (!isa(U->repl())) + return; + StringRef Alias = findMangle(U->getName()); + if (!Alias.empty()) + U->WeakAlias = addUndefined(Alias); +} + +Undefined *SymbolTable::addUndefined(StringRef Name) { + auto *New = new (Alloc) Undefined(Name); + addSymbol(New); + if (auto *U = dyn_cast(New->repl())) + return U; + return New; +} + +DefinedRelative *SymbolTable::addRelative(StringRef Name, uint64_t VA) { + auto *New = new (Alloc) DefinedRelative(Name, VA); + addSymbol(New); + return New; +} + +DefinedAbsolute *SymbolTable::addAbsolute(StringRef Name, uint64_t VA) { + auto *New = new (Alloc) DefinedAbsolute(Name, VA); + addSymbol(New); + return New; +} + +void SymbolTable::printMap(llvm::raw_ostream &OS) { + for (ObjectFile *File : ObjectFiles) { + OS << File->getShortName() << ":\n"; + for (SymbolBody *Body : File->getSymbols()) + if (auto *R = dyn_cast(Body)) + if (R->getChunk()->isLive()) + OS << Twine::utohexstr(Config->ImageBase + R->getRVA()) + << " " << R->getName() << "\n"; + } +} + +void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) { + for (SymbolBody *Body : Obj->getSymbols()) { + if (!Body->isExternal()) + continue; + // We should not see any new undefined symbols at this point, but we'll + // diagnose them later in reportRemainingUndefines(). + StringRef Name = Body->getName(); + Symbol *Sym = insert(Body); + + if (isa(Sym->Body)) { + Sym->Body = Body; + continue; + } + if (auto *L = dyn_cast(Sym->Body)) { + // We may see new references to runtime library symbols such as __chkstk + // here. These symbols must be wholly defined in non-bitcode files. + addMemberFile(L); + continue; + } + SymbolBody *Existing = Sym->Body; + int Comp = Existing->compare(Body); + if (Comp == 0) + error(Twine("LTO: unexpected duplicate symbol: ") + Name); + if (Comp < 0) + Sym->Body = Body; + } +} + +void SymbolTable::addCombinedLTOObjects() { + if (BitcodeFiles.empty()) + return; + + // Diagnose any undefined symbols early, but do not resolve weak externals, + // as resolution breaks the invariant that each Symbol points to a unique + // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly. + reportRemainingUndefines(/*Resolve=*/false); + + // Create an object file and add it to the symbol table by replacing any + // DefinedBitcode symbols with the definitions in the object file. + LTOCodeGenerator CG(getGlobalContext()); + CG.setOptLevel(Config->LTOOptLevel); + std::vector Objs = createLTOObjects(&CG); + + for (ObjectFile *Obj : Objs) + addCombinedLTOObject(Obj); + + size_t NumBitcodeFiles = BitcodeFiles.size(); + run(); + if (BitcodeFiles.size() != NumBitcodeFiles) + error("LTO: late loaded symbol created new bitcode reference"); +} + +// Combine and compile bitcode files and then return the result +// as a vector of regular COFF object files. +std::vector SymbolTable::createLTOObjects(LTOCodeGenerator *CG) { + // All symbols referenced by non-bitcode objects must be preserved. + for (ObjectFile *File : ObjectFiles) + for (SymbolBody *Body : File->getSymbols()) + if (auto *S = dyn_cast(Body->repl())) + CG->addMustPreserveSymbol(S->getName()); + + // Likewise for bitcode symbols which we initially resolved to non-bitcode. + for (BitcodeFile *File : BitcodeFiles) + for (SymbolBody *Body : File->getSymbols()) + if (isa(Body) && !isa(Body->repl())) + CG->addMustPreserveSymbol(Body->getName()); + + // Likewise for other symbols that must be preserved. + for (Undefined *U : Config->GCRoot) { + if (auto *S = dyn_cast(U->repl())) + CG->addMustPreserveSymbol(S->getName()); + else if (auto *S = dyn_cast_or_null(U->getWeakAlias())) + CG->addMustPreserveSymbol(S->getName()); + } + + CG->setModule(BitcodeFiles[0]->takeModule()); + for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I) + CG->addModule(BitcodeFiles[I]->takeModule().get()); + + bool DisableVerify = true; +#ifdef NDEBUG + DisableVerify = false; +#endif + if (!CG->optimize(DisableVerify, false, false, false)) + error(""); // optimize() should have emitted any error message. + + Objs.resize(Config->LTOJobs); + // Use std::list to avoid invalidation of pointers in OSPtrs. + std::list OSs; + std::vector OSPtrs; + for (SmallVector &Obj : Objs) { + OSs.emplace_back(Obj); + OSPtrs.push_back(&OSs.back()); + } + + if (!CG->compileOptimized(OSPtrs)) + error(""); // compileOptimized() should have emitted any error message. + + std::vector ObjFiles; + for (SmallVector &Obj : Objs) { + auto *ObjFile = new ObjectFile( + MemoryBufferRef(StringRef(Obj.data(), Obj.size()), "")); + Files.emplace_back(ObjFile); + ObjectFiles.push_back(ObjFile); + ObjFile->parse(); + ObjFiles.push_back(ObjFile); + } + + return ObjFiles; +} + +} // namespace coff +} // namespace lld diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h new file mode 100644 index 00000000000..ce305bfa874 --- /dev/null +++ b/COFF/SymbolTable.h @@ -0,0 +1,125 @@ +//===- SymbolTable.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_SYMBOL_TABLE_H +#define LLD_COFF_SYMBOL_TABLE_H + +#include "InputFiles.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" + +#ifdef _MSC_VER +// depends on for __uncaught_exception. +#include +#endif + +#include + +namespace llvm { +struct LTOCodeGenerator; +} + +namespace lld { +namespace coff { + +class Chunk; +class Defined; +class Lazy; +class SymbolBody; +struct Symbol; + +// SymbolTable is a bucket of all known symbols, including defined, +// undefined, or lazy symbols (the last one is symbols in archive +// files whose archive members are not yet loaded). +// +// We put all symbols of all files to a SymbolTable, and the +// SymbolTable selects the "best" symbols if there are name +// conflicts. For example, obviously, a defined symbol is better than +// an undefined symbol. Or, if there's a conflict between a lazy and a +// undefined, it'll read an archive member to read a real definition +// to replace the lazy symbol. The logic is implemented in resolve(). +class SymbolTable { +public: + void addFile(std::unique_ptr File); + std::vector> &getFiles() { return Files; } + void step(); + void run(); + bool queueEmpty(); + + // Print an error message on undefined symbols. If Resolve is true, try to + // resolve any undefined symbols and update the symbol table accordingly. + void reportRemainingUndefines(bool Resolve); + + // Returns a list of chunks of selected symbols. + std::vector getChunks(); + + // Returns a symbol for a given name. Returns a nullptr if not found. + Symbol *find(StringRef Name); + Symbol *findUnderscore(StringRef Name); + + // Occasionally we have to resolve an undefined symbol to its + // mangled symbol. This function tries to find a mangled name + // for U from the symbol table, and if found, set the symbol as + // a weak alias for U. + void mangleMaybe(Undefined *U); + StringRef findMangle(StringRef Name); + + // Print a layout map to OS. + void printMap(llvm::raw_ostream &OS); + + // Build a set of COFF objects representing the combined contents of + // BitcodeFiles and add them to the symbol table. Called after all files are + // added and before the writer writes results to a file. + void addCombinedLTOObjects(); + + // The writer needs to handle DLL import libraries specially in + // order to create the import descriptor table. + std::vector ImportFiles; + + // The writer needs to infer the machine type from the object files. + std::vector ObjectFiles; + + // Creates an Undefined symbol for a given name. + Undefined *addUndefined(StringRef Name); + DefinedRelative *addRelative(StringRef Name, uint64_t VA); + DefinedAbsolute *addAbsolute(StringRef Name, uint64_t VA); + + // A list of chunks which to be added to .rdata. + std::vector LocalImportChunks; + +private: + void readArchives(); + void readObjects(); + + void addSymbol(SymbolBody *New); + void addLazy(Lazy *New, std::vector *Accum); + Symbol *insert(SymbolBody *New); + StringRef findByPrefix(StringRef Prefix); + + void addMemberFile(Lazy *Body); + void addCombinedLTOObject(ObjectFile *Obj); + std::vector createLTOObjects(llvm::LTOCodeGenerator *CG); + + llvm::DenseMap Symtab; + + std::vector> Files; + std::vector> ArchiveQueue; + std::vector> ObjectQueue; + + std::vector BitcodeFiles; + std::vector> Objs; + llvm::BumpPtrAllocator Alloc; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp new file mode 100644 index 00000000000..d732d76cfb0 --- /dev/null +++ b/COFF/Symbols.cpp @@ -0,0 +1,243 @@ +//===- Symbols.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::object; +using llvm::sys::fs::identify_magic; +using llvm::sys::fs::file_magic; + +namespace lld { +namespace coff { + +StringRef SymbolBody::getName() { + // DefinedCOFF names are read lazily for a performance reason. + // Non-external symbol names are never used by the linker except for logging + // or debugging. Their internal references are resolved not by name but by + // symbol index. And because they are not external, no one can refer them by + // name. Object files contain lots of non-external symbols, and creating + // StringRefs for them (which involves lots of strlen() on the string table) + // is a waste of time. + if (Name.empty()) { + auto *D = cast(this); + D->File->getCOFFObj()->getSymbolName(D->Sym, Name); + } + return Name; +} + +// Returns 1, 0 or -1 if this symbol should take precedence +// over the Other, tie or lose, respectively. +int SymbolBody::compare(SymbolBody *Other) { + Kind LK = kind(), RK = Other->kind(); + + // Normalize so that the smaller kind is on the left. + if (LK > RK) + return -Other->compare(this); + + // First handle comparisons between two different kinds. + if (LK != RK) { + if (RK > LastDefinedKind) { + if (LK == LazyKind && cast(Other)->WeakAlias) + return -1; + + // The LHS is either defined or lazy and so it wins. + assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!"); + return 1; + } + + // Bitcode has special complexities. + if (RK == DefinedBitcodeKind) { + auto *RHS = cast(Other); + + switch (LK) { + case DefinedCommonKind: + return 1; + + case DefinedRegularKind: + // As an approximation, regular symbols win over bitcode symbols, + // but we definitely have a conflict if the regular symbol is not + // replaceable and neither is the bitcode symbol. We do not + // replicate the rest of the symbol resolution logic here; symbol + // resolution will be done accurately after lowering bitcode symbols + // to regular symbols in addCombinedLTOObject(). + if (cast(this)->isCOMDAT() || RHS->IsReplaceable) + return 1; + + // Fallthrough to the default of a tie otherwise. + default: + return 0; + } + } + + // Either of the object file kind will trump a higher kind. + if (LK <= LastDefinedCOFFKind) + return 1; + + // The remaining kind pairs are ties amongst defined symbols. + return 0; + } + + // Now handle the case where the kinds are the same. + switch (LK) { + case DefinedRegularKind: { + auto *LHS = cast(this); + auto *RHS = cast(Other); + if (LHS->isCOMDAT() && RHS->isCOMDAT()) + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + return 0; + } + + case DefinedCommonKind: { + auto *LHS = cast(this); + auto *RHS = cast(Other); + if (LHS->getSize() == RHS->getSize()) + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + return LHS->getSize() > RHS->getSize() ? 1 : -1; + } + + case DefinedBitcodeKind: { + auto *LHS = cast(this); + auto *RHS = cast(Other); + // If both are non-replaceable, we have a tie. + if (!LHS->IsReplaceable && !RHS->IsReplaceable) + return 0; + + // Non-replaceable symbols win, but even two replaceable symboles don't + // tie. If both symbols are replaceable, choice is arbitrary. + if (RHS->IsReplaceable && LHS->IsReplaceable) + return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; + return LHS->IsReplaceable ? -1 : 1; + } + + case LazyKind: { + // Don't tie, pick the earliest. + auto *LHS = cast(this); + auto *RHS = cast(Other); + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + } + + case UndefinedKind: { + auto *LHS = cast(this); + auto *RHS = cast(Other); + // Tie if both undefined symbols have different weak aliases. + if (LHS->WeakAlias && RHS->WeakAlias) { + if (LHS->WeakAlias->getName() != RHS->WeakAlias->getName()) + return 0; + return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; + } + return LHS->WeakAlias ? 1 : -1; + } + + case DefinedLocalImportKind: + case DefinedImportThunkKind: + case DefinedImportDataKind: + case DefinedAbsoluteKind: + case DefinedRelativeKind: + // These all simply tie. + return 0; + } + llvm_unreachable("unknown symbol kind"); +} + +std::string SymbolBody::getDebugName() { + std::string N = getName().str(); + if (auto *D = dyn_cast(this)) { + N += " "; + N += D->File->getShortName(); + } else if (auto *D = dyn_cast(this)) { + N += " "; + N += D->File->getShortName(); + } + return N; +} + +uint64_t Defined::getFileOff() { + switch (kind()) { + case DefinedImportDataKind: + return cast(this)->getFileOff(); + case DefinedImportThunkKind: + return cast(this)->getFileOff(); + case DefinedLocalImportKind: + return cast(this)->getFileOff(); + case DefinedCommonKind: + return cast(this)->getFileOff(); + case DefinedRegularKind: + return cast(this)->getFileOff(); + + case DefinedBitcodeKind: + llvm_unreachable("There is no file offset for a bitcode symbol."); + case DefinedAbsoluteKind: + llvm_unreachable("Cannot get a file offset for an absolute symbol."); + case DefinedRelativeKind: + llvm_unreachable("Cannot get a file offset for a relative symbol."); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get a file offset for an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + +COFFSymbolRef DefinedCOFF::getCOFFSymbol() { + size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize(); + if (SymSize == sizeof(coff_symbol16)) + return COFFSymbolRef(reinterpret_cast(Sym)); + assert(SymSize == sizeof(coff_symbol32)); + return COFFSymbolRef(reinterpret_cast(Sym)); +} + +DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine) + : Defined(DefinedImportThunkKind, Name) { + switch (Machine) { + case AMD64: Data.reset(new ImportThunkChunkX64(S)); return; + case I386: Data.reset(new ImportThunkChunkX86(S)); return; + case ARMNT: Data.reset(new ImportThunkChunkARM(S)); return; + default: llvm_unreachable("unknown machine type"); + } +} + +std::unique_ptr Lazy::getMember() { + MemoryBufferRef MBRef = File->getMember(&Sym); + + // getMember returns an empty buffer if the member was already + // read from the library. + if (MBRef.getBuffer().empty()) + return std::unique_ptr(nullptr); + + file_magic Magic = identify_magic(MBRef.getBuffer()); + if (Magic == file_magic::coff_import_library) + return std::unique_ptr(new ImportFile(MBRef)); + + std::unique_ptr Obj; + if (Magic == file_magic::coff_object) + Obj.reset(new ObjectFile(MBRef)); + else if (Magic == file_magic::bitcode) + Obj.reset(new BitcodeFile(MBRef)); + else + error(Twine(File->getName()) + ": unknown file type"); + + Obj->setParentName(File->getName()); + return Obj; +} + +Defined *Undefined::getWeakAlias() { + // A weak alias may be a weak alias to another symbol, so check recursively. + for (SymbolBody *A = WeakAlias; A; A = cast(A)->WeakAlias) + if (auto *D = dyn_cast(A->repl())) + return D; + return nullptr; +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Symbols.h b/COFF/Symbols.h new file mode 100644 index 00000000000..7059fbc8bb1 --- /dev/null +++ b/COFF/Symbols.h @@ -0,0 +1,407 @@ +//===- Symbols.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_SYMBOLS_H +#define LLD_COFF_SYMBOLS_H + +#include "Chunks.h" +#include "Config.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include +#include +#include + +namespace lld { +namespace coff { + +using llvm::object::Archive; +using llvm::object::COFFSymbolRef; +using llvm::object::coff_import_header; +using llvm::object::coff_symbol_generic; + +class ArchiveFile; +class BitcodeFile; +class InputFile; +class ObjectFile; +class SymbolBody; + +// A real symbol object, SymbolBody, is usually accessed indirectly +// through a Symbol. There's always one Symbol for each symbol name. +// The resolver updates SymbolBody pointers as it resolves symbols. +struct Symbol { + explicit Symbol(SymbolBody *P) : Body(P) {} + SymbolBody *Body; +}; + +// The base class for real symbol classes. +class SymbolBody { +public: + enum Kind { + // The order of these is significant. We start with the regular defined + // symbols as those are the most prevelant and the zero tag is the cheapest + // to set. Among the defined kinds, the lower the kind is preferred over + // the higher kind when testing wether one symbol should take precedence + // over another. + DefinedRegularKind = 0, + DefinedCommonKind, + DefinedLocalImportKind, + DefinedImportThunkKind, + DefinedImportDataKind, + DefinedAbsoluteKind, + DefinedRelativeKind, + DefinedBitcodeKind, + + UndefinedKind, + LazyKind, + + LastDefinedCOFFKind = DefinedCommonKind, + LastDefinedKind = DefinedBitcodeKind, + }; + + Kind kind() const { return static_cast(SymbolKind); } + + // Returns true if this is an external symbol. + bool isExternal() { return IsExternal; } + + // Returns the symbol name. + StringRef getName(); + + // A SymbolBody has a backreference to a Symbol. Originally they are + // doubly-linked. A backreference will never change. But the pointer + // in the Symbol may be mutated by the resolver. If you have a + // pointer P to a SymbolBody and are not sure whether the resolver + // has chosen the object among other objects having the same name, + // you can access P->Backref->Body to get the resolver's result. + void setBackref(Symbol *P) { Backref = P; } + SymbolBody *repl() { return Backref ? Backref->Body : this; } + + // Decides which symbol should "win" in the symbol table, this or + // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if + // they are duplicate (conflicting) symbols. + int compare(SymbolBody *Other); + + // Returns a name of this symbol including source file name. + // Used only for debugging and logging. + std::string getDebugName(); + +protected: + explicit SymbolBody(Kind K, StringRef N = "") + : SymbolKind(K), IsExternal(true), IsCOMDAT(false), + IsReplaceable(false), Name(N) {} + + const unsigned SymbolKind : 8; + unsigned IsExternal : 1; + + // This bit is used by the \c DefinedRegular subclass. + unsigned IsCOMDAT : 1; + + // This bit is used by the \c DefinedBitcode subclass. + unsigned IsReplaceable : 1; + + StringRef Name; + Symbol *Backref = nullptr; +}; + +// The base class for any defined symbols, including absolute symbols, +// etc. +class Defined : public SymbolBody { +public: + Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {} + + static bool classof(const SymbolBody *S) { + return S->kind() <= LastDefinedKind; + } + + // Returns the RVA (relative virtual address) of this symbol. The + // writer sets and uses RVAs. + uint64_t getRVA(); + + // Returns the file offset of this symbol in the final executable. + // The writer uses this information to apply relocations. + uint64_t getFileOff(); + + // Returns the RVA relative to the beginning of the output section. + // Used to implement SECREL relocation type. + uint64_t getSecrel(); + + // Returns the output section index. + // Used to implement SECTION relocation type. + uint64_t getSectionIndex(); + + // Returns true if this symbol points to an executable (e.g. .text) section. + // Used to implement ARM relocations. + bool isExecutable(); +}; + +// Symbols defined via a COFF object file. +class DefinedCOFF : public Defined { + friend SymbolBody; +public: + DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S) + : Defined(K), File(F), Sym(S.getGeneric()) {} + + static bool classof(const SymbolBody *S) { + return S->kind() <= LastDefinedCOFFKind; + } + + int getFileIndex() { return File->Index; } + + COFFSymbolRef getCOFFSymbol(); + +protected: + ObjectFile *File; + const coff_symbol_generic *Sym; +}; + +// Regular defined symbols read from object file symbol tables. +class DefinedRegular : public DefinedCOFF { +public: + DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C) + : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) { + IsExternal = S.isExternal(); + IsCOMDAT = C->isCOMDAT(); + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedRegularKind; + } + + uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; } + bool isCOMDAT() { return IsCOMDAT; } + SectionChunk *getChunk() { return *Data; } + uint32_t getValue() { return Sym->Value; } + +private: + SectionChunk **Data; +}; + +class DefinedCommon : public DefinedCOFF { +public: + DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C) + : DefinedCOFF(DefinedCommonKind, F, S), Data(C) { + IsExternal = S.isExternal(); + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedCommonKind; + } + + uint64_t getRVA() { return Data->getRVA(); } + +private: + friend SymbolBody; + uint64_t getSize() { return Sym->Value; } + CommonChunk *Data; +}; + +// Absolute symbols. +class DefinedAbsolute : public Defined { +public: + DefinedAbsolute(StringRef N, COFFSymbolRef S) + : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { + IsExternal = S.isExternal(); + } + + DefinedAbsolute(StringRef N, uint64_t V) + : Defined(DefinedAbsoluteKind, N), VA(V) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedAbsoluteKind; + } + + uint64_t getRVA() { return VA - Config->ImageBase; } + void setVA(uint64_t V) { VA = V; } + +private: + uint64_t VA; +}; + +// This is a kind of absolute symbol but relative to the image base. +// Unlike absolute symbols, relocations referring this kind of symbols +// are subject of the base relocation. This type is used rarely -- +// mainly for __ImageBase. +class DefinedRelative : public Defined { +public: + explicit DefinedRelative(StringRef Name, uint64_t V = 0) + : Defined(DefinedRelativeKind, Name), RVA(V) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedRelativeKind; + } + + uint64_t getRVA() { return RVA; } + void setRVA(uint64_t V) { RVA = V; } + +private: + uint64_t RVA; +}; + +// This class represents a symbol defined in an archive file. It is +// created from an archive file header, and it knows how to load an +// object file from an archive to replace itself with a defined +// symbol. If the resolver finds both Undefined and Lazy for +// the same name, it will ask the Lazy to load a file. +class Lazy : public SymbolBody { +public: + Lazy(ArchiveFile *F, const Archive::Symbol S) + : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {} + + static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } + + // Returns an object file for this symbol, or a nullptr if the file + // was already returned. + std::unique_ptr getMember(); + + int getFileIndex() { return File->Index; } + +private: + ArchiveFile *File; + const Archive::Symbol Sym; +}; + +// Undefined symbols. +class Undefined : public SymbolBody { +public: + explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == UndefinedKind; + } + + // An undefined symbol can have a fallback symbol which gives an + // undefined symbol a second chance if it would remain undefined. + // If it remains undefined, it'll be replaced with whatever the + // Alias pointer points to. + SymbolBody *WeakAlias = nullptr; + + // If this symbol is external weak, try to resolve it to a defined + // symbol by searching the chain of fallback symbols. Returns the symbol if + // successful, otherwise returns null. + Defined *getWeakAlias(); +}; + +// Windows-specific classes. + +// This class represents a symbol imported from a DLL. This has two +// names for internal use and external use. The former is used for +// name resolution, and the latter is used for the import descriptor +// table in an output. The former has "__imp_" prefix. +class DefinedImportData : public Defined { +public: + DefinedImportData(StringRef D, StringRef N, StringRef E, + const coff_import_header *H) + : Defined(DefinedImportDataKind, N), DLLName(D), ExternalName(E), Hdr(H) { + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedImportDataKind; + } + + uint64_t getRVA() { return Location->getRVA(); } + StringRef getDLLName() { return DLLName; } + StringRef getExternalName() { return ExternalName; } + void setLocation(Chunk *AddressTable) { Location = AddressTable; } + uint16_t getOrdinal() { return Hdr->OrdinalHint; } + +private: + StringRef DLLName; + StringRef ExternalName; + const coff_import_header *Hdr; + Chunk *Location = nullptr; +}; + +// This class represents a symbol for a jump table entry which jumps +// to a function in a DLL. Linker are supposed to create such symbols +// without "__imp_" prefix for all function symbols exported from +// DLLs, so that you can call DLL functions as regular functions with +// a regular name. A function pointer is given as a DefinedImportData. +class DefinedImportThunk : public Defined { +public: + DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedImportThunkKind; + } + + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data.get(); } + +private: + std::unique_ptr Data; +}; + +// If you have a symbol "__imp_foo" in your object file, a symbol name +// "foo" becomes automatically available as a pointer to "__imp_foo". +// This class is for such automatically-created symbols. +// Yes, this is an odd feature. We didn't intend to implement that. +// This is here just for compatibility with MSVC. +class DefinedLocalImport : public Defined { +public: + DefinedLocalImport(StringRef N, Defined *S) + : Defined(DefinedLocalImportKind, N), Data(S) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedLocalImportKind; + } + + uint64_t getRVA() { return Data.getRVA(); } + Chunk *getChunk() { return &Data; } + +private: + LocalImportChunk Data; +}; + +class DefinedBitcode : public Defined { + friend SymbolBody; +public: + DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) + : Defined(DefinedBitcodeKind, N), File(F) { + this->IsReplaceable = IsReplaceable; + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedBitcodeKind; + } + +private: + BitcodeFile *File; +}; + +inline uint64_t Defined::getRVA() { + switch (kind()) { + case DefinedAbsoluteKind: + return cast(this)->getRVA(); + case DefinedRelativeKind: + return cast(this)->getRVA(); + case DefinedImportDataKind: + return cast(this)->getRVA(); + case DefinedImportThunkKind: + return cast(this)->getRVA(); + case DefinedLocalImportKind: + return cast(this)->getRVA(); + case DefinedCommonKind: + return cast(this)->getRVA(); + case DefinedRegularKind: + return cast(this)->getRVA(); + case DefinedBitcodeKind: + llvm_unreachable("There is no address for a bitcode symbol."); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get the address for an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp new file mode 100644 index 00000000000..a74b316b87a --- /dev/null +++ b/COFF/Writer.cpp @@ -0,0 +1,765 @@ +//===- Writer.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "DLL.h" +#include "Error.h" +#include "InputFiles.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "Writer.h" +#include "lld/Core/Parallel.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm::support; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::coff; + +static const int PageSize = 4096; +static const int SectorSize = 512; +static const int DOSStubSize = 64; +static const int NumberfOfDataDirectory = 16; + +namespace { +// The writer writes a SymbolTable result to a file. +class Writer { +public: + Writer(SymbolTable *T) : Symtab(T) {} + void run(); + +private: + void createSections(); + void createMiscChunks(); + void createImportTables(); + void createExportTable(); + void assignAddresses(); + void removeEmptySections(); + void createSymbolAndStringTable(); + void openFile(StringRef OutputPath); + template void writeHeader(); + void fixSafeSEHSymbols(); + void writeSections(); + void sortExceptionTable(); + void applyRelocations(); + + llvm::Optional createSymbol(Defined *D); + size_t addEntryToStringTable(StringRef Str); + + OutputSection *findSection(StringRef Name); + OutputSection *createSection(StringRef Name); + void addBaserels(OutputSection *Dest); + void addBaserelBlocks(OutputSection *Dest, std::vector &V); + + uint32_t getSizeOfInitializedData(); + std::map> binImports(); + + SymbolTable *Symtab; + std::unique_ptr Buffer; + llvm::SpecificBumpPtrAllocator CAlloc; + llvm::SpecificBumpPtrAllocator BAlloc; + std::vector OutputSections; + std::vector Strtab; + std::vector OutputSymtab; + IdataContents Idata; + DelayLoadContents DelayIdata; + EdataContents Edata; + std::unique_ptr SEHTable; + + uint64_t FileSize; + uint32_t PointerToSymbolTable = 0; + uint64_t SizeOfImage; + uint64_t SizeOfHeaders; + + std::vector> Chunks; +}; +} // anonymous namespace + +namespace lld { +namespace coff { + +void writeResult(SymbolTable *T) { Writer(T).run(); } + +// OutputSection represents a section in an output file. It's a +// container of chunks. OutputSection and Chunk are 1:N relationship. +// Chunks cannot belong to more than one OutputSections. The writer +// creates multiple OutputSections and assign them unique, +// non-overlapping file offsets and RVAs. +class OutputSection { +public: + OutputSection(StringRef N) : Name(N), Header({}) {} + void setRVA(uint64_t); + void setFileOffset(uint64_t); + void addChunk(Chunk *C); + StringRef getName() { return Name; } + std::vector &getChunks() { return Chunks; } + void addPermissions(uint32_t C); + uint32_t getPermissions() { return Header.Characteristics & PermMask; } + uint32_t getCharacteristics() { return Header.Characteristics; } + uint64_t getRVA() { return Header.VirtualAddress; } + uint64_t getFileOff() { return Header.PointerToRawData; } + void writeHeaderTo(uint8_t *Buf); + + // Returns the size of this section in an executable memory image. + // This may be smaller than the raw size (the raw size is multiple + // of disk sector size, so there may be padding at end), or may be + // larger (if that's the case, the loader reserves spaces after end + // of raw data). + uint64_t getVirtualSize() { return Header.VirtualSize; } + + // Returns the size of the section in the output file. + uint64_t getRawSize() { return Header.SizeOfRawData; } + + // Set offset into the string table storing this section name. + // Used only when the name is longer than 8 bytes. + void setStringTableOff(uint32_t V) { StringTableOff = V; } + + // N.B. The section index is one based. + uint32_t SectionIndex = 0; + +private: + StringRef Name; + coff_section Header; + uint32_t StringTableOff = 0; + std::vector Chunks; +}; + +void OutputSection::setRVA(uint64_t RVA) { + Header.VirtualAddress = RVA; + for (Chunk *C : Chunks) + C->setRVA(C->getRVA() + RVA); +} + +void OutputSection::setFileOffset(uint64_t Off) { + // If a section has no actual data (i.e. BSS section), we want to + // set 0 to its PointerToRawData. Otherwise the output is rejected + // by the loader. + if (Header.SizeOfRawData == 0) + return; + Header.PointerToRawData = Off; +} + +void OutputSection::addChunk(Chunk *C) { + Chunks.push_back(C); + C->setOutputSection(this); + uint64_t Off = Header.VirtualSize; + Off = RoundUpToAlignment(Off, C->getAlign()); + C->setRVA(Off); + C->setOutputSectionOff(Off); + Off += C->getSize(); + Header.VirtualSize = Off; + if (C->hasData()) + Header.SizeOfRawData = RoundUpToAlignment(Off, SectorSize); +} + +void OutputSection::addPermissions(uint32_t C) { + Header.Characteristics |= C & PermMask; +} + +// Write the section header to a given buffer. +void OutputSection::writeHeaderTo(uint8_t *Buf) { + auto *Hdr = reinterpret_cast(Buf); + *Hdr = Header; + if (StringTableOff) { + // If name is too long, write offset into the string table as a name. + sprintf(Hdr->Name, "/%d", StringTableOff); + } else { + assert(!Config->Debug || Name.size() <= COFF::NameSize); + strncpy(Hdr->Name, Name.data(), + std::min(Name.size(), (size_t)COFF::NameSize)); + } +} + +uint64_t Defined::getSecrel() { + if (auto *D = dyn_cast(this)) + return getRVA() - D->getChunk()->getOutputSection()->getRVA(); + error("SECREL relocation points to a non-regular symbol"); +} + +uint64_t Defined::getSectionIndex() { + if (auto *D = dyn_cast(this)) + return D->getChunk()->getOutputSection()->SectionIndex; + error("SECTION relocation points to a non-regular symbol"); +} + +bool Defined::isExecutable() { + const auto X = IMAGE_SCN_MEM_EXECUTE; + if (auto *D = dyn_cast(this)) + return D->getChunk()->getOutputSection()->getPermissions() & X; + return isa(this); +} + +} // namespace coff +} // namespace lld + +// The main function of the writer. +void Writer::run() { + createSections(); + createMiscChunks(); + createImportTables(); + createExportTable(); + if (Config->Relocatable) + createSection(".reloc"); + assignAddresses(); + removeEmptySections(); + createSymbolAndStringTable(); + openFile(Config->OutputFile); + if (Config->is64()) { + writeHeader(); + } else { + writeHeader(); + } + fixSafeSEHSymbols(); + writeSections(); + sortExceptionTable(); + error(Buffer->commit(), "Failed to write the output file"); +} + +static StringRef getOutputSection(StringRef Name) { + StringRef S = Name.split('$').first; + auto It = Config->Merge.find(S); + if (It == Config->Merge.end()) + return S; + return It->second; +} + +// Create output section objects and add them to OutputSections. +void Writer::createSections() { + // First, bin chunks by name. + std::map> Map; + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (SC && !SC->isLive()) { + if (Config->Verbose) + SC->printDiscardedMessage(); + continue; + } + Map[C->getSectionName()].push_back(C); + } + + // Then create an OutputSection for each section. + // '$' and all following characters in input section names are + // discarded when determining output section. So, .text$foo + // contributes to .text, for example. See PE/COFF spec 3.2. + SmallDenseMap Sections; + for (auto Pair : Map) { + StringRef Name = getOutputSection(Pair.first); + OutputSection *&Sec = Sections[Name]; + if (!Sec) { + Sec = new (CAlloc.Allocate()) OutputSection(Name); + OutputSections.push_back(Sec); + } + std::vector &Chunks = Pair.second; + for (Chunk *C : Chunks) { + Sec->addChunk(C); + Sec->addPermissions(C->getPermissions()); + } + } +} + +void Writer::createMiscChunks() { + // Create thunks for locally-dllimported symbols. + if (!Symtab->LocalImportChunks.empty()) { + OutputSection *Sec = createSection(".rdata"); + for (Chunk *C : Symtab->LocalImportChunks) + Sec->addChunk(C); + } + + // Create SEH table. x86-only. + if (Config->Machine != I386) + return; + std::set Handlers; + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { + if (!File->SEHCompat) + return; + for (SymbolBody *B : File->SEHandlers) + Handlers.insert(cast(B->repl())); + } + SEHTable.reset(new SEHTableChunk(Handlers)); + createSection(".rdata")->addChunk(SEHTable.get()); +} + +// Create .idata section for the DLL-imported symbol table. +// The format of this section is inherently Windows-specific. +// IdataContents class abstracted away the details for us, +// so we just let it create chunks and add them to the section. +void Writer::createImportTables() { + if (Symtab->ImportFiles.empty()) + return; + + // Initialize DLLOrder so that import entries are ordered in + // the same order as in the command line. (That affects DLL + // initialization order, and this ordering is MSVC-compatible.) + for (ImportFile *File : Symtab->ImportFiles) { + std::string DLL = StringRef(File->DLLName).lower(); + if (Config->DLLOrder.count(DLL) == 0) + Config->DLLOrder[DLL] = Config->DLLOrder.size(); + } + + OutputSection *Text = createSection(".text"); + for (ImportFile *File : Symtab->ImportFiles) { + if (DefinedImportThunk *Thunk = File->ThunkSym) + Text->addChunk(Thunk->getChunk()); + if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { + DelayIdata.add(File->ImpSym); + } else { + Idata.add(File->ImpSym); + } + } + if (!Idata.empty()) { + OutputSection *Sec = createSection(".idata"); + for (Chunk *C : Idata.getChunks()) + Sec->addChunk(C); + } + if (!DelayIdata.empty()) { + Defined *Helper = cast(Config->DelayLoadHelper->repl()); + DelayIdata.create(Helper); + OutputSection *Sec = createSection(".didat"); + for (Chunk *C : DelayIdata.getChunks()) + Sec->addChunk(C); + Sec = createSection(".data"); + for (Chunk *C : DelayIdata.getDataChunks()) + Sec->addChunk(C); + Sec = createSection(".text"); + for (std::unique_ptr &C : DelayIdata.getCodeChunks()) + Sec->addChunk(C.get()); + } +} + +void Writer::createExportTable() { + if (Config->Exports.empty()) + return; + OutputSection *Sec = createSection(".edata"); + for (std::unique_ptr &C : Edata.Chunks) + Sec->addChunk(C.get()); +} + +// The Windows loader doesn't seem to like empty sections, +// so we remove them if any. +void Writer::removeEmptySections() { + auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; + OutputSections.erase( + std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), + OutputSections.end()); + uint32_t Idx = 1; + for (OutputSection *Sec : OutputSections) + Sec->SectionIndex = Idx++; +} + +size_t Writer::addEntryToStringTable(StringRef Str) { + assert(Str.size() > COFF::NameSize); + size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field + Strtab.insert(Strtab.end(), Str.begin(), Str.end()); + Strtab.push_back('\0'); + return OffsetOfEntry; +} + +Optional Writer::createSymbol(Defined *Def) { + if (auto *D = dyn_cast(Def)) + if (!D->getChunk()->isLive()) + return None; + + coff_symbol16 Sym; + StringRef Name = Def->getName(); + if (Name.size() > COFF::NameSize) { + Sym.Name.Offset.Zeroes = 0; + Sym.Name.Offset.Offset = addEntryToStringTable(Name); + } else { + memset(Sym.Name.ShortName, 0, COFF::NameSize); + memcpy(Sym.Name.ShortName, Name.data(), Name.size()); + } + + if (auto *D = dyn_cast(Def)) { + COFFSymbolRef Ref = D->getCOFFSymbol(); + Sym.Type = Ref.getType(); + Sym.StorageClass = Ref.getStorageClass(); + } else { + Sym.Type = IMAGE_SYM_TYPE_NULL; + Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; + } + Sym.NumberOfAuxSymbols = 0; + + switch (Def->kind()) { + case SymbolBody::DefinedAbsoluteKind: + case SymbolBody::DefinedRelativeKind: + Sym.Value = Def->getRVA(); + Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + break; + default: { + uint64_t RVA = Def->getRVA(); + OutputSection *Sec = nullptr; + for (OutputSection *S : OutputSections) { + if (S->getRVA() > RVA) + break; + Sec = S; + } + Sym.Value = RVA - Sec->getRVA(); + Sym.SectionNumber = Sec->SectionIndex; + break; + } + } + return Sym; +} + +void Writer::createSymbolAndStringTable() { + if (!Config->Debug || !Config->WriteSymtab) + return; + + // Name field in the section table is 8 byte long. Longer names need + // to be written to the string table. First, construct string table. + for (OutputSection *Sec : OutputSections) { + StringRef Name = Sec->getName(); + if (Name.size() <= COFF::NameSize) + continue; + Sec->setStringTableOff(addEntryToStringTable(Name)); + } + + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) + for (SymbolBody *B : File->getSymbols()) + if (auto *D = dyn_cast(B)) + if (Optional Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); + + for (ImportFile *File : Symtab->ImportFiles) + for (SymbolBody *B : File->getSymbols()) + if (Optional Sym = createSymbol(cast(B))) + OutputSymtab.push_back(*Sym); + + OutputSection *LastSection = OutputSections.back(); + // We position the symbol table to be adjacent to the end of the last section. + uint64_t FileOff = + LastSection->getFileOff() + + RoundUpToAlignment(LastSection->getRawSize(), SectorSize); + if (!OutputSymtab.empty()) { + PointerToSymbolTable = FileOff; + FileOff += OutputSymtab.size() * sizeof(coff_symbol16); + } + if (!Strtab.empty()) + FileOff += Strtab.size() + 4; + FileSize = RoundUpToAlignment(FileOff, SectorSize); +} + +// Visits all sections to assign incremental, non-overlapping RVAs and +// file offsets. +void Writer::assignAddresses() { + SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + + sizeof(data_directory) * NumberfOfDataDirectory + + sizeof(coff_section) * OutputSections.size(); + SizeOfHeaders += + Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); + SizeOfHeaders = RoundUpToAlignment(SizeOfHeaders, SectorSize); + uint64_t RVA = 0x1000; // The first page is kept unmapped. + FileSize = SizeOfHeaders; + // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because + // the loader cannot handle holes. + std::stable_partition( + OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { + return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; + }); + for (OutputSection *Sec : OutputSections) { + if (Sec->getName() == ".reloc") + addBaserels(Sec); + Sec->setRVA(RVA); + Sec->setFileOffset(FileSize); + RVA += RoundUpToAlignment(Sec->getVirtualSize(), PageSize); + FileSize += RoundUpToAlignment(Sec->getRawSize(), SectorSize); + } + SizeOfImage = SizeOfHeaders + RoundUpToAlignment(RVA - 0x1000, PageSize); +} + +template void Writer::writeHeader() { + // Write DOS stub + uint8_t *Buf = Buffer->getBufferStart(); + auto *DOS = reinterpret_cast(Buf); + Buf += DOSStubSize; + DOS->Magic[0] = 'M'; + DOS->Magic[1] = 'Z'; + DOS->AddressOfRelocationTable = sizeof(dos_header); + DOS->AddressOfNewExeHeader = DOSStubSize; + + // Write PE magic + memcpy(Buf, PEMagic, sizeof(PEMagic)); + Buf += sizeof(PEMagic); + + // Write COFF header + auto *COFF = reinterpret_cast(Buf); + Buf += sizeof(*COFF); + COFF->Machine = Config->Machine; + COFF->NumberOfSections = OutputSections.size(); + COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; + if (Config->LargeAddressAware) + COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (!Config->is64()) + COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; + if (Config->DLL) + COFF->Characteristics |= IMAGE_FILE_DLL; + if (!Config->Relocatable) + COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; + COFF->SizeOfOptionalHeader = + sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; + + // Write PE header + auto *PE = reinterpret_cast(Buf); + Buf += sizeof(*PE); + PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + PE->ImageBase = Config->ImageBase; + PE->SectionAlignment = PageSize; + PE->FileAlignment = SectorSize; + PE->MajorImageVersion = Config->MajorImageVersion; + PE->MinorImageVersion = Config->MinorImageVersion; + PE->MajorOperatingSystemVersion = Config->MajorOSVersion; + PE->MinorOperatingSystemVersion = Config->MinorOSVersion; + PE->MajorSubsystemVersion = Config->MajorOSVersion; + PE->MinorSubsystemVersion = Config->MinorOSVersion; + PE->Subsystem = Config->Subsystem; + PE->SizeOfImage = SizeOfImage; + PE->SizeOfHeaders = SizeOfHeaders; + if (!Config->NoEntry) { + Defined *Entry = cast(Config->Entry->repl()); + PE->AddressOfEntryPoint = Entry->getRVA(); + // Pointer to thumb code must have the LSB set, so adjust it. + if (Config->Machine == ARMNT) + PE->AddressOfEntryPoint |= 1; + } + PE->SizeOfStackReserve = Config->StackReserve; + PE->SizeOfStackCommit = Config->StackCommit; + PE->SizeOfHeapReserve = Config->HeapReserve; + PE->SizeOfHeapCommit = Config->HeapCommit; + if (Config->DynamicBase) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + if (Config->HighEntropyVA) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; + if (!Config->AllowBind) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (Config->NxCompat) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + if (!Config->AllowIsolation) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; + if (Config->TerminalServerAware) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; + PE->NumberOfRvaAndSize = NumberfOfDataDirectory; + if (OutputSection *Text = findSection(".text")) { + PE->BaseOfCode = Text->getRVA(); + PE->SizeOfCode = Text->getRawSize(); + } + PE->SizeOfInitializedData = getSizeOfInitializedData(); + + // Write data directory + auto *Dir = reinterpret_cast(Buf); + Buf += sizeof(*Dir) * NumberfOfDataDirectory; + if (OutputSection *Sec = findSection(".edata")) { + Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); + } + if (!Idata.empty()) { + Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); + Dir[IMPORT_TABLE].Size = Idata.getDirSize(); + Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); + Dir[IAT].Size = Idata.getIATSize(); + } + if (!DelayIdata.empty()) { + Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = + DelayIdata.getDirRVA(); + Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); + } + if (OutputSection *Sec = findSection(".rsrc")) { + Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); + } + if (OutputSection *Sec = findSection(".reloc")) { + Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); + } + if (OutputSection *Sec = findSection(".pdata")) { + Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); + } + if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { + if (Defined *B = dyn_cast(Sym->Body)) { + Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[TLS_TABLE].Size = 40; + } + } + if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { + if (Defined *B = dyn_cast(Sym->Body)) { + Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[LOAD_CONFIG_TABLE].Size = Config->is64() ? 112 : 64; + } + } + + // Write section table + for (OutputSection *Sec : OutputSections) { + Sec->writeHeaderTo(Buf); + Buf += sizeof(coff_section); + } + + if (OutputSymtab.empty()) + return; + + COFF->PointerToSymbolTable = PointerToSymbolTable; + uint32_t NumberOfSymbols = OutputSymtab.size(); + COFF->NumberOfSymbols = NumberOfSymbols; + auto *SymbolTable = reinterpret_cast( + Buffer->getBufferStart() + COFF->PointerToSymbolTable); + for (size_t I = 0; I != NumberOfSymbols; ++I) + SymbolTable[I] = OutputSymtab[I]; + // Create the string table, it follows immediately after the symbol table. + // The first 4 bytes is length including itself. + Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); + write32le(Buf, Strtab.size() + 4); + memcpy(Buf + 4, Strtab.data(), Strtab.size()); +} + +void Writer::openFile(StringRef Path) { + ErrorOr> BufferOrErr = + FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable); + error(BufferOrErr, Twine("failed to open ") + Path); + Buffer = std::move(*BufferOrErr); +} + +void Writer::fixSafeSEHSymbols() { + if (!SEHTable) + return; + Config->SEHTable->setRVA(SEHTable->getRVA()); + Config->SEHCount->setVA(SEHTable->getSize() / 4); +} + +// Write section contents to a mmap'ed file. +void Writer::writeSections() { + uint8_t *Buf = Buffer->getBufferStart(); + for (OutputSection *Sec : OutputSections) { + uint8_t *SecBuf = Buf + Sec->getFileOff(); + // Fill gaps between functions in .text with INT3 instructions + // instead of leaving as NUL bytes (which can be interpreted as + // ADD instructions). + if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) + memset(SecBuf, 0xCC, Sec->getRawSize()); + parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(), + [&](Chunk *C) { C->writeTo(SecBuf); }); + } +} + +// Sort .pdata section contents according to PE/COFF spec 5.5. +void Writer::sortExceptionTable() { + OutputSection *Sec = findSection(".pdata"); + if (!Sec) + return; + // We assume .pdata contains function table entries only. + uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); + uint8_t *End = Begin + Sec->getVirtualSize(); + if (Config->Machine == AMD64) { + struct Entry { ulittle32_t Begin, End, Unwind; }; + parallel_sort( + (Entry *)Begin, (Entry *)End, + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + return; + } + if (Config->Machine == ARMNT) { + struct Entry { ulittle32_t Begin, Unwind; }; + parallel_sort( + (Entry *)Begin, (Entry *)End, + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + return; + } + errs() << "warning: don't know how to handle .pdata.\n"; +} + +OutputSection *Writer::findSection(StringRef Name) { + for (OutputSection *Sec : OutputSections) + if (Sec->getName() == Name) + return Sec; + return nullptr; +} + +uint32_t Writer::getSizeOfInitializedData() { + uint32_t Res = 0; + for (OutputSection *S : OutputSections) + if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) + Res += S->getRawSize(); + return Res; +} + +// Returns an existing section or create a new one if not found. +OutputSection *Writer::createSection(StringRef Name) { + if (auto *Sec = findSection(Name)) + return Sec; + const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; + const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const auto CODE = IMAGE_SCN_CNT_CODE; + const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; + const auto R = IMAGE_SCN_MEM_READ; + const auto W = IMAGE_SCN_MEM_WRITE; + const auto X = IMAGE_SCN_MEM_EXECUTE; + uint32_t Perms = StringSwitch(Name) + .Case(".bss", BSS | R | W) + .Case(".data", DATA | R | W) + .Case(".didat", DATA | R) + .Case(".edata", DATA | R) + .Case(".idata", DATA | R) + .Case(".rdata", DATA | R) + .Case(".reloc", DATA | DISCARDABLE | R) + .Case(".text", CODE | R | X) + .Default(0); + if (!Perms) + llvm_unreachable("unknown section name"); + auto Sec = new (CAlloc.Allocate()) OutputSection(Name); + Sec->addPermissions(Perms); + OutputSections.push_back(Sec); + return Sec; +} + +// Dest is .reloc section. Add contents to that section. +void Writer::addBaserels(OutputSection *Dest) { + std::vector V; + for (OutputSection *Sec : OutputSections) { + if (Sec == Dest) + continue; + // Collect all locations for base relocations. + for (Chunk *C : Sec->getChunks()) + C->getBaserels(&V); + // Add the addresses to .reloc section. + if (!V.empty()) + addBaserelBlocks(Dest, V); + V.clear(); + } +} + +// Add addresses to .reloc section. Note that addresses are grouped by page. +void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { + const uint32_t Mask = ~uint32_t(PageSize - 1); + uint32_t Page = V[0].RVA & Mask; + size_t I = 0, J = 1; + for (size_t E = V.size(); J < E; ++J) { + uint32_t P = V[J].RVA & Mask; + if (P == Page) + continue; + BaserelChunk *Buf = BAlloc.Allocate(); + Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J)); + I = J; + Page = P; + } + if (I == J) + return; + BaserelChunk *Buf = BAlloc.Allocate(); + Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J)); +} diff --git a/COFF/Writer.h b/COFF/Writer.h new file mode 100644 index 00000000000..0473315ae50 --- /dev/null +++ b/COFF/Writer.h @@ -0,0 +1,26 @@ +//===- Writer.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_WRITER_H +#define LLD_COFF_WRITER_H + +#include + +namespace lld { +namespace coff { + +class Chunk; +class OutputSection; + +void writeResult(SymbolTable *T); + +} +} + +#endif diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt new file mode 100644 index 00000000000..763275e30ca --- /dev/null +++ b/ELF/CMakeLists.txt @@ -0,0 +1,26 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(ELFOptionsTableGen) + +add_llvm_library(lldELF2 + Driver.cpp + DriverUtils.cpp + Error.cpp + InputFiles.cpp + InputSection.cpp + LinkerScript.cpp + MarkLive.cpp + OutputSections.cpp + SymbolTable.cpp + Symbols.cpp + Target.cpp + Writer.cpp + + LINK_COMPONENTS + Object + Option + MC + Support + ) + +add_dependencies(lldELF2 ELFOptionsTableGen) diff --git a/ELF/Config.h b/ELF/Config.h new file mode 100644 index 00000000000..7b820f18b8c --- /dev/null +++ b/ELF/Config.h @@ -0,0 +1,84 @@ +//===- Config.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_CONFIG_H +#define LLD_ELF_CONFIG_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ELF.h" + +#include + +namespace lld { +namespace elf2 { + +class InputFile; +class SymbolBody; + +enum ELFKind { + ELFNoneKind, + ELF32LEKind, + ELF32BEKind, + ELF64LEKind, + ELF64BEKind +}; + +struct Configuration { + SymbolBody *EntrySym = nullptr; + SymbolBody *MipsGpDisp = nullptr; + InputFile *FirstElf = nullptr; + llvm::StringRef DynamicLinker; + llvm::StringRef Entry; + llvm::StringRef Emulation; + llvm::StringRef Fini; + llvm::StringRef Init; + llvm::StringRef OutputFile; + llvm::StringRef SoName; + llvm::StringRef Sysroot; + std::string RPath; + llvm::MapVector> OutputSections; + std::vector SearchPaths; + std::vector Undefined; + bool AllowMultipleDefinition; + bool AsNeeded = false; + bool Bsymbolic; + bool DiscardAll; + bool DiscardLocals; + bool DiscardNone; + bool EnableNewDtags; + bool ExportDynamic; + bool GcSections; + bool GnuHash = false; + bool Mips64EL = false; + bool NoInhibitExec; + bool NoUndefined; + bool PrintGcSections; + bool Shared; + bool Static = false; + bool StripAll; + bool SysvHash = true; + bool Verbose; + bool ZExecStack; + bool ZNodelete; + bool ZNow; + bool ZOrigin; + bool ZRelro; + ELFKind EKind = ELFNoneKind; + uint16_t EMachine = llvm::ELF::EM_NONE; + uint64_t EntryAddr = -1; + unsigned Optimize = 0; +}; + +extern Configuration *Config; + +} // namespace elf2 +} // namespace lld + +#endif diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp new file mode 100644 index 00000000000..6d881373b30 --- /dev/null +++ b/ELF/Driver.cpp @@ -0,0 +1,299 @@ +//===- Driver.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Driver.h" +#include "Config.h" +#include "Error.h" +#include "InputFiles.h" +#include "SymbolTable.h" +#include "Target.h" +#include "Writer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; + +using namespace lld; +using namespace lld::elf2; + +Configuration *lld::elf2::Config; +LinkerDriver *lld::elf2::Driver; + +void lld::elf2::link(ArrayRef Args) { + Configuration C; + LinkerDriver D; + Config = &C; + Driver = &D; + Driver->main(Args.slice(1)); +} + +static std::pair parseEmulation(StringRef S) { + if (S == "elf32btsmip") + return {ELF32BEKind, EM_MIPS}; + if (S == "elf32ltsmip") + return {ELF32LEKind, EM_MIPS}; + if (S == "elf32ppc") + return {ELF32BEKind, EM_PPC}; + if (S == "elf64ppc") + return {ELF64BEKind, EM_PPC64}; + if (S == "elf_i386") + return {ELF32LEKind, EM_386}; + if (S == "elf_x86_64") + return {ELF64LEKind, EM_X86_64}; + if (S == "aarch64linux") + return {ELF64LEKind, EM_AARCH64}; + if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") + error("Windows targets are not supported on the ELF frontend: " + S); + error("Unknown emulation: " + S); +} + +// Opens and parses a file. Path has to be resolved already. +// Newly created memory buffers are owned by this driver. +void LinkerDriver::addFile(StringRef Path) { + using namespace llvm::sys::fs; + if (Config->Verbose) + llvm::outs() << Path << "\n"; + auto MBOrErr = MemoryBuffer::getFile(Path); + error(MBOrErr, "cannot open " + Path); + std::unique_ptr &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take MB ownership + + switch (identify_magic(MBRef.getBuffer())) { + case file_magic::unknown: + readLinkerScript(&Alloc, MBRef); + return; + case file_magic::archive: + if (WholeArchive) { + auto File = make_unique(MBRef); + for (MemoryBufferRef &MB : File->getMembers()) + Files.push_back(createELFFile(MB)); + OwningArchives.emplace_back(std::move(File)); + return; + } + Files.push_back(make_unique(MBRef)); + return; + case file_magic::elf_shared_object: + Files.push_back(createELFFile(MBRef)); + return; + default: + Files.push_back(createELFFile(MBRef)); + } +} + +static StringRef +getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { + if (auto *Arg = Args.getLastArg(Key)) + return Arg->getValue(); + return Default; +} + +static bool hasZOption(opt::InputArgList &Args, StringRef Key) { + for (auto *Arg : Args.filtered(OPT_z)) + if (Key == Arg->getValue()) + return true; + return false; +} + +void LinkerDriver::main(ArrayRef ArgsArr) { + initSymbols(); + + opt::InputArgList Args = parseArgs(&Alloc, ArgsArr); + createFiles(Args); + + // Traditional linkers can generate re-linkable object files instead + // of executables or DSOs. We don't support that since the feature + // does not seem to provide more value than the static archiver. + if (Args.hasArg(OPT_relocatable)) + error("-r option is not supported. Use 'ar' command instead."); + + switch (Config->EKind) { + case ELF32LEKind: + link(Args); + return; + case ELF32BEKind: + link(Args); + return; + case ELF64LEKind: + link(Args); + return; + case ELF64BEKind: + link(Args); + return; + default: + error("-m or at least a .o file required"); + } +} + +void LinkerDriver::createFiles(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_L)) + Config->SearchPaths.push_back(Arg->getValue()); + + std::vector RPaths; + for (auto *Arg : Args.filtered(OPT_rpath)) + RPaths.push_back(Arg->getValue()); + if (!RPaths.empty()) + Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); + + if (auto *Arg = Args.getLastArg(OPT_m)) { + StringRef S = Arg->getValue(); + std::pair P = parseEmulation(S); + Config->EKind = P.first; + Config->EMachine = P.second; + Config->Emulation = S; + } + + Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); + Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); + Config->DiscardAll = Args.hasArg(OPT_discard_all); + Config->DiscardLocals = Args.hasArg(OPT_discard_locals); + Config->DiscardNone = Args.hasArg(OPT_discard_none); + Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); + Config->ExportDynamic = Args.hasArg(OPT_export_dynamic); + Config->GcSections = Args.hasArg(OPT_gc_sections); + Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); + Config->NoUndefined = Args.hasArg(OPT_no_undefined); + Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); + Config->Shared = Args.hasArg(OPT_shared); + Config->StripAll = Args.hasArg(OPT_strip_all); + Config->Verbose = Args.hasArg(OPT_verbose); + + Config->DynamicLinker = getString(Args, OPT_dynamic_linker); + Config->Entry = getString(Args, OPT_entry); + Config->Fini = getString(Args, OPT_fini, "_fini"); + Config->Init = getString(Args, OPT_init, "_init"); + Config->OutputFile = getString(Args, OPT_o); + Config->SoName = getString(Args, OPT_soname); + Config->Sysroot = getString(Args, OPT_sysroot); + + Config->ZExecStack = hasZOption(Args, "execstack"); + Config->ZNodelete = hasZOption(Args, "nodelete"); + Config->ZNow = hasZOption(Args, "now"); + Config->ZOrigin = hasZOption(Args, "origin"); + Config->ZRelro = !hasZOption(Args, "norelro"); + + if (auto *Arg = Args.getLastArg(OPT_O)) { + StringRef Val = Arg->getValue(); + if (Val.getAsInteger(10, Config->Optimize)) + error("Invalid optimization level"); + } + + if (auto *Arg = Args.getLastArg(OPT_hash_style)) { + StringRef S = Arg->getValue(); + if (S == "gnu") { + Config->GnuHash = true; + Config->SysvHash = false; + } else if (S == "both") { + Config->GnuHash = true; + } else if (S != "sysv") + error("Unknown hash style: " + S); + } + + for (auto *Arg : Args.filtered(OPT_undefined)) + Config->Undefined.push_back(Arg->getValue()); + + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_l: + addFile(searchLibrary(Arg->getValue())); + break; + case OPT_INPUT: + case OPT_script: + addFile(Arg->getValue()); + break; + case OPT_as_needed: + Config->AsNeeded = true; + break; + case OPT_no_as_needed: + Config->AsNeeded = false; + break; + case OPT_Bstatic: + Config->Static = true; + break; + case OPT_Bdynamic: + Config->Static = false; + break; + case OPT_whole_archive: + WholeArchive = true; + break; + case OPT_no_whole_archive: + WholeArchive = false; + break; + } + } + + if (Files.empty()) + error("no input files."); + + if (Config->GnuHash && Config->EMachine == EM_MIPS) + error("The .gnu.hash section is not compatible with the MIPS target."); +} + +template void LinkerDriver::link(opt::InputArgList &Args) { + SymbolTable Symtab; + Target.reset(createTarget()); + + if (!Config->Shared) { + // Add entry symbol. + if (Config->Entry.empty()) + Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; + + // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol + // is magical and is used to produce a R_386_GOTPC relocation. + // The R_386_GOTPC relocation value doesn't actually depend on the + // symbol value, so it could use an index of STN_UNDEF which, according + // to the spec, means the symbol value is 0. + // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in + // the object file. + // The situation is even stranger on x86_64 where the assembly doesn't + // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as + // an undefined symbol in the .o files. + // Given that the symbol is effectively unused, we just create a dummy + // hidden one to avoid the undefined symbol error. + Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); + } + + if (!Config->Entry.empty()) { + // Set either EntryAddr (if S is a number) or EntrySym (otherwise). + StringRef S = Config->Entry; + if (S.getAsInteger(0, Config->EntryAddr)) + Config->EntrySym = Symtab.addUndefined(S); + } + + if (Config->EMachine == EM_MIPS) { + // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between + // start of function and gp pointer into GOT. + Config->MipsGpDisp = Symtab.addIgnored("_gp_disp"); + + // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer + // so that it points to an absolute address which is relative to GOT. + // See "Global Data Symbols" in Chapter 6 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Symtab.addAbsolute("_gp", ElfSym::MipsGp); + } + + for (std::unique_ptr &F : Files) + Symtab.addFile(std::move(F)); + + for (StringRef S : Config->Undefined) + Symtab.addUndefinedOpt(S); + + if (Config->OutputFile.empty()) + Config->OutputFile = "a.out"; + + // Write the result to the file. + Symtab.scanShlibUndefined(); + if (Config->GcSections) + markLive(&Symtab); + writeResult(&Symtab); +} diff --git a/ELF/Driver.h b/ELF/Driver.h new file mode 100644 index 00000000000..2641155104d --- /dev/null +++ b/ELF/Driver.h @@ -0,0 +1,67 @@ +//===- Driver.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_DRIVER_H +#define LLD_ELF_DRIVER_H + +#include "SymbolTable.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" + +namespace lld { +namespace elf2 { + +extern class LinkerDriver *Driver; + +// Entry point of the ELF linker. +void link(ArrayRef Args); + +class LinkerDriver { +public: + void main(ArrayRef Args); + void createFiles(llvm::opt::InputArgList &Args); + template void link(llvm::opt::InputArgList &Args); + + void addFile(StringRef Path); + +private: + template