From fb911942f1434f3d1750f83f25f5e42c80e60638 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 24 Mar 2015 21:31:36 +0000 Subject: Vendor import of lld trunk r233088: https://llvm.org/svn/llvm-project/lld/trunk@233088 --- .arcconfig | 4 + .clang-format | 1 + .gitignore | 24 + CMakeLists.txt | 98 + LICENSE.TXT | 62 + Makefile | 86 + README.md | 10 + cmake/modules/FindVTune.cmake | 31 + docs/C++11.rst | 9 + docs/CMakeLists.txt | 8 + docs/Driver.rst | 79 + docs/Makefile | 155 ++ docs/README.txt | 12 + docs/Readers.rst | 172 ++ docs/_static/favicon.ico | Bin 0 -> 1150 bytes docs/_templates/indexsidebar.html | 4 + docs/_templates/layout.html | 12 + docs/conf.py | 254 ++ docs/design.rst | 500 ++++ docs/development.rst | 48 + docs/getting_started.rst | 106 + docs/hello.png | Bin 0 -> 27616 bytes docs/index.rst | 88 + docs/llvm-theme/layout.html | 22 + docs/llvm-theme/static/contents.png | Bin 0 -> 202 bytes docs/llvm-theme/static/llvm.css | 345 +++ docs/llvm-theme/static/logo.png | Bin 0 -> 9865 bytes docs/llvm-theme/static/navigation.png | Bin 0 -> 218 bytes docs/llvm-theme/theme.conf | 4 + docs/make.bat | 190 ++ docs/open_projects.rst | 17 + docs/sphinx_intro.rst | 147 ++ docs/windows_support.rst | 118 + include/Makefile | 4 + include/lld/Config/Makefile | 32 + include/lld/Config/Version.h | 51 + include/lld/Config/Version.inc.in | 5 + include/lld/Core/AbsoluteAtom.h | 43 + include/lld/Core/Alias.h | 102 + include/lld/Core/ArchiveLibraryFile.h | 60 + include/lld/Core/Atom.h | 76 + include/lld/Core/DefinedAtom.h | 368 +++ include/lld/Core/Error.h | 82 + include/lld/Core/File.h | 324 +++ include/lld/Core/Instrumentation.h | 132 + include/lld/Core/LLVM.h | 75 + include/lld/Core/LinkingContext.h | 364 +++ include/lld/Core/Node.h | 78 + include/lld/Core/Parallel.h | 309 +++ include/lld/Core/Pass.h | 46 + include/lld/Core/PassManager.h | 46 + include/lld/Core/Reader.h | 169 ++ include/lld/Core/Reference.h | 125 + include/lld/Core/Resolver.h | 119 + include/lld/Core/STDExtras.h | 29 + include/lld/Core/SharedLibraryAtom.h | 53 + include/lld/Core/SharedLibraryFile.h | 65 + include/lld/Core/Simple.h | 341 +++ include/lld/Core/SymbolTable.h | 117 + include/lld/Core/TODO.txt | 17 + include/lld/Core/UndefinedAtom.h | 74 + include/lld/Core/Writer.h | 52 + include/lld/Core/range.h | 738 ++++++ include/lld/Driver/Driver.h | 162 ++ include/lld/Driver/WinLinkModuleDef.h | 200 ++ include/lld/Makefile | 44 + include/lld/ReaderWriter/AtomLayout.h | 39 + include/lld/ReaderWriter/CoreLinkingContext.h | 47 + include/lld/ReaderWriter/ELFLinkingContext.h | 362 +++ include/lld/ReaderWriter/ELFTargets.h | 38 + include/lld/ReaderWriter/LinkerScript.h | 1396 +++++++++++ include/lld/ReaderWriter/MachOLinkingContext.h | 369 +++ include/lld/ReaderWriter/PECOFFLinkingContext.h | 463 ++++ .../lld/ReaderWriter/RelocationHelperFunctions.h | 57 + include/lld/ReaderWriter/YamlContext.h | 46 + lib/CMakeLists.txt | 4 + lib/Config/CMakeLists.txt | 5 + lib/Config/Makefile | 13 + lib/Config/Version.cpp | 66 + lib/Core/CMakeLists.txt | 12 + lib/Core/DefinedAtom.cpp | 96 + lib/Core/Error.cpp | 151 ++ lib/Core/File.cpp | 30 + lib/Core/LinkingContext.cpp | 104 + lib/Core/Makefile | 13 + lib/Core/Reader.cpp | 117 + lib/Core/Resolver.cpp | 516 ++++ lib/Core/SymbolTable.cpp | 390 +++ lib/Core/TODO.txt | 18 + lib/Core/Writer.cpp | 23 + lib/Driver/CMakeLists.txt | 43 + lib/Driver/CoreDriver.cpp | 172 ++ lib/Driver/CoreOptions.td | 15 + lib/Driver/DarwinLdDriver.cpp | 832 +++++++ lib/Driver/DarwinLdOptions.td | 187 ++ lib/Driver/Driver.cpp | 130 + lib/Driver/GnuLdDriver.cpp | 760 ++++++ lib/Driver/GnuLdOptions.td | 323 +++ lib/Driver/Makefile | 38 + lib/Driver/TODO.rst | 101 + lib/Driver/UniversalDriver.cpp | 218 ++ lib/Driver/UniversalDriverOptions.td | 19 + lib/Driver/WinLinkDriver.cpp | 1371 +++++++++++ lib/Driver/WinLinkModuleDef.cpp | 295 +++ lib/Driver/WinLinkOptions.td | 120 + lib/Makefile | 16 + lib/ReaderWriter/CMakeLists.txt | 20 + lib/ReaderWriter/CoreLinkingContext.cpp | 171 ++ .../ELF/AArch64/AArch64DynamicLibraryWriter.h | 69 + lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h | 41 + lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h | 62 + .../ELF/AArch64/AArch64ExecutableWriter.h | 68 + .../ELF/AArch64/AArch64LinkingContext.cpp | 33 + .../ELF/AArch64/AArch64LinkingContext.h | 95 + .../ELF/AArch64/AArch64RelocationHandler.cpp | 440 ++++ .../ELF/AArch64/AArch64RelocationHandler.h | 33 + .../ELF/AArch64/AArch64RelocationPass.cpp | 527 ++++ .../ELF/AArch64/AArch64RelocationPass.h | 32 + .../ELF/AArch64/AArch64TargetHandler.cpp | 52 + .../ELF/AArch64/AArch64TargetHandler.h | 64 + lib/ReaderWriter/ELF/AArch64/CMakeLists.txt | 12 + lib/ReaderWriter/ELF/AArch64/Makefile | 15 + lib/ReaderWriter/ELF/AArch64/TODO.rst | 15 + lib/ReaderWriter/ELF/ARM/ARMELFFile.h | 97 + lib/ReaderWriter/ELF/ARM/ARMELFReader.h | 62 + lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h | 121 + lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp | 34 + lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h | 36 + lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 500 ++++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h | 38 + lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp | 373 +++ lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h | 31 + lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h | 46 + lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp | 44 + lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 88 + lib/ReaderWriter/ELF/ARM/CMakeLists.txt | 12 + lib/ReaderWriter/ELF/ARM/Makefile | 15 + lib/ReaderWriter/ELF/ARM/TODO.rst | 20 + lib/ReaderWriter/ELF/Atoms.h | 849 +++++++ lib/ReaderWriter/ELF/CMakeLists.txt | 19 + lib/ReaderWriter/ELF/Chunk.h | 102 + lib/ReaderWriter/ELF/CreateELF.h | 118 + lib/ReaderWriter/ELF/DefaultLayout.h | 1050 ++++++++ lib/ReaderWriter/ELF/DefaultTargetHandler.h | 38 + lib/ReaderWriter/ELF/DynamicFile.h | 123 + lib/ReaderWriter/ELF/DynamicLibraryWriter.h | 96 + lib/ReaderWriter/ELF/ELFFile.h | 1179 +++++++++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp | 259 ++ lib/ReaderWriter/ELF/ELFReader.h | 102 + lib/ReaderWriter/ELF/ExecutableWriter.h | 182 ++ lib/ReaderWriter/ELF/HeaderChunks.h | 364 +++ lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt | 11 + .../ELF/Hexagon/HexagonDynamicLibraryWriter.h | 79 + lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h | 170 ++ lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h | 62 + lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h | 61 + lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h | 601 +++++ .../ELF/Hexagon/HexagonExecutableAtoms.h | 29 + .../ELF/Hexagon/HexagonExecutableWriter.h | 86 + .../ELF/Hexagon/HexagonLinkingContext.cpp | 25 + .../ELF/Hexagon/HexagonLinkingContext.h | 69 + .../ELF/Hexagon/HexagonRelocationFunctions.h | 49 + .../ELF/Hexagon/HexagonRelocationHandler.cpp | 350 +++ .../ELF/Hexagon/HexagonRelocationHandler.h | 35 + .../ELF/Hexagon/HexagonSectionChunks.h | 86 + .../ELF/Hexagon/HexagonTargetHandler.cpp | 334 +++ .../ELF/Hexagon/HexagonTargetHandler.h | 143 ++ lib/ReaderWriter/ELF/Hexagon/Makefile | 16 + lib/ReaderWriter/ELF/Layout.h | 59 + lib/ReaderWriter/ELF/Makefile | 18 + lib/ReaderWriter/ELF/Mips/CMakeLists.txt | 14 + lib/ReaderWriter/ELF/Mips/Makefile | 15 + lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp | 73 + lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h | 25 + .../ELF/Mips/MipsDynamicLibraryWriter.h | 101 + lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h | 115 + lib/ReaderWriter/ELF/Mips/MipsELFFile.h | 331 +++ lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp | 149 ++ lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h | 36 + lib/ReaderWriter/ELF/Mips/MipsELFReader.h | 93 + lib/ReaderWriter/ELF/Mips/MipsELFWriters.h | 82 + lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h | 154 ++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp | 115 + lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h | 68 + .../ELF/Mips/MipsRelocationHandler.cpp | 606 +++++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h | 31 + lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | 1070 ++++++++ lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h | 25 + lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h | 170 ++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp | 35 + lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h | 257 ++ lib/ReaderWriter/ELF/OrderPass.h | 30 + lib/ReaderWriter/ELF/OutputELFWriter.h | 615 +++++ lib/ReaderWriter/ELF/Reader.cpp | 43 + lib/ReaderWriter/ELF/SectionChunks.h | 1498 ++++++++++++ lib/ReaderWriter/ELF/SegmentChunks.h | 686 ++++++ lib/ReaderWriter/ELF/TODO.txt | 18 + lib/ReaderWriter/ELF/TargetHandler.h | 86 + lib/ReaderWriter/ELF/TargetLayout.h | 28 + lib/ReaderWriter/ELF/Writer.cpp | 23 + lib/ReaderWriter/ELF/Writer.h | 38 + lib/ReaderWriter/ELF/X86/CMakeLists.txt | 11 + lib/ReaderWriter/ELF/X86/Makefile | 15 + lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h | 67 + lib/ReaderWriter/ELF/X86/X86ELFFile.h | 41 + lib/ReaderWriter/ELF/X86/X86ELFReader.h | 62 + lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h | 57 + lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp | 28 + lib/ReaderWriter/ELF/X86/X86LinkingContext.h | 42 + lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp | 57 + lib/ReaderWriter/ELF/X86/X86RelocationHandler.h | 29 + lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp | 53 + lib/ReaderWriter/ELF/X86/X86TargetHandler.h | 63 + lib/ReaderWriter/ELF/X86_64/CMakeLists.txt | 16 + .../ELF/X86_64/ExampleSubTarget/CMakeLists.txt | 11 + .../ExampleSubTarget/ExampleLinkingContext.cpp | 35 + .../ExampleSubTarget/ExampleLinkingContext.h | 31 + .../ExampleSubTarget/ExampleTargetHandler.cpp | 23 + .../X86_64/ExampleSubTarget/ExampleTargetHandler.h | 31 + .../ELF/X86_64/ExampleSubTarget/Makefile | 15 + lib/ReaderWriter/ELF/X86_64/Makefile | 19 + lib/ReaderWriter/ELF/X86_64/TODO.rst | 46 + .../ELF/X86_64/X86_64DynamicLibraryWriter.h | 63 + 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 | 61 + .../ELF/X86_64/X86_64LinkingContext.cpp | 38 + lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h | 100 + .../ELF/X86_64/X86_64RelocationHandler.cpp | 151 ++ .../ELF/X86_64/X86_64RelocationHandler.h | 39 + .../ELF/X86_64/X86_64RelocationPass.cpp | 513 ++++ lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h | 32 + .../ELF/X86_64/X86_64TargetHandler.cpp | 52 + lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h | 69 + lib/ReaderWriter/FileArchive.cpp | 293 +++ lib/ReaderWriter/LinkerScript.cpp | 2564 ++++++++++++++++++++ lib/ReaderWriter/MachO/ArchHandler.cpp | 172 ++ lib/ReaderWriter/MachO/ArchHandler.h | 300 +++ lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 1524 ++++++++++++ lib/ReaderWriter/MachO/ArchHandler_arm64.cpp | 822 +++++++ lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 642 +++++ lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 723 ++++++ lib/ReaderWriter/MachO/Atoms.h | 181 ++ lib/ReaderWriter/MachO/CMakeLists.txt | 26 + lib/ReaderWriter/MachO/CompactUnwindPass.cpp | 530 ++++ lib/ReaderWriter/MachO/ExecutableAtoms.hpp | 136 ++ lib/ReaderWriter/MachO/File.h | 327 +++ lib/ReaderWriter/MachO/GOTPass.cpp | 185 ++ lib/ReaderWriter/MachO/LayoutPass.cpp | 482 ++++ lib/ReaderWriter/MachO/LayoutPass.h | 97 + lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 969 ++++++++ lib/ReaderWriter/MachO/MachONormalizedFile.h | 323 +++ .../MachO/MachONormalizedFileBinaryReader.cpp | 582 +++++ .../MachO/MachONormalizedFileBinaryUtils.h | 177 ++ .../MachO/MachONormalizedFileBinaryWriter.cpp | 1346 ++++++++++ .../MachO/MachONormalizedFileFromAtoms.cpp | 1238 ++++++++++ .../MachO/MachONormalizedFileToAtoms.cpp | 911 +++++++ lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp | 802 ++++++ lib/ReaderWriter/MachO/MachOPasses.h | 28 + lib/ReaderWriter/MachO/Makefile | 14 + lib/ReaderWriter/MachO/ShimPass.cpp | 129 + lib/ReaderWriter/MachO/StubsPass.cpp | 373 +++ lib/ReaderWriter/MachO/WriterMachO.cpp | 72 + 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 + lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp | 352 +++ lib/ReaderWriter/PECOFF/Pass.cpp | 95 + lib/ReaderWriter/PECOFF/Pass.h | 34 + lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 1140 +++++++++ lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp | 389 +++ lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp | 118 + lib/ReaderWriter/PECOFF/WriterImportLibrary.h | 23 + lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 1417 +++++++++++ lib/ReaderWriter/YAML/CMakeLists.txt | 6 + lib/ReaderWriter/YAML/Makefile | 14 + lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 1358 +++++++++++ test/CMakeLists.txt | 47 + test/Driver/Inputs/libtest.a | 1 + test/Driver/Inputs/usr/lib/i386/libtest.a | 1 + test/Driver/Inputs/usr/lib/libtest.a | 1 + test/Driver/def-lib-search.test | 8 + test/Driver/flavor-option.test | 8 + test/Driver/lib-search.test | 24 + test/Driver/so-whole-archive.test | 63 + test/Driver/trivial-driver.test | 5 + test/Driver/undef-basic.objtxt | 22 + test/LinkerScript/expr-precedence.test | 34 + test/LinkerScript/extern-bad-symbol.test | 22 + test/LinkerScript/extern-empty.test | 19 + test/LinkerScript/extern-valid.test | 29 + test/LinkerScript/incomplete-ternary.test | 25 + test/LinkerScript/libname-err-1.test | 11 + test/LinkerScript/libname-err-2.test | 11 + test/LinkerScript/linker-script-outputformat.test | 12 + test/LinkerScript/linker-script.test | 46 + test/LinkerScript/memory-empty.test | 17 + test/LinkerScript/memory-missing-attrs.test | 32 + test/LinkerScript/memory-missing-length.test | 29 + test/LinkerScript/memory-missing-name.test | 31 + test/LinkerScript/memory-missing-origin.test | 30 + test/LinkerScript/memory-valid.test | 56 + test/LinkerScript/missing-entry-symbol.test | 21 + test/LinkerScript/missing-input-file-name.test | 25 + test/LinkerScript/missing-input-sections.test | 27 + test/LinkerScript/missing-operand.test | 24 + test/LinkerScript/missing-output-section-name.test | 25 + test/LinkerScript/missing-symbol.test | 24 + test/LinkerScript/sections.test | 618 +++++ test/Makefile | 71 + test/Unit/lit.cfg | 23 + test/Unit/lit.site.cfg.in | 25 + test/core/absolute-basic.objtxt | 23 + test/core/absolute-local.objtxt | 25 + test/core/archive-basic.objtxt | 44 + test/core/archive-chain.objtxt | 70 + test/core/archive-tentdef-search.objtxt | 42 + test/core/associates.objtxt | 30 + test/core/auto-hide-coalesce.objtxt | 60 + test/core/code-model-attributes.objtxt | 50 + test/core/constants-coalesce.objtxt | 60 + test/core/cstring-coalesce.objtxt | 41 + test/core/custom-section-coalesce.objtxt | 78 + test/core/custom-section.objtxt | 34 + test/core/dead-strip-attributes.objtxt | 29 + test/core/dead-strip-basic.objtxt | 62 + test/core/dead-strip-globals.objtxt | 60 + test/core/dead-strip-reverse.objtxt | 25 + test/core/error-atom-attribute.objtxt | 19 + test/core/error-atom-content-byte-value.objtxt | 18 + test/core/error-atom-content-bytes.objtxt | 19 + test/core/error-atom-type.objtxt | 19 + .../error-atom-undefined-wrong-attribue.objtxt | 17 + test/core/error-duplicate-absolutes.objtxt | 24 + test/core/error-file-attribute.objtxt | 17 + test/core/error-fixup-attribute.objtxt | 21 + test/core/error-fixup-target.objtxt | 26 + test/core/fixups-addend.objtxt | 50 + test/core/fixups-dup-named.objtxt | 31 + test/core/fixups-named.objtxt | 36 + test/core/fixups-unnamed.objtxt | 40 + test/core/gnulinkonce-rearrange-resolve.objtxt | 79 + test/core/gnulinkonce-remaining-undef.objtxt | 80 + test/core/gnulinkonce-resolve.objtxt | 89 + test/core/gnulinkonce-simple.objtxt | 80 + test/core/inline-coalesce.objtxt | 31 + test/core/multiple-def-error.objtxt | 19 + test/core/permissions.objtxt | 57 + test/core/sectiongroup-deadstrip.objtxt | 88 + test/core/sectiongroup-gnulinkonce-error.objtxt | 64 + test/core/sectiongroup-rearrange-resolve.objtxt | 79 + test/core/sectiongroup-remaining-undef.objtxt | 80 + test/core/sectiongroup-resolve.objtxt | 90 + test/core/sectiongroup-simple.objtxt | 80 + test/core/shared-library-basic.objtxt | 40 + test/core/shared-library-coalesce.objtxt | 84 + test/core/tent-merge.objtxt | 25 + test/core/undef-coalesce-error.objtxt | 47 + test/core/undef-coalesce.objtxt | 42 + test/core/undef-fallback.objtxt | 37 + test/core/undef-weak-coalesce.objtxt | 72 + test/core/weak-coalesce.objtxt | 30 + test/darwin/native-and-mach-o.objtxt | 65 + test/elf/AArch64/Inputs/fn.c | 4 + test/elf/AArch64/Inputs/fn.o | Bin 0 -> 899 bytes test/elf/AArch64/Inputs/initfini-option.c | 12 + test/elf/AArch64/Inputs/initfini-option.o | Bin 0 -> 1552 bytes test/elf/AArch64/Inputs/initfini.c | 13 + test/elf/AArch64/Inputs/initfini.o | Bin 0 -> 2056 bytes test/elf/AArch64/Inputs/main.c | 4 + test/elf/AArch64/Inputs/main.o | Bin 0 -> 1064 bytes test/elf/AArch64/Inputs/no-interp-section.c | 1 + test/elf/AArch64/Inputs/no-interp-section.o | Bin 0 -> 903 bytes test/elf/AArch64/Inputs/zerosizedsection.o | Bin 0 -> 816 bytes test/elf/AArch64/Inputs/zerosizedsection.s | 3 + test/elf/AArch64/defsym.test | 22 + test/elf/AArch64/dontignorezerosize-sections.test | 9 + test/elf/AArch64/dynlib-nointerp-section.test | 5 + test/elf/AArch64/initfini.test | 23 + test/elf/AArch64/rel-abs32-overflow.test | 53 + test/elf/AArch64/rel-abs32.test | 59 + test/elf/AArch64/rel-abs64.test | 59 + test/elf/AArch64/rel-bad.test | 44 + test/elf/ARM/arm-symbols.test | 52 + test/elf/ARM/defsym.test | 51 + test/elf/ARM/entry-point.test | 77 + test/elf/ARM/missing-symbol.test | 39 + test/elf/ARM/rel-abs32.test | 59 + test/elf/ARM/rel-arm-call.test | 60 + test/elf/ARM/rel-arm-jump24-veneer-b.test | 101 + test/elf/ARM/rel-arm-jump24-veneer-bl.test | 100 + test/elf/ARM/rel-arm-jump24.test | 58 + test/elf/ARM/rel-arm-mov.test | 64 + test/elf/ARM/rel-arm-prel31.test | 47 + test/elf/ARM/rel-arm-thm-interwork.test | 123 + test/elf/ARM/rel-rel32.test | 57 + test/elf/ARM/rel-thm-call.test | 61 + test/elf/ARM/rel-thm-jump11.test | 141 ++ test/elf/ARM/rel-thm-jump24-veneer.test | 100 + test/elf/ARM/rel-thm-jump24.test | 59 + test/elf/ARM/rel-thm-mov.test | 70 + test/elf/ARM/rel-tls-ie32.test | 109 + test/elf/ARM/rel-tls-le32.test | 61 + test/elf/ARM/thm-symbols.test | 52 + test/elf/ARM/undef-lazy-symbol.test | 135 ++ test/elf/Hexagon/Inputs/dynobj-data.c | 3 + test/elf/Hexagon/Inputs/dynobj-data.o | Bin 0 -> 916 bytes test/elf/Hexagon/Inputs/dynobj.c | 26 + test/elf/Hexagon/Inputs/dynobj.o | Bin 0 -> 1288 bytes test/elf/Hexagon/Inputs/got-plt-order.c | 6 + test/elf/Hexagon/Inputs/got-plt-order.o | Bin 0 -> 964 bytes test/elf/Hexagon/Inputs/libMaxAlignment.a | Bin 0 -> 1010 bytes test/elf/Hexagon/Inputs/sda-base.o | Bin 0 -> 1469 bytes test/elf/Hexagon/Inputs/sdata1.c | 3 + test/elf/Hexagon/Inputs/sdata1.o | Bin 0 -> 684 bytes test/elf/Hexagon/Inputs/sdata2.c | 6 + test/elf/Hexagon/Inputs/sdata2.o | Bin 0 -> 829 bytes test/elf/Hexagon/Inputs/use-shared.hexagon | Bin 0 -> 872 bytes test/elf/Hexagon/dynlib-data.test | 9 + test/elf/Hexagon/dynlib-gotoff.test | 128 + test/elf/Hexagon/dynlib-hash.test | 9 + test/elf/Hexagon/dynlib-rela.test | 9 + test/elf/Hexagon/dynlib-syms.test | 7 + test/elf/Hexagon/dynlib.test | 36 + test/elf/Hexagon/hexagon-got-plt-order.test | 5 + test/elf/Hexagon/hexagon-plt-setup.test | 12 + test/elf/Hexagon/maxalignment.test | 8 + test/elf/Hexagon/rela-order.test | 9 + test/elf/Hexagon/sda-base.test | 4 + test/elf/Hexagon/zerofillquick-sdata.test | 18 + test/elf/Inputs/abs-test.i386 | Bin 0 -> 504 bytes test/elf/Inputs/bar.o.x86-64 | Bin 0 -> 1240 bytes test/elf/Inputs/branch-test.hexagon | Bin 0 -> 700 bytes test/elf/Inputs/branch-test.ppc | Bin 0 -> 852 bytes test/elf/Inputs/consecutive-weak-defs.o.yaml | 66 + test/elf/Inputs/constants-merge.x86-64 | Bin 0 -> 1232 bytes test/elf/Inputs/constdata.x86-64 | Bin 0 -> 1688 bytes test/elf/Inputs/foo.o.x86-64 | Bin 0 -> 1240 bytes test/elf/Inputs/globalconst.c | 2 + test/elf/Inputs/globalconst.o.x86-64 | Bin 0 -> 1072 bytes test/elf/Inputs/gotpcrel.S | 11 + test/elf/Inputs/gotpcrel.x86-64 | Bin 0 -> 904 bytes test/elf/Inputs/group-cmd-search-1.ls | 1 + test/elf/Inputs/group-cmd-search-2.ls | 1 + test/elf/Inputs/group-cmd-search-3.ls | 1 + test/elf/Inputs/ifunc.S | 21 + test/elf/Inputs/ifunc.cpp | 3 + test/elf/Inputs/ifunc.cpp.x86-64 | Bin 0 -> 1224 bytes test/elf/Inputs/ifunc.x86-64 | Bin 0 -> 912 bytes test/elf/Inputs/init_array.x86-64 | Bin 0 -> 3440 bytes test/elf/Inputs/libfnarchive.a | Bin 0 -> 2656 bytes test/elf/Inputs/libifunc.x86-64.so | Bin 0 -> 2512 bytes test/elf/Inputs/libundef.so | Bin 0 -> 11128 bytes test/elf/Inputs/libweaksym.so | Bin 0 -> 2160 bytes test/elf/Inputs/main-with-global-def.o.yaml | 56 + test/elf/Inputs/mainobj.x86_64 | Bin 0 -> 1360 bytes test/elf/Inputs/object-test.elf-hexagon | Bin 0 -> 1532 bytes test/elf/Inputs/object-test.elf-i386 | Bin 0 -> 1784 bytes test/elf/Inputs/phdr.i386 | Bin 0 -> 17536 bytes test/elf/Inputs/quickdata-sort-test.o.elf-hexagon | Bin 0 -> 1385 bytes .../Inputs/quickdata-sortcommon-test.o.elf-hexagon | Bin 0 -> 1469 bytes test/elf/Inputs/quickdata-test.elf-hexagon | Bin 0 -> 891 bytes test/elf/Inputs/reloc-test.elf-i386 | Bin 0 -> 1076 bytes test/elf/Inputs/reloc-xb.x86 | Bin 0 -> 568 bytes test/elf/Inputs/reloc-xt.x86 | Bin 0 -> 548 bytes test/elf/Inputs/relocs-dynamic.x86-64 | Bin 0 -> 864 bytes test/elf/Inputs/relocs.x86-64 | Bin 0 -> 1536 bytes test/elf/Inputs/responsefile | 1 + test/elf/Inputs/rodata-test.hexagon | Bin 0 -> 669 bytes test/elf/Inputs/rodata-test.i386 | Bin 0 -> 537 bytes test/elf/Inputs/rodata.c | 4 + test/elf/Inputs/rodata.o | Bin 0 -> 1568 bytes test/elf/Inputs/section-test.i386 | Bin 0 -> 717 bytes test/elf/Inputs/shared.c | 16 + test/elf/Inputs/shared.so-x86-64 | Bin 0 -> 7536 bytes test/elf/Inputs/stripped-empty.x86_64 | Bin 0 -> 416 bytes test/elf/Inputs/target-test.hexagon | Bin 0 -> 676 bytes test/elf/Inputs/target-test.ppc | Bin 0 -> 552 bytes test/elf/Inputs/tls.S | 50 + test/elf/Inputs/tls.c | 11 + test/elf/Inputs/tls.x86-64 | Bin 0 -> 1424 bytes test/elf/Inputs/tlsAddr.x86-64 | Bin 0 -> 1752 bytes test/elf/Inputs/tlsaddr.c | 8 + test/elf/Inputs/undef-from-main-so.c | 1 + test/elf/Inputs/undef-from-main.c | 5 + test/elf/Inputs/undef-pc32.o | Bin 0 -> 1248 bytes test/elf/Inputs/undef.o | Bin 0 -> 1264 bytes test/elf/Inputs/undef2-so.o.yaml | 50 + test/elf/Inputs/use-shared-32s.c | 8 + test/elf/Inputs/use-shared-32s.x86-64 | Bin 0 -> 1336 bytes test/elf/Inputs/use-shared.c | 7 + test/elf/Inputs/use-shared.x86-64 | Bin 0 -> 1376 bytes test/elf/Inputs/weaksym.o | Bin 0 -> 840 bytes test/elf/Inputs/writersyms.o | Bin 0 -> 868 bytes test/elf/Inputs/x86-64-relocs.S | 12 + test/elf/Mips/base-address-64.test | 78 + test/elf/Mips/base-address.test | 109 + test/elf/Mips/ctors-order.test | 163 ++ test/elf/Mips/dt-textrel-64.test | 74 + test/elf/Mips/dt-textrel.test | 74 + test/elf/Mips/dynlib-dynamic.test | 110 + test/elf/Mips/dynlib-dynsym-micro.test | 208 ++ test/elf/Mips/dynlib-dynsym.test | 202 ++ test/elf/Mips/dynlib-fileheader-64.test | 72 + test/elf/Mips/dynlib-fileheader-micro-64.test | 75 + test/elf/Mips/dynlib-fileheader-micro.test | 82 + test/elf/Mips/dynlib-fileheader.test | 80 + test/elf/Mips/dynsym-table-1.test | 127 + test/elf/Mips/dynsym-table-2.test | 105 + test/elf/Mips/e-flags-merge-1-64.test | 30 + test/elf/Mips/e-flags-merge-1.test | 56 + test/elf/Mips/e-flags-merge-10.test | 43 + test/elf/Mips/e-flags-merge-11.test | 43 + test/elf/Mips/e-flags-merge-2-64.test | 33 + test/elf/Mips/e-flags-merge-2.test | 35 + test/elf/Mips/e-flags-merge-3-64.test | 130 + test/elf/Mips/e-flags-merge-3.test | 134 + test/elf/Mips/e-flags-merge-4-64.test | 64 + test/elf/Mips/e-flags-merge-4.test | 65 + test/elf/Mips/e-flags-merge-5-64.test | 42 + test/elf/Mips/e-flags-merge-5.test | 42 + test/elf/Mips/e-flags-merge-6-64.test | 79 + test/elf/Mips/e-flags-merge-6.test | 80 + test/elf/Mips/e-flags-merge-7-64.test | 42 + test/elf/Mips/e-flags-merge-7.test | 42 + test/elf/Mips/e-flags-merge-8.test | 65 + test/elf/Mips/e-flags-merge-9.test | 43 + test/elf/Mips/entry-name.test | 26 + test/elf/Mips/exe-dynamic.test | 108 + test/elf/Mips/exe-dynsym-micro.test | 94 + test/elf/Mips/exe-dynsym.test | 91 + test/elf/Mips/exe-fileheader-64.test | 66 + test/elf/Mips/exe-fileheader-micro-64.test | 68 + test/elf/Mips/exe-fileheader-micro.test | 69 + test/elf/Mips/exe-fileheader.test | 105 + test/elf/Mips/exe-got-micro.test | 115 + test/elf/Mips/exe-got.test | 116 + test/elf/Mips/got-page-32.test | 203 ++ test/elf/Mips/got-page-64.test | 203 ++ test/elf/Mips/got16-2.test | 73 + test/elf/Mips/got16-micro.test | 165 ++ test/elf/Mips/got16.test | 196 ++ test/elf/Mips/gotsym.test | 43 + test/elf/Mips/gp-sym-1-micro.test | 88 + test/elf/Mips/gp-sym-1.test | 86 + test/elf/Mips/gp-sym-2.test | 103 + 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-4.test | 93 + test/elf/Mips/hilo16-5.test | 103 + test/elf/Mips/hilo16-8-micro.test | 81 + test/elf/Mips/hilo16-9-micro.test | 68 + test/elf/Mips/initfini-micro.test | 45 + test/elf/Mips/interpreter-64.test | 26 + test/elf/Mips/interpreter.test | 26 + test/elf/Mips/invalid-reginfo.test | 28 + test/elf/Mips/jalx-align-err.test | 46 + test/elf/Mips/jump-fix-err.test | 45 + test/elf/Mips/la25-stub-micro.test | 140 ++ test/elf/Mips/la25-stub.test | 133 + test/elf/Mips/mips-options-gp0.test | 78 + test/elf/Mips/n64-rel-chain.test | 134 + test/elf/Mips/opt-emulation.test | 41 + test/elf/Mips/pc23-range.test | 56 + test/elf/Mips/plt-entry-mixed-1.test | 114 + test/elf/Mips/plt-entry-mixed-2.test | 93 + test/elf/Mips/plt-entry-mixed-3.test | 98 + test/elf/Mips/plt-entry-mixed-4.test | 85 + test/elf/Mips/plt-entry-r6.test | 109 + test/elf/Mips/plt-header-micro.test | 108 + test/elf/Mips/plt-header-mixed.test | 105 + test/elf/Mips/plt-header.test | 99 + test/elf/Mips/r26-1-micro.test | 131 + test/elf/Mips/r26-1.test | 132 + test/elf/Mips/r26-2-micro.test | 88 + test/elf/Mips/r26-2.test | 82 + test/elf/Mips/rel-32.test | 59 + test/elf/Mips/rel-64.test | 61 + test/elf/Mips/rel-copy-micro.test | 159 ++ test/elf/Mips/rel-copy-pc.test | 113 + test/elf/Mips/rel-copy.test | 177 ++ test/elf/Mips/rel-dynamic-01-micro.test | 201 ++ test/elf/Mips/rel-dynamic-01.test | 237 ++ test/elf/Mips/rel-dynamic-02.test | 82 + test/elf/Mips/rel-dynamic-03-micro.test | 133 + test/elf/Mips/rel-dynamic-03.test | 129 + test/elf/Mips/rel-dynamic-04-micro.test | 211 ++ test/elf/Mips/rel-dynamic-04.test | 206 ++ test/elf/Mips/rel-dynamic-05-micro.test | 192 ++ test/elf/Mips/rel-dynamic-05.test | 188 ++ test/elf/Mips/rel-dynamic-06-64.test | 101 + test/elf/Mips/rel-dynamic-06.test | 103 + test/elf/Mips/rel-dynamic-07-64.test | 261 ++ test/elf/Mips/rel-dynamic-07.test | 276 +++ test/elf/Mips/rel-dynamic-08-64.test | 233 ++ test/elf/Mips/rel-dynamic-08-micro.test | 236 ++ test/elf/Mips/rel-dynamic-08.test | 233 ++ test/elf/Mips/rel-dynamic-09-micro.test | 109 + test/elf/Mips/rel-dynamic-09.test | 107 + test/elf/Mips/rel-dynamic-10-micro.test | 166 ++ test/elf/Mips/rel-dynamic-10.test | 160 ++ test/elf/Mips/rel-dynamic-11.test | 110 + test/elf/Mips/rel-dynamic-12.test | 213 ++ test/elf/Mips/rel-gprel16.test | 104 + test/elf/Mips/rel-gprel32-64.test | 70 + test/elf/Mips/rel-gprel32.test | 84 + test/elf/Mips/rel-pc-hilo.test | 70 + test/elf/Mips/rel-pc18-s3.test | 54 + test/elf/Mips/rel-pc19-s2.test | 54 + test/elf/Mips/rel-pc21-s2.test | 54 + test/elf/Mips/rel-pc26-s2.test | 54 + test/elf/Mips/rel-pc32.test | 59 + test/elf/Mips/rel-pc7-10-16-23.test | 86 + test/elf/Mips/rel-sub.test | 61 + test/elf/Mips/st-other.test | 90 + test/elf/Mips/tls-1-micro.test | 65 + test/elf/Mips/tls-1.test | 63 + test/elf/Mips/tls-2-64.test | 69 + test/elf/Mips/tls-2-micro.test | 70 + test/elf/Mips/tls-2.test | 69 + test/elf/Mips/tls-3-micro.test | 183 ++ test/elf/Mips/tls-3.test | 180 ++ test/elf/Mips/tls-4-micro.test | 126 + test/elf/Mips/tls-4.test | 123 + test/elf/Mips/tls-5-64.test | 71 + test/elf/Mips/tls-5-micro.test | 70 + test/elf/Mips/tls-5.test | 69 + test/elf/X86_64/ExampleTarget/triple.test | 32 + test/elf/X86_64/Inputs/constint.c | 1 + test/elf/X86_64/Inputs/constint.o | Bin 0 -> 1062 bytes test/elf/X86_64/Inputs/debug0.c | 5 + test/elf/X86_64/Inputs/debug0.x86-64 | Bin 0 -> 2704 bytes test/elf/X86_64/Inputs/debug1.c | 3 + test/elf/X86_64/Inputs/debug1.x86-64 | Bin 0 -> 2584 bytes test/elf/X86_64/Inputs/externtls.c | 6 + test/elf/X86_64/Inputs/externtls.x86-64 | Bin 0 -> 1424 bytes test/elf/X86_64/Inputs/fn.c | 4 + test/elf/X86_64/Inputs/fn.o | Bin 0 -> 1072 bytes test/elf/X86_64/Inputs/generaltls-so.o.yaml | 68 + test/elf/X86_64/Inputs/group/1.c | 8 + test/elf/X86_64/Inputs/group/1.o | Bin 0 -> 1456 bytes test/elf/X86_64/Inputs/group/fn.c | 4 + test/elf/X86_64/Inputs/group/fn.o | Bin 0 -> 1360 bytes test/elf/X86_64/Inputs/group/fn1.c | 3 + test/elf/X86_64/Inputs/group/fn1.o | Bin 0 -> 1352 bytes test/elf/X86_64/Inputs/group/fn2.c | 3 + test/elf/X86_64/Inputs/group/fn2.o | Bin 0 -> 1224 bytes test/elf/X86_64/Inputs/group/group.sh | 38 + test/elf/X86_64/Inputs/group/libfn.a | Bin 0 -> 2792 bytes test/elf/X86_64/Inputs/group/libfn.so | Bin 0 -> 2516 bytes test/elf/X86_64/Inputs/group/libfn1.a | Bin 0 -> 1492 bytes test/elf/X86_64/Inputs/group/libfn2.so | Bin 0 -> 9624 bytes test/elf/X86_64/Inputs/initfini-option.c | 13 + test/elf/X86_64/Inputs/initfini-option.o | Bin 0 -> 1824 bytes test/elf/X86_64/Inputs/initfini.c | 14 + test/elf/X86_64/Inputs/initfini.o | Bin 0 -> 2256 bytes test/elf/X86_64/Inputs/largebss.c | 3 + test/elf/X86_64/Inputs/largebss.o | Bin 0 -> 1131 bytes test/elf/X86_64/Inputs/layoutpass/1.c | 8 + test/elf/X86_64/Inputs/layoutpass/1.o | Bin 0 -> 1448 bytes test/elf/X86_64/Inputs/layoutpass/2.c | 7 + test/elf/X86_64/Inputs/layoutpass/2.o | Bin 0 -> 1320 bytes test/elf/X86_64/Inputs/layoutpass/3.c | 3 + test/elf/X86_64/Inputs/layoutpass/3.o | Bin 0 -> 1216 bytes test/elf/X86_64/Inputs/layoutpass/lib2.a | Bin 0 -> 1464 bytes test/elf/X86_64/Inputs/libfn.a | Bin 0 -> 1364 bytes test/elf/X86_64/Inputs/libfn.so | Bin 0 -> 2008 bytes test/elf/X86_64/Inputs/main.c | 4 + test/elf/X86_64/Inputs/main.o | Bin 0 -> 1360 bytes test/elf/X86_64/Inputs/multi-ovrd.c | 10 + test/elf/X86_64/Inputs/multi-ovrd.o | Bin 0 -> 1648 bytes test/elf/X86_64/Inputs/multi-weak.c | 20 + test/elf/X86_64/Inputs/multi-weak.o | Bin 0 -> 1856 bytes test/elf/X86_64/Inputs/multiweaksyms.o | Bin 0 -> 928 bytes test/elf/X86_64/Inputs/nmagic.c | 8 + test/elf/X86_64/Inputs/nmagic.o | Bin 0 -> 1528 bytes test/elf/X86_64/Inputs/no-interp-section.c | 1 + test/elf/X86_64/Inputs/no-interp-section.o | Bin 0 -> 975 bytes test/elf/X86_64/Inputs/note.o | Bin 0 -> 785 bytes test/elf/X86_64/Inputs/note.s | 11 + test/elf/X86_64/Inputs/note_ro_rw.o | Bin 0 -> 905 bytes test/elf/X86_64/Inputs/note_ro_rw.s | 21 + test/elf/X86_64/Inputs/ovrd.c | 6 + test/elf/X86_64/Inputs/ovrd.o | Bin 0 -> 1488 bytes test/elf/X86_64/Inputs/rodata.c | 3 + test/elf/X86_64/Inputs/rodata.o | Bin 0 -> 1584 bytes test/elf/X86_64/Inputs/rodata.s | 24 + test/elf/X86_64/Inputs/rwint.c | 1 + test/elf/X86_64/Inputs/rwint.o | Bin 0 -> 963 bytes test/elf/X86_64/Inputs/sectionmap.c | 4 + test/elf/X86_64/Inputs/sectionmap.o | Bin 0 -> 1478 bytes test/elf/X86_64/Inputs/undefcpp.c | 1 + test/elf/X86_64/Inputs/undefcpp.o | Bin 0 -> 1344 bytes test/elf/X86_64/Inputs/weak-zero-sized.o | Bin 0 -> 688 bytes test/elf/X86_64/Inputs/weak.c | 14 + test/elf/X86_64/Inputs/weak.o | Bin 0 -> 1712 bytes test/elf/X86_64/Inputs/weak.s | 21 + test/elf/X86_64/Inputs/zerosizedsection.o | Bin 0 -> 760 bytes test/elf/X86_64/Inputs/zerosizedsection.s | 3 + test/elf/X86_64/alignoffset.test | 119 + test/elf/X86_64/debug.test | 57 + test/elf/X86_64/defsym.test | 22 + test/elf/X86_64/demangle.test | 12 + test/elf/X86_64/dontignorezerosize-sections.test | 9 + test/elf/X86_64/dynamicvars.test | 124 + test/elf/X86_64/dynlib-nointerp-section.test | 4 + test/elf/X86_64/dynlib-search.test | 6 + test/elf/X86_64/dynsym-weak.test | 118 + test/elf/X86_64/extern-tls.test | 16 + test/elf/X86_64/general-dynamic-tls.test | 129 + test/elf/X86_64/imagebase.test | 94 + test/elf/X86_64/initfini-order.test | 10 + test/elf/X86_64/initfini.test | 23 + test/elf/X86_64/largebss.test | 20 + test/elf/X86_64/layoutpass-order.test | 14 + test/elf/X86_64/maxpagesize.test | 113 + test/elf/X86_64/mergesimilarstrings.test | 47 + test/elf/X86_64/multi-weak-layout.test | 52 + test/elf/X86_64/multi-weak-override.test | 16 + test/elf/X86_64/multi-weak-syms-order.test | 13 + test/elf/X86_64/nmagic.test | 91 + test/elf/X86_64/noalignsegments.test | 95 + test/elf/X86_64/note-sections-ro_plus_rw.test | 42 + test/elf/X86_64/note-sections.test | 23 + test/elf/X86_64/omagic.test | 237 ++ test/elf/X86_64/outputsegments.test | 189 ++ test/elf/X86_64/reloc_r_x86_64_16.test | 60 + test/elf/X86_64/reloc_r_x86_64_pc16.test | 61 + test/elf/X86_64/reloc_r_x86_64_pc64.test | 61 + test/elf/X86_64/rodata.test | 9 + test/elf/X86_64/sectionchoice.test | 7 + test/elf/X86_64/sectionmap.test | 22 + test/elf/X86_64/startGroupEndGroup.test | 48 + test/elf/X86_64/startGroupEndGroupWithDynlib.test | 10 + test/elf/X86_64/staticlib-search.test | 6 + test/elf/X86_64/undef.test | 18 + test/elf/X86_64/underscore-end.test | 81 + test/elf/X86_64/weak-override.test | 45 + test/elf/X86_64/weak-zero-sized.test | 26 + test/elf/X86_64/weaksym.test | 78 + test/elf/X86_64/yamlinput.test | 166 ++ test/elf/abs-dup.objtxt | 19 + test/elf/abs.test | 19 + test/elf/allowduplicates.objtxt | 51 + test/elf/archive-elf-forceload.test | 43 + test/elf/archive-elf.test | 38 + test/elf/as-needed.test | 15 + test/elf/branch.test | 34 + test/elf/check.test | 39 + test/elf/checkrodata.test | 9 + test/elf/common.test | 10 + test/elf/consecutive-weak-sym-defs.test | 81 + test/elf/defsym.objtxt | 28 + test/elf/dynamic-segorder.test | 17 + test/elf/dynamic-undef.test | 34 + test/elf/dynamic.test | 80 + test/elf/eh_frame_hdr.test | 30 + test/elf/entry.objtxt | 58 + test/elf/export-dynamic.test | 99 + test/elf/filenotfound.test | 3 + .../gnulinkonce-report-discarded-reference.test | 147 ++ test/elf/gnulinkonce/gnulinkonce-report-undef.test | 129 + test/elf/gnulinkonce/gnulinkonce.test | 151 ++ test/elf/gotpcrel.test | 21 + test/elf/gottpoff.test | 120 + test/elf/group-cmd-search.test | 134 + test/elf/hexagon-quickdata-sort.test | 12 + test/elf/hexagon-quickdata-sortcommon.test | 16 + test/elf/ifunc.test | 69 + test/elf/ignore-unknownoption.test | 5 + test/elf/init_array-order.test | 67 + test/elf/init_array.test | 6 + test/elf/initfini-options.test-1.test | 33 + test/elf/initfini-options.test-2.test | 47 + test/elf/initfini-options.test-3.test | 53 + test/elf/librarynotfound.test | 5 + test/elf/linker-as-ld.test | 16 + test/elf/linkerscript/Inputs/externs.ls | 3 + test/elf/linkerscript/Inputs/invalid.ls | 1 + test/elf/linkerscript/Inputs/prog1.o.yaml | 88 + test/elf/linkerscript/Inputs/prog2.o.yaml | 89 + test/elf/linkerscript/Inputs/prog3.o.yaml | 52 + test/elf/linkerscript/Inputs/simple.o.yaml | 52 + test/elf/linkerscript/Inputs/valid.ls | 6 + test/elf/linkerscript/externs.objtxt | 21 + test/elf/linkerscript/invalid-script-cli-1.test | 10 + test/elf/linkerscript/invalid-script-cli-2.test | 6 + test/elf/linkerscript/invalid.test | 5 + test/elf/linkerscript/sections-order.test | 97 + test/elf/linkerscript/sections-with-wildcards.test | 88 + test/elf/linkerscript/symbol-definition.test | 54 + test/elf/linkerscript/valid-script-cli.objtxt | 23 + test/elf/loginputfiles.test | 28 + test/elf/mergeatoms.test | 6 + test/elf/mergeconstants.test | 20 + test/elf/mergeglobalatoms.test | 11 + test/elf/note.test | 49 + test/elf/options/dynamic-linker.test | 17 + test/elf/phdr.test | 99 + test/elf/quickdata.test | 15 + test/elf/reloc.test | 38 + test/elf/responsefile.test | 6 + test/elf/rodata.test | 5 + test/elf/rosegment.test | 26 + .../sectionGroups/sectiongroup-new-members.test | 153 ++ test/elf/sectionGroups/sectiongroup-simple.test | 146 ++ .../sectiongroup-undef-member-other.test | 158 ++ .../sectionGroups/sectiongroup-undef-member.test | 144 ++ .../sectiongroup-with-globalsymbols.test | 253 ++ ...sectiongroup-with-undef-external-reference.test | 239 ++ .../sectiongroup-with-undef-signature.test | 222 ++ test/elf/sections.test | 142 ++ test/elf/sh_addralign.test | 38 + test/elf/soname.test | 6 + test/elf/strip-all.test | 107 + test/elf/stripped-empty.test | 4 + test/elf/symbols.test | 33 + test/elf/tls.test | 43 + test/elf/tlsAddr.test | 7 + test/elf/undef-from-dso-to-main.test | 52 + test/elf/undef-from-main-dso.test | 43 + test/elf/weaksym.test | 7 + test/elf/wrap.test | 279 +++ test/elf/x86-64-dynamic-relocs.test | 26 + test/elf/x86-64-dynamic.test | 79 + test/elf/x86.test | 38 + test/elf/x86_64-kinds.test | 23 + test/lit.cfg | 167 ++ test/lit.site.cfg.in | 22 + test/mach-o/Inputs/DependencyDump.py | 30 + test/mach-o/Inputs/bar.yaml | 18 + test/mach-o/Inputs/exported_symbols_list.exp | 6 + test/mach-o/Inputs/full.filelist | 3 + .../lib-search-paths/usr/lib/libmyshared.dylib | Bin 0 -> 20628 bytes .../Inputs/lib-search-paths/usr/lib/libmystatic.a | Bin 0 -> 556 bytes .../Inputs/lib-search-paths/usr/local/lib/file.o | Bin 0 -> 404 bytes test/mach-o/Inputs/libSystem.yaml | 13 + test/mach-o/Inputs/libbar.a | Bin 0 -> 824 bytes test/mach-o/Inputs/libfoo.a | Bin 0 -> 1320 bytes test/mach-o/Inputs/order_file-basic.order | 11 + test/mach-o/Inputs/partial.filelist | 3 + test/mach-o/Inputs/use-dylib-install-names.yaml | 28 + test/mach-o/PIE.yaml | 44 + test/mach-o/align_text.yaml | 45 + test/mach-o/arm-interworking-movw.yaml | 393 +++ test/mach-o/arm-interworking.yaml | 362 +++ test/mach-o/arm-shims.yaml | 179 ++ test/mach-o/arm-subsections-via-symbols.yaml | 60 + test/mach-o/cstring-sections.yaml | 91 + test/mach-o/data-only-dylib.yaml | 27 + test/mach-o/demangle.yaml | 74 + test/mach-o/dependency_info.yaml | 24 + test/mach-o/dso_handle.yaml | 62 + test/mach-o/dylib-exports.yaml | 41 + test/mach-o/dylib-install-names.yaml | 74 + test/mach-o/exe-offsets.yaml | 45 + test/mach-o/exe-segment-overlap.yaml | 44 + test/mach-o/exported_symbols_list-dylib.yaml | 77 + test/mach-o/exported_symbols_list-obj.yaml | 67 + test/mach-o/exported_symbols_list-undef.yaml | 55 + test/mach-o/fat-archive.yaml | 45 + test/mach-o/filelist.yaml | 18 + test/mach-o/force_load-dylib.yaml | 45 + test/mach-o/force_load-x86_64.yaml | 38 + test/mach-o/framework-user-paths.yaml | 41 + test/mach-o/got-order.yaml | 134 + test/mach-o/hello-world-arm64.yaml | 104 + test/mach-o/hello-world-armv6.yaml | 72 + test/mach-o/hello-world-armv7.yaml | 85 + test/mach-o/hello-world-x86.yaml | 71 + test/mach-o/hello-world-x86_64.yaml | 126 + test/mach-o/image-base.yaml | 27 + test/mach-o/infer-arch.yaml | 29 + test/mach-o/interposing-section.yaml | 79 + test/mach-o/keep_private_externs.yaml | 63 + test/mach-o/lazy-bind-x86_64.yaml | 125 + test/mach-o/lib-search-paths.yaml | 16 + test/mach-o/library-order.yaml | 45 + test/mach-o/library-rescan.yaml | 46 + test/mach-o/libresolve-bizarre-root-override.yaml | 17 + test/mach-o/libresolve-multiple-syslibroots.yaml | 17 + test/mach-o/libresolve-one-syslibroot.yaml | 25 + test/mach-o/libresolve-simple.yaml | 21 + test/mach-o/libresolve-user-paths.yaml | 20 + test/mach-o/libresolve-z.yaml | 21 + test/mach-o/linker-as-ld.yaml | 39 + test/mach-o/lit.local.cfg | 4 + test/mach-o/mh_bundle_header.yaml | 53 + test/mach-o/mh_dylib_header.yaml | 53 + test/mach-o/objc_export_list.yaml | 63 + test/mach-o/order_file-basic.yaml | 75 + test/mach-o/parse-aliases.yaml | 90 + test/mach-o/parse-arm-relocs.yaml | 818 +++++++ test/mach-o/parse-cfstring32.yaml | 94 + test/mach-o/parse-cfstring64.yaml | 108 + test/mach-o/parse-compact-unwind32.yaml | 72 + test/mach-o/parse-compact-unwind64.yaml | 76 + test/mach-o/parse-data-in-code-armv7.yaml | 157 ++ test/mach-o/parse-data-in-code-x86.yaml | 77 + test/mach-o/parse-data-relocs-arm64.yaml | 222 ++ test/mach-o/parse-data-relocs-x86_64.yaml | 230 ++ test/mach-o/parse-data.yaml | 119 + test/mach-o/parse-eh-frame-x86-anon.yaml | 129 + test/mach-o/parse-eh-frame-x86-labeled.yaml | 193 ++ test/mach-o/parse-eh-frame.yaml | 88 + test/mach-o/parse-function.yaml | 100 + test/mach-o/parse-initializers32.yaml | 84 + test/mach-o/parse-initializers64.yaml | 105 + test/mach-o/parse-literals-error.yaml | 25 + test/mach-o/parse-literals.yaml | 93 + test/mach-o/parse-non-lazy-pointers.yaml | 98 + test/mach-o/parse-relocs-x86.yaml | 296 +++ test/mach-o/parse-section-no-symbol.yaml | 23 + test/mach-o/parse-tentative-defs.yaml | 88 + test/mach-o/parse-text-relocs-arm64.yaml | 237 ++ test/mach-o/parse-text-relocs-x86_64.yaml | 168 ++ test/mach-o/re-exported-dylib-ordinal.yaml | 105 + test/mach-o/rpath.yaml | 38 + test/mach-o/sectalign.yaml | 80 + test/mach-o/unwind-info-simple-arm64.yaml | 280 +++ test/mach-o/unwind-info-simple-x86_64.yaml | 118 + test/mach-o/upward-dylib-load-command.yaml | 48 + test/mach-o/upward-dylib-paths.yaml | 18 + test/mach-o/usage.yaml | 8 + test/mach-o/use-simple-dylib.yaml | 131 + test/mach-o/write-final-sections.yaml | 167 ++ test/mach-o/wrong-arch-error.yaml | 49 + test/pecoff/Inputs/abs.obj.yaml | 11 + test/pecoff/Inputs/alignment.obj.yaml | 103 + test/pecoff/Inputs/alternatename1.obj.yaml | 23 + test/pecoff/Inputs/alternatename2.obj.yaml | 23 + test/pecoff/Inputs/alternatename3.obj.yaml | 39 + test/pecoff/Inputs/armnt-ImageBase.obj.yaml | 39 + test/pecoff/Inputs/armnt-ImageBase.s | 16 + test/pecoff/Inputs/armnt-addr32-exec.obj.yaml | 55 + 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.obj.yaml | 39 + test/pecoff/Inputs/armnt-blx23t.s | 33 + test/pecoff/Inputs/armnt-branch24t.obj.yaml | 39 + test/pecoff/Inputs/armnt-branch24t.s | 26 + test/pecoff/Inputs/armnt-exports.def | 4 + test/pecoff/Inputs/armnt-exports.obj.yaml | 35 + test/pecoff/Inputs/armnt-import.obj.yaml | 39 + test/pecoff/Inputs/armnt-import.s | 21 + test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml | 39 + test/pecoff/Inputs/armnt-mov32t-exec.s | 30 + test/pecoff/Inputs/armnt-mov32t.obj.yaml | 55 + test/pecoff/Inputs/armnt-mov32t.s | 24 + test/pecoff/Inputs/armnt-obj.s | 12 + test/pecoff/Inputs/armnt-obj.yaml | 29 + test/pecoff/Inputs/associative1.obj.yaml | 53 + test/pecoff/Inputs/associative3.obj.yaml | 33 + test/pecoff/Inputs/basereloc.obj.yaml | 164 ++ test/pecoff/Inputs/bss.asm | 20 + test/pecoff/Inputs/bss.obj | Bin 0 -> 683 bytes test/pecoff/Inputs/comdat.obj.yaml | 53 + test/pecoff/Inputs/common-symbol.obj.yaml | 85 + test/pecoff/Inputs/drectve.obj.yaml | 79 + test/pecoff/Inputs/drectve2.obj.yaml | 45 + test/pecoff/Inputs/drectve3.lib | Bin 0 -> 462 bytes test/pecoff/Inputs/entry.obj.yaml | 40 + test/pecoff/Inputs/executable.obj.yaml | 29 + test/pecoff/Inputs/executable.s | 17 + test/pecoff/Inputs/export.obj.yaml | 69 + 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 0 -> 1938 bytes test/pecoff/Inputs/imagebase.obj.yaml | 55 + test/pecoff/Inputs/library.lib | Bin 0 -> 1694 bytes test/pecoff/Inputs/machine-type-unknown.obj.yaml | 38 + test/pecoff/Inputs/main.obj.yaml | 70 + 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 + test/pecoff/Inputs/nonstandard-sections.obj.yaml | 53 + test/pecoff/Inputs/nop.asm | 9 + test/pecoff/Inputs/nop.obj.yaml | 51 + test/pecoff/Inputs/nop64.obj.yaml | 67 + test/pecoff/Inputs/reloc.obj.yaml | 82 + test/pecoff/Inputs/reloc64.obj.yaml | 63 + test/pecoff/Inputs/resource.rc | 4 + test/pecoff/Inputs/resource.res | Bin 0 -> 108 bytes test/pecoff/Inputs/responsefile.txt | 1 + test/pecoff/Inputs/secrel1.obj.yaml | 69 + 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 0 -> 1120 bytes test/pecoff/Inputs/subsystem.main.yaml | 35 + test/pecoff/Inputs/subsystem.winmain.yaml | 35 + test/pecoff/Inputs/tlsused.obj.yaml | 29 + test/pecoff/Inputs/unknown-drectve.obj.yaml | 42 + test/pecoff/Inputs/unwind.obj.yaml | 129 + test/pecoff/Inputs/vars-main-x64.obj.yaml | 63 + 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 0 -> 1994 bytes test/pecoff/Inputs/vars64.lib | Bin 0 -> 2016 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/manifest.test | 63 + 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/CMakeLists.txt | 2 + tools/Makefile | 17 + tools/linker-script-test/CMakeLists.txt | 8 + tools/linker-script-test/Makefile | 24 + tools/linker-script-test/linker-script-test.cpp | 57 + tools/lld/CMakeLists.txt | 25 + tools/lld/Makefile | 30 + tools/lld/TODO.txt | 2 + tools/lld/lld.cpp | 36 + unittests/CMakeLists.txt | 15 + unittests/CoreTests/CMakeLists.txt | 4 + unittests/CoreTests/Makefile | 14 + unittests/CoreTests/ParallelTest.cpp | 31 + unittests/CoreTests/RangeTest.cpp | 240 ++ unittests/DriverTests/CMakeLists.txt | 14 + unittests/DriverTests/DarwinLdDriverTest.cpp | 240 ++ unittests/DriverTests/DriverTest.h | 61 + unittests/DriverTests/GnuLdDriverTest.cpp | 284 +++ unittests/DriverTests/Makefile | 20 + unittests/DriverTests/UniversalDriverTest.cpp | 33 + unittests/DriverTests/WinLinkDriverTest.cpp | 728 ++++++ unittests/DriverTests/WinLinkModuleDefTest.cpp | 155 ++ unittests/MachOTests/CMakeLists.txt | 13 + .../MachONormalizedFileBinaryReaderTests.cpp | 748 ++++++ .../MachONormalizedFileBinaryWriterTests.cpp | 693 ++++++ .../MachOTests/MachONormalizedFileToAtomsTests.cpp | 94 + .../MachOTests/MachONormalizedFileYAMLTests.cpp | 766 ++++++ unittests/MachOTests/empty_obj_x86_armv7.txt | 1272 ++++++++++ unittests/Makefile | 31 + utils/astyle-options | 7 + 1131 files changed, 106976 insertions(+) create mode 100644 .arcconfig create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE.TXT create mode 100644 Makefile create mode 100644 README.md create mode 100644 cmake/modules/FindVTune.cmake create mode 100644 docs/C++11.rst create mode 100644 docs/CMakeLists.txt create mode 100644 docs/Driver.rst create mode 100644 docs/Makefile create mode 100644 docs/README.txt create mode 100644 docs/Readers.rst create mode 100644 docs/_static/favicon.ico create mode 100644 docs/_templates/indexsidebar.html create mode 100644 docs/_templates/layout.html create mode 100644 docs/conf.py create mode 100644 docs/design.rst create mode 100644 docs/development.rst create mode 100644 docs/getting_started.rst create mode 100644 docs/hello.png create mode 100644 docs/index.rst create mode 100644 docs/llvm-theme/layout.html create mode 100644 docs/llvm-theme/static/contents.png create mode 100644 docs/llvm-theme/static/llvm.css create mode 100644 docs/llvm-theme/static/logo.png create mode 100644 docs/llvm-theme/static/navigation.png create mode 100644 docs/llvm-theme/theme.conf create mode 100644 docs/make.bat create mode 100644 docs/open_projects.rst create mode 100644 docs/sphinx_intro.rst create mode 100644 docs/windows_support.rst create mode 100644 include/Makefile create mode 100644 include/lld/Config/Makefile create mode 100644 include/lld/Config/Version.h create mode 100644 include/lld/Config/Version.inc.in create mode 100644 include/lld/Core/AbsoluteAtom.h create mode 100644 include/lld/Core/Alias.h create mode 100644 include/lld/Core/ArchiveLibraryFile.h create mode 100644 include/lld/Core/Atom.h create mode 100644 include/lld/Core/DefinedAtom.h create mode 100644 include/lld/Core/Error.h create mode 100644 include/lld/Core/File.h create mode 100644 include/lld/Core/Instrumentation.h create mode 100644 include/lld/Core/LLVM.h create mode 100644 include/lld/Core/LinkingContext.h create mode 100644 include/lld/Core/Node.h create mode 100644 include/lld/Core/Parallel.h create mode 100644 include/lld/Core/Pass.h create mode 100644 include/lld/Core/PassManager.h create mode 100644 include/lld/Core/Reader.h create mode 100644 include/lld/Core/Reference.h create mode 100644 include/lld/Core/Resolver.h create mode 100644 include/lld/Core/STDExtras.h create mode 100644 include/lld/Core/SharedLibraryAtom.h create mode 100644 include/lld/Core/SharedLibraryFile.h create mode 100644 include/lld/Core/Simple.h create mode 100644 include/lld/Core/SymbolTable.h create mode 100644 include/lld/Core/TODO.txt create mode 100644 include/lld/Core/UndefinedAtom.h create mode 100644 include/lld/Core/Writer.h create mode 100644 include/lld/Core/range.h create mode 100644 include/lld/Driver/Driver.h create mode 100644 include/lld/Driver/WinLinkModuleDef.h create mode 100644 include/lld/Makefile create mode 100644 include/lld/ReaderWriter/AtomLayout.h create mode 100644 include/lld/ReaderWriter/CoreLinkingContext.h create mode 100644 include/lld/ReaderWriter/ELFLinkingContext.h create mode 100644 include/lld/ReaderWriter/ELFTargets.h create mode 100644 include/lld/ReaderWriter/LinkerScript.h create mode 100644 include/lld/ReaderWriter/MachOLinkingContext.h create mode 100644 include/lld/ReaderWriter/PECOFFLinkingContext.h create mode 100644 include/lld/ReaderWriter/RelocationHelperFunctions.h create mode 100644 include/lld/ReaderWriter/YamlContext.h create mode 100644 lib/CMakeLists.txt create mode 100644 lib/Config/CMakeLists.txt create mode 100644 lib/Config/Makefile create mode 100644 lib/Config/Version.cpp create mode 100644 lib/Core/CMakeLists.txt create mode 100644 lib/Core/DefinedAtom.cpp create mode 100644 lib/Core/Error.cpp create mode 100644 lib/Core/File.cpp create mode 100644 lib/Core/LinkingContext.cpp create mode 100644 lib/Core/Makefile create mode 100644 lib/Core/Reader.cpp create mode 100644 lib/Core/Resolver.cpp create mode 100644 lib/Core/SymbolTable.cpp create mode 100644 lib/Core/TODO.txt create mode 100644 lib/Core/Writer.cpp create mode 100644 lib/Driver/CMakeLists.txt create mode 100644 lib/Driver/CoreDriver.cpp create mode 100644 lib/Driver/CoreOptions.td create mode 100644 lib/Driver/DarwinLdDriver.cpp create mode 100644 lib/Driver/DarwinLdOptions.td create mode 100644 lib/Driver/Driver.cpp create mode 100644 lib/Driver/GnuLdDriver.cpp create mode 100644 lib/Driver/GnuLdOptions.td create mode 100644 lib/Driver/Makefile create mode 100644 lib/Driver/TODO.rst create mode 100644 lib/Driver/UniversalDriver.cpp create mode 100644 lib/Driver/UniversalDriverOptions.td create mode 100644 lib/Driver/WinLinkDriver.cpp create mode 100644 lib/Driver/WinLinkModuleDef.cpp create mode 100644 lib/Driver/WinLinkOptions.td create mode 100644 lib/Makefile create mode 100644 lib/ReaderWriter/CMakeLists.txt create mode 100644 lib/ReaderWriter/CoreLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h create mode 100644 lib/ReaderWriter/ELF/AArch64/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/AArch64/Makefile create mode 100644 lib/ReaderWriter/ELF/AArch64/TODO.rst create mode 100644 lib/ReaderWriter/ELF/ARM/ARMELFFile.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMELFReader.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp create mode 100644 lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h create mode 100644 lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/ARM/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/ARM/Makefile create mode 100644 lib/ReaderWriter/ELF/ARM/TODO.rst create mode 100644 lib/ReaderWriter/ELF/Atoms.h create mode 100644 lib/ReaderWriter/ELF/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/Chunk.h create mode 100644 lib/ReaderWriter/ELF/CreateELF.h create mode 100644 lib/ReaderWriter/ELF/DefaultLayout.h create mode 100644 lib/ReaderWriter/ELF/DefaultTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/DynamicFile.h create mode 100644 lib/ReaderWriter/ELF/DynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/ELFFile.h create mode 100644 lib/ReaderWriter/ELF/ELFLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/ELFReader.h create mode 100644 lib/ReaderWriter/ELF/ExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/HeaderChunks.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/Hexagon/Makefile create mode 100644 lib/ReaderWriter/ELF/Layout.h create mode 100644 lib/ReaderWriter/ELF/Makefile create mode 100644 lib/ReaderWriter/ELF/Mips/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/Mips/Makefile create mode 100644 lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFile.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFReader.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsELFWriters.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h create mode 100644 lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/OrderPass.h create mode 100644 lib/ReaderWriter/ELF/OutputELFWriter.h create mode 100644 lib/ReaderWriter/ELF/Reader.cpp create mode 100644 lib/ReaderWriter/ELF/SectionChunks.h create mode 100644 lib/ReaderWriter/ELF/SegmentChunks.h create mode 100644 lib/ReaderWriter/ELF/TODO.txt create mode 100644 lib/ReaderWriter/ELF/TargetHandler.h create mode 100644 lib/ReaderWriter/ELF/TargetLayout.h create mode 100644 lib/ReaderWriter/ELF/Writer.cpp create mode 100644 lib/ReaderWriter/ELF/Writer.h create mode 100644 lib/ReaderWriter/ELF/X86/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/X86/Makefile create mode 100644 lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/X86/X86ELFFile.h create mode 100644 lib/ReaderWriter/ELF/X86/X86ELFReader.h create mode 100644 lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/X86/X86LinkingContext.h create mode 100644 lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/X86/X86RelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/X86/X86TargetHandler.h create mode 100644 lib/ReaderWriter/ELF/X86_64/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h create mode 100644 lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile create mode 100644 lib/ReaderWriter/ELF/X86_64/Makefile create mode 100644 lib/ReaderWriter/ELF/X86_64/TODO.rst create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp create mode 100644 lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h create mode 100644 lib/ReaderWriter/FileArchive.cpp create mode 100644 lib/ReaderWriter/LinkerScript.cpp create mode 100644 lib/ReaderWriter/MachO/ArchHandler.cpp create mode 100644 lib/ReaderWriter/MachO/ArchHandler.h create mode 100644 lib/ReaderWriter/MachO/ArchHandler_arm.cpp create mode 100644 lib/ReaderWriter/MachO/ArchHandler_arm64.cpp create mode 100644 lib/ReaderWriter/MachO/ArchHandler_x86.cpp create mode 100644 lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp create mode 100644 lib/ReaderWriter/MachO/Atoms.h create mode 100644 lib/ReaderWriter/MachO/CMakeLists.txt create mode 100644 lib/ReaderWriter/MachO/CompactUnwindPass.cpp create mode 100644 lib/ReaderWriter/MachO/ExecutableAtoms.hpp create mode 100644 lib/ReaderWriter/MachO/File.h create mode 100644 lib/ReaderWriter/MachO/GOTPass.cpp create mode 100644 lib/ReaderWriter/MachO/LayoutPass.cpp create mode 100644 lib/ReaderWriter/MachO/LayoutPass.h create mode 100644 lib/ReaderWriter/MachO/MachOLinkingContext.cpp create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFile.h create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp create mode 100644 lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp create mode 100644 lib/ReaderWriter/MachO/MachOPasses.h create mode 100644 lib/ReaderWriter/MachO/Makefile create mode 100644 lib/ReaderWriter/MachO/ShimPass.cpp create mode 100644 lib/ReaderWriter/MachO/StubsPass.cpp create mode 100644 lib/ReaderWriter/MachO/WriterMachO.cpp create mode 100644 lib/ReaderWriter/Makefile create mode 100644 lib/ReaderWriter/Native/CMakeLists.txt create mode 100644 lib/ReaderWriter/Native/Makefile create mode 100644 lib/ReaderWriter/Native/NativeFileFormat.h create mode 100644 lib/ReaderWriter/Native/ReaderNative.cpp create mode 100644 lib/ReaderWriter/Native/WriterNative.cpp create mode 100644 lib/ReaderWriter/PECOFF/Atoms.h create mode 100644 lib/ReaderWriter/PECOFF/CMakeLists.txt create mode 100644 lib/ReaderWriter/PECOFF/EdataPass.cpp create mode 100644 lib/ReaderWriter/PECOFF/EdataPass.h create mode 100644 lib/ReaderWriter/PECOFF/IdataPass.cpp create mode 100644 lib/ReaderWriter/PECOFF/IdataPass.h create mode 100644 lib/ReaderWriter/PECOFF/InferSubsystemPass.h create mode 100644 lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp create mode 100644 lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h create mode 100644 lib/ReaderWriter/PECOFF/LoadConfigPass.cpp create mode 100644 lib/ReaderWriter/PECOFF/LoadConfigPass.h create mode 100644 lib/ReaderWriter/PECOFF/Makefile create mode 100644 lib/ReaderWriter/PECOFF/OrderPass.h create mode 100644 lib/ReaderWriter/PECOFF/PDBPass.h create mode 100644 lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp create mode 100644 lib/ReaderWriter/PECOFF/Pass.cpp create mode 100644 lib/ReaderWriter/PECOFF/Pass.h create mode 100644 lib/ReaderWriter/PECOFF/ReaderCOFF.cpp create mode 100644 lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp create mode 100644 lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp create mode 100644 lib/ReaderWriter/PECOFF/WriterImportLibrary.h create mode 100644 lib/ReaderWriter/PECOFF/WriterPECOFF.cpp create mode 100644 lib/ReaderWriter/YAML/CMakeLists.txt create mode 100644 lib/ReaderWriter/YAML/Makefile create mode 100644 lib/ReaderWriter/YAML/ReaderWriterYAML.cpp create mode 100644 test/CMakeLists.txt create mode 100644 test/Driver/Inputs/libtest.a create mode 100644 test/Driver/Inputs/usr/lib/i386/libtest.a create mode 100644 test/Driver/Inputs/usr/lib/libtest.a create mode 100644 test/Driver/def-lib-search.test create mode 100644 test/Driver/flavor-option.test create mode 100644 test/Driver/lib-search.test create mode 100644 test/Driver/so-whole-archive.test create mode 100644 test/Driver/trivial-driver.test create mode 100644 test/Driver/undef-basic.objtxt create mode 100644 test/LinkerScript/expr-precedence.test create mode 100644 test/LinkerScript/extern-bad-symbol.test create mode 100644 test/LinkerScript/extern-empty.test create mode 100644 test/LinkerScript/extern-valid.test create mode 100644 test/LinkerScript/incomplete-ternary.test create mode 100644 test/LinkerScript/libname-err-1.test create mode 100644 test/LinkerScript/libname-err-2.test create mode 100644 test/LinkerScript/linker-script-outputformat.test create mode 100644 test/LinkerScript/linker-script.test create mode 100644 test/LinkerScript/memory-empty.test create mode 100644 test/LinkerScript/memory-missing-attrs.test create mode 100644 test/LinkerScript/memory-missing-length.test create mode 100644 test/LinkerScript/memory-missing-name.test create mode 100644 test/LinkerScript/memory-missing-origin.test create mode 100644 test/LinkerScript/memory-valid.test create mode 100644 test/LinkerScript/missing-entry-symbol.test create mode 100644 test/LinkerScript/missing-input-file-name.test create mode 100644 test/LinkerScript/missing-input-sections.test create mode 100644 test/LinkerScript/missing-operand.test create mode 100644 test/LinkerScript/missing-output-section-name.test create mode 100644 test/LinkerScript/missing-symbol.test create mode 100644 test/LinkerScript/sections.test create mode 100644 test/Makefile create mode 100644 test/Unit/lit.cfg create mode 100644 test/Unit/lit.site.cfg.in create mode 100644 test/core/absolute-basic.objtxt create mode 100644 test/core/absolute-local.objtxt create mode 100644 test/core/archive-basic.objtxt create mode 100644 test/core/archive-chain.objtxt create mode 100644 test/core/archive-tentdef-search.objtxt create mode 100644 test/core/associates.objtxt create mode 100644 test/core/auto-hide-coalesce.objtxt create mode 100644 test/core/code-model-attributes.objtxt create mode 100644 test/core/constants-coalesce.objtxt create mode 100644 test/core/cstring-coalesce.objtxt create mode 100644 test/core/custom-section-coalesce.objtxt create mode 100644 test/core/custom-section.objtxt create mode 100644 test/core/dead-strip-attributes.objtxt create mode 100644 test/core/dead-strip-basic.objtxt create mode 100644 test/core/dead-strip-globals.objtxt create mode 100644 test/core/dead-strip-reverse.objtxt create mode 100644 test/core/error-atom-attribute.objtxt create mode 100644 test/core/error-atom-content-byte-value.objtxt create mode 100644 test/core/error-atom-content-bytes.objtxt create mode 100644 test/core/error-atom-type.objtxt create mode 100644 test/core/error-atom-undefined-wrong-attribue.objtxt create mode 100644 test/core/error-duplicate-absolutes.objtxt create mode 100644 test/core/error-file-attribute.objtxt create mode 100644 test/core/error-fixup-attribute.objtxt create mode 100644 test/core/error-fixup-target.objtxt create mode 100644 test/core/fixups-addend.objtxt create mode 100644 test/core/fixups-dup-named.objtxt create mode 100644 test/core/fixups-named.objtxt create mode 100644 test/core/fixups-unnamed.objtxt create mode 100644 test/core/gnulinkonce-rearrange-resolve.objtxt create mode 100644 test/core/gnulinkonce-remaining-undef.objtxt create mode 100644 test/core/gnulinkonce-resolve.objtxt create mode 100644 test/core/gnulinkonce-simple.objtxt create mode 100644 test/core/inline-coalesce.objtxt create mode 100644 test/core/multiple-def-error.objtxt create mode 100644 test/core/permissions.objtxt create mode 100644 test/core/sectiongroup-deadstrip.objtxt create mode 100644 test/core/sectiongroup-gnulinkonce-error.objtxt create mode 100644 test/core/sectiongroup-rearrange-resolve.objtxt create mode 100644 test/core/sectiongroup-remaining-undef.objtxt create mode 100644 test/core/sectiongroup-resolve.objtxt create mode 100644 test/core/sectiongroup-simple.objtxt create mode 100644 test/core/shared-library-basic.objtxt create mode 100644 test/core/shared-library-coalesce.objtxt create mode 100644 test/core/tent-merge.objtxt create mode 100644 test/core/undef-coalesce-error.objtxt create mode 100644 test/core/undef-coalesce.objtxt create mode 100644 test/core/undef-fallback.objtxt create mode 100644 test/core/undef-weak-coalesce.objtxt create mode 100644 test/core/weak-coalesce.objtxt create mode 100644 test/darwin/native-and-mach-o.objtxt create mode 100644 test/elf/AArch64/Inputs/fn.c create mode 100644 test/elf/AArch64/Inputs/fn.o create mode 100644 test/elf/AArch64/Inputs/initfini-option.c create mode 100644 test/elf/AArch64/Inputs/initfini-option.o create mode 100644 test/elf/AArch64/Inputs/initfini.c create mode 100644 test/elf/AArch64/Inputs/initfini.o create mode 100644 test/elf/AArch64/Inputs/main.c create mode 100644 test/elf/AArch64/Inputs/main.o create mode 100644 test/elf/AArch64/Inputs/no-interp-section.c create mode 100644 test/elf/AArch64/Inputs/no-interp-section.o create mode 100644 test/elf/AArch64/Inputs/zerosizedsection.o create mode 100644 test/elf/AArch64/Inputs/zerosizedsection.s create mode 100644 test/elf/AArch64/defsym.test create mode 100644 test/elf/AArch64/dontignorezerosize-sections.test create mode 100644 test/elf/AArch64/dynlib-nointerp-section.test create mode 100644 test/elf/AArch64/initfini.test create mode 100644 test/elf/AArch64/rel-abs32-overflow.test create mode 100644 test/elf/AArch64/rel-abs32.test create mode 100644 test/elf/AArch64/rel-abs64.test create mode 100644 test/elf/AArch64/rel-bad.test create mode 100644 test/elf/ARM/arm-symbols.test create mode 100644 test/elf/ARM/defsym.test create mode 100644 test/elf/ARM/entry-point.test create mode 100644 test/elf/ARM/missing-symbol.test create mode 100644 test/elf/ARM/rel-abs32.test create mode 100644 test/elf/ARM/rel-arm-call.test create mode 100644 test/elf/ARM/rel-arm-jump24-veneer-b.test create mode 100644 test/elf/ARM/rel-arm-jump24-veneer-bl.test create mode 100644 test/elf/ARM/rel-arm-jump24.test create mode 100644 test/elf/ARM/rel-arm-mov.test create mode 100644 test/elf/ARM/rel-arm-prel31.test create mode 100644 test/elf/ARM/rel-arm-thm-interwork.test create mode 100644 test/elf/ARM/rel-rel32.test create mode 100644 test/elf/ARM/rel-thm-call.test create mode 100644 test/elf/ARM/rel-thm-jump11.test create mode 100644 test/elf/ARM/rel-thm-jump24-veneer.test create mode 100644 test/elf/ARM/rel-thm-jump24.test create mode 100644 test/elf/ARM/rel-thm-mov.test create mode 100644 test/elf/ARM/rel-tls-ie32.test create mode 100644 test/elf/ARM/rel-tls-le32.test create mode 100644 test/elf/ARM/thm-symbols.test create mode 100644 test/elf/ARM/undef-lazy-symbol.test create mode 100644 test/elf/Hexagon/Inputs/dynobj-data.c create mode 100644 test/elf/Hexagon/Inputs/dynobj-data.o create mode 100644 test/elf/Hexagon/Inputs/dynobj.c create mode 100644 test/elf/Hexagon/Inputs/dynobj.o create mode 100644 test/elf/Hexagon/Inputs/got-plt-order.c create mode 100644 test/elf/Hexagon/Inputs/got-plt-order.o create mode 100644 test/elf/Hexagon/Inputs/libMaxAlignment.a create mode 100644 test/elf/Hexagon/Inputs/sda-base.o create mode 100644 test/elf/Hexagon/Inputs/sdata1.c create mode 100644 test/elf/Hexagon/Inputs/sdata1.o create mode 100644 test/elf/Hexagon/Inputs/sdata2.c create mode 100644 test/elf/Hexagon/Inputs/sdata2.o create mode 100644 test/elf/Hexagon/Inputs/use-shared.hexagon create mode 100644 test/elf/Hexagon/dynlib-data.test create mode 100644 test/elf/Hexagon/dynlib-gotoff.test create mode 100644 test/elf/Hexagon/dynlib-hash.test create mode 100644 test/elf/Hexagon/dynlib-rela.test create mode 100644 test/elf/Hexagon/dynlib-syms.test create mode 100644 test/elf/Hexagon/dynlib.test create mode 100644 test/elf/Hexagon/hexagon-got-plt-order.test create mode 100644 test/elf/Hexagon/hexagon-plt-setup.test create mode 100644 test/elf/Hexagon/maxalignment.test create mode 100644 test/elf/Hexagon/rela-order.test create mode 100644 test/elf/Hexagon/sda-base.test create mode 100644 test/elf/Hexagon/zerofillquick-sdata.test create mode 100644 test/elf/Inputs/abs-test.i386 create mode 100644 test/elf/Inputs/bar.o.x86-64 create mode 100644 test/elf/Inputs/branch-test.hexagon create mode 100644 test/elf/Inputs/branch-test.ppc create mode 100644 test/elf/Inputs/consecutive-weak-defs.o.yaml create mode 100644 test/elf/Inputs/constants-merge.x86-64 create mode 100644 test/elf/Inputs/constdata.x86-64 create mode 100644 test/elf/Inputs/foo.o.x86-64 create mode 100644 test/elf/Inputs/globalconst.c create mode 100644 test/elf/Inputs/globalconst.o.x86-64 create mode 100644 test/elf/Inputs/gotpcrel.S create mode 100644 test/elf/Inputs/gotpcrel.x86-64 create mode 100644 test/elf/Inputs/group-cmd-search-1.ls create mode 100644 test/elf/Inputs/group-cmd-search-2.ls create mode 100644 test/elf/Inputs/group-cmd-search-3.ls create mode 100644 test/elf/Inputs/ifunc.S create mode 100644 test/elf/Inputs/ifunc.cpp create mode 100644 test/elf/Inputs/ifunc.cpp.x86-64 create mode 100644 test/elf/Inputs/ifunc.x86-64 create mode 100644 test/elf/Inputs/init_array.x86-64 create mode 100644 test/elf/Inputs/libfnarchive.a create mode 100644 test/elf/Inputs/libifunc.x86-64.so create mode 100644 test/elf/Inputs/libundef.so create mode 100755 test/elf/Inputs/libweaksym.so create mode 100644 test/elf/Inputs/main-with-global-def.o.yaml create mode 100644 test/elf/Inputs/mainobj.x86_64 create mode 100644 test/elf/Inputs/object-test.elf-hexagon create mode 100644 test/elf/Inputs/object-test.elf-i386 create mode 100644 test/elf/Inputs/phdr.i386 create mode 100644 test/elf/Inputs/quickdata-sort-test.o.elf-hexagon create mode 100644 test/elf/Inputs/quickdata-sortcommon-test.o.elf-hexagon create mode 100644 test/elf/Inputs/quickdata-test.elf-hexagon create mode 100644 test/elf/Inputs/reloc-test.elf-i386 create mode 100644 test/elf/Inputs/reloc-xb.x86 create mode 100644 test/elf/Inputs/reloc-xt.x86 create mode 100644 test/elf/Inputs/relocs-dynamic.x86-64 create mode 100644 test/elf/Inputs/relocs.x86-64 create mode 100644 test/elf/Inputs/responsefile create mode 100644 test/elf/Inputs/rodata-test.hexagon create mode 100644 test/elf/Inputs/rodata-test.i386 create mode 100644 test/elf/Inputs/rodata.c create mode 100644 test/elf/Inputs/rodata.o create mode 100644 test/elf/Inputs/section-test.i386 create mode 100644 test/elf/Inputs/shared.c create mode 100644 test/elf/Inputs/shared.so-x86-64 create mode 100644 test/elf/Inputs/stripped-empty.x86_64 create mode 100644 test/elf/Inputs/target-test.hexagon create mode 100644 test/elf/Inputs/target-test.ppc create mode 100644 test/elf/Inputs/tls.S create mode 100644 test/elf/Inputs/tls.c create mode 100644 test/elf/Inputs/tls.x86-64 create mode 100644 test/elf/Inputs/tlsAddr.x86-64 create mode 100644 test/elf/Inputs/tlsaddr.c create mode 100644 test/elf/Inputs/undef-from-main-so.c create mode 100644 test/elf/Inputs/undef-from-main.c create mode 100644 test/elf/Inputs/undef-pc32.o create mode 100644 test/elf/Inputs/undef.o create mode 100644 test/elf/Inputs/undef2-so.o.yaml create mode 100644 test/elf/Inputs/use-shared-32s.c create mode 100644 test/elf/Inputs/use-shared-32s.x86-64 create mode 100644 test/elf/Inputs/use-shared.c create mode 100644 test/elf/Inputs/use-shared.x86-64 create mode 100644 test/elf/Inputs/weaksym.o create mode 100644 test/elf/Inputs/writersyms.o create mode 100644 test/elf/Inputs/x86-64-relocs.S create mode 100644 test/elf/Mips/base-address-64.test create mode 100644 test/elf/Mips/base-address.test create mode 100644 test/elf/Mips/ctors-order.test create mode 100644 test/elf/Mips/dt-textrel-64.test create mode 100644 test/elf/Mips/dt-textrel.test create mode 100644 test/elf/Mips/dynlib-dynamic.test create mode 100644 test/elf/Mips/dynlib-dynsym-micro.test create mode 100644 test/elf/Mips/dynlib-dynsym.test create mode 100644 test/elf/Mips/dynlib-fileheader-64.test create mode 100644 test/elf/Mips/dynlib-fileheader-micro-64.test create mode 100644 test/elf/Mips/dynlib-fileheader-micro.test create mode 100644 test/elf/Mips/dynlib-fileheader.test create mode 100644 test/elf/Mips/dynsym-table-1.test create mode 100644 test/elf/Mips/dynsym-table-2.test create mode 100644 test/elf/Mips/e-flags-merge-1-64.test create mode 100644 test/elf/Mips/e-flags-merge-1.test create mode 100644 test/elf/Mips/e-flags-merge-10.test create mode 100644 test/elf/Mips/e-flags-merge-11.test create mode 100644 test/elf/Mips/e-flags-merge-2-64.test create mode 100644 test/elf/Mips/e-flags-merge-2.test create mode 100644 test/elf/Mips/e-flags-merge-3-64.test create mode 100644 test/elf/Mips/e-flags-merge-3.test create mode 100644 test/elf/Mips/e-flags-merge-4-64.test create mode 100644 test/elf/Mips/e-flags-merge-4.test create mode 100644 test/elf/Mips/e-flags-merge-5-64.test create mode 100644 test/elf/Mips/e-flags-merge-5.test create mode 100644 test/elf/Mips/e-flags-merge-6-64.test create mode 100644 test/elf/Mips/e-flags-merge-6.test create mode 100644 test/elf/Mips/e-flags-merge-7-64.test create mode 100644 test/elf/Mips/e-flags-merge-7.test create mode 100644 test/elf/Mips/e-flags-merge-8.test create mode 100644 test/elf/Mips/e-flags-merge-9.test create mode 100644 test/elf/Mips/entry-name.test create mode 100644 test/elf/Mips/exe-dynamic.test create mode 100644 test/elf/Mips/exe-dynsym-micro.test create mode 100644 test/elf/Mips/exe-dynsym.test create mode 100644 test/elf/Mips/exe-fileheader-64.test create mode 100644 test/elf/Mips/exe-fileheader-micro-64.test create mode 100644 test/elf/Mips/exe-fileheader-micro.test create mode 100644 test/elf/Mips/exe-fileheader.test create mode 100644 test/elf/Mips/exe-got-micro.test create mode 100644 test/elf/Mips/exe-got.test create mode 100644 test/elf/Mips/got-page-32.test create mode 100644 test/elf/Mips/got-page-64.test create mode 100644 test/elf/Mips/got16-2.test create mode 100644 test/elf/Mips/got16-micro.test create mode 100644 test/elf/Mips/got16.test create mode 100644 test/elf/Mips/gotsym.test create mode 100644 test/elf/Mips/gp-sym-1-micro.test create mode 100644 test/elf/Mips/gp-sym-1.test create mode 100644 test/elf/Mips/gp-sym-2.test create mode 100644 test/elf/Mips/hilo16-1.test create mode 100644 test/elf/Mips/hilo16-2.test create mode 100644 test/elf/Mips/hilo16-3.test create mode 100644 test/elf/Mips/hilo16-4.test create mode 100644 test/elf/Mips/hilo16-5.test create mode 100644 test/elf/Mips/hilo16-8-micro.test create mode 100644 test/elf/Mips/hilo16-9-micro.test create mode 100644 test/elf/Mips/initfini-micro.test create mode 100644 test/elf/Mips/interpreter-64.test create mode 100644 test/elf/Mips/interpreter.test create mode 100644 test/elf/Mips/invalid-reginfo.test create mode 100644 test/elf/Mips/jalx-align-err.test create mode 100644 test/elf/Mips/jump-fix-err.test create mode 100644 test/elf/Mips/la25-stub-micro.test create mode 100644 test/elf/Mips/la25-stub.test create mode 100644 test/elf/Mips/mips-options-gp0.test create mode 100644 test/elf/Mips/n64-rel-chain.test create mode 100644 test/elf/Mips/opt-emulation.test create mode 100644 test/elf/Mips/pc23-range.test create mode 100644 test/elf/Mips/plt-entry-mixed-1.test create mode 100644 test/elf/Mips/plt-entry-mixed-2.test create mode 100644 test/elf/Mips/plt-entry-mixed-3.test create mode 100644 test/elf/Mips/plt-entry-mixed-4.test create mode 100644 test/elf/Mips/plt-entry-r6.test create mode 100644 test/elf/Mips/plt-header-micro.test create mode 100644 test/elf/Mips/plt-header-mixed.test create mode 100644 test/elf/Mips/plt-header.test create mode 100644 test/elf/Mips/r26-1-micro.test create mode 100644 test/elf/Mips/r26-1.test create mode 100644 test/elf/Mips/r26-2-micro.test create mode 100644 test/elf/Mips/r26-2.test create mode 100644 test/elf/Mips/rel-32.test create mode 100644 test/elf/Mips/rel-64.test create mode 100644 test/elf/Mips/rel-copy-micro.test create mode 100644 test/elf/Mips/rel-copy-pc.test create mode 100644 test/elf/Mips/rel-copy.test create mode 100644 test/elf/Mips/rel-dynamic-01-micro.test create mode 100644 test/elf/Mips/rel-dynamic-01.test create mode 100644 test/elf/Mips/rel-dynamic-02.test create mode 100644 test/elf/Mips/rel-dynamic-03-micro.test create mode 100644 test/elf/Mips/rel-dynamic-03.test create mode 100644 test/elf/Mips/rel-dynamic-04-micro.test create mode 100644 test/elf/Mips/rel-dynamic-04.test create mode 100644 test/elf/Mips/rel-dynamic-05-micro.test create mode 100644 test/elf/Mips/rel-dynamic-05.test create mode 100644 test/elf/Mips/rel-dynamic-06-64.test create mode 100644 test/elf/Mips/rel-dynamic-06.test create mode 100644 test/elf/Mips/rel-dynamic-07-64.test create mode 100644 test/elf/Mips/rel-dynamic-07.test create mode 100644 test/elf/Mips/rel-dynamic-08-64.test create mode 100644 test/elf/Mips/rel-dynamic-08-micro.test create mode 100644 test/elf/Mips/rel-dynamic-08.test create mode 100644 test/elf/Mips/rel-dynamic-09-micro.test create mode 100644 test/elf/Mips/rel-dynamic-09.test create mode 100644 test/elf/Mips/rel-dynamic-10-micro.test create mode 100644 test/elf/Mips/rel-dynamic-10.test create mode 100644 test/elf/Mips/rel-dynamic-11.test create mode 100644 test/elf/Mips/rel-dynamic-12.test create mode 100644 test/elf/Mips/rel-gprel16.test create mode 100644 test/elf/Mips/rel-gprel32-64.test create mode 100644 test/elf/Mips/rel-gprel32.test create mode 100644 test/elf/Mips/rel-pc-hilo.test create mode 100644 test/elf/Mips/rel-pc18-s3.test create mode 100644 test/elf/Mips/rel-pc19-s2.test create mode 100644 test/elf/Mips/rel-pc21-s2.test create mode 100644 test/elf/Mips/rel-pc26-s2.test create mode 100644 test/elf/Mips/rel-pc32.test create mode 100644 test/elf/Mips/rel-pc7-10-16-23.test create mode 100644 test/elf/Mips/rel-sub.test create mode 100644 test/elf/Mips/st-other.test create mode 100644 test/elf/Mips/tls-1-micro.test create mode 100644 test/elf/Mips/tls-1.test create mode 100644 test/elf/Mips/tls-2-64.test create mode 100644 test/elf/Mips/tls-2-micro.test create mode 100644 test/elf/Mips/tls-2.test create mode 100644 test/elf/Mips/tls-3-micro.test create mode 100644 test/elf/Mips/tls-3.test create mode 100644 test/elf/Mips/tls-4-micro.test create mode 100644 test/elf/Mips/tls-4.test create mode 100644 test/elf/Mips/tls-5-64.test create mode 100644 test/elf/Mips/tls-5-micro.test create mode 100644 test/elf/Mips/tls-5.test create mode 100644 test/elf/X86_64/ExampleTarget/triple.test create mode 100644 test/elf/X86_64/Inputs/constint.c create mode 100644 test/elf/X86_64/Inputs/constint.o create mode 100644 test/elf/X86_64/Inputs/debug0.c create mode 100644 test/elf/X86_64/Inputs/debug0.x86-64 create mode 100644 test/elf/X86_64/Inputs/debug1.c create mode 100644 test/elf/X86_64/Inputs/debug1.x86-64 create mode 100644 test/elf/X86_64/Inputs/externtls.c create mode 100644 test/elf/X86_64/Inputs/externtls.x86-64 create mode 100644 test/elf/X86_64/Inputs/fn.c create mode 100644 test/elf/X86_64/Inputs/fn.o create mode 100644 test/elf/X86_64/Inputs/generaltls-so.o.yaml create mode 100644 test/elf/X86_64/Inputs/group/1.c create mode 100644 test/elf/X86_64/Inputs/group/1.o create mode 100644 test/elf/X86_64/Inputs/group/fn.c create mode 100644 test/elf/X86_64/Inputs/group/fn.o create mode 100644 test/elf/X86_64/Inputs/group/fn1.c create mode 100644 test/elf/X86_64/Inputs/group/fn1.o create mode 100644 test/elf/X86_64/Inputs/group/fn2.c create mode 100644 test/elf/X86_64/Inputs/group/fn2.o create mode 100755 test/elf/X86_64/Inputs/group/group.sh create mode 100644 test/elf/X86_64/Inputs/group/libfn.a create mode 100755 test/elf/X86_64/Inputs/group/libfn.so create mode 100644 test/elf/X86_64/Inputs/group/libfn1.a create mode 100755 test/elf/X86_64/Inputs/group/libfn2.so create mode 100644 test/elf/X86_64/Inputs/initfini-option.c create mode 100644 test/elf/X86_64/Inputs/initfini-option.o create mode 100644 test/elf/X86_64/Inputs/initfini.c create mode 100644 test/elf/X86_64/Inputs/initfini.o create mode 100644 test/elf/X86_64/Inputs/largebss.c create mode 100644 test/elf/X86_64/Inputs/largebss.o create mode 100644 test/elf/X86_64/Inputs/layoutpass/1.c create mode 100644 test/elf/X86_64/Inputs/layoutpass/1.o create mode 100644 test/elf/X86_64/Inputs/layoutpass/2.c create mode 100644 test/elf/X86_64/Inputs/layoutpass/2.o create mode 100644 test/elf/X86_64/Inputs/layoutpass/3.c create mode 100644 test/elf/X86_64/Inputs/layoutpass/3.o create mode 100644 test/elf/X86_64/Inputs/layoutpass/lib2.a create mode 100644 test/elf/X86_64/Inputs/libfn.a create mode 100755 test/elf/X86_64/Inputs/libfn.so create mode 100644 test/elf/X86_64/Inputs/main.c create mode 100644 test/elf/X86_64/Inputs/main.o create mode 100644 test/elf/X86_64/Inputs/multi-ovrd.c create mode 100644 test/elf/X86_64/Inputs/multi-ovrd.o create mode 100644 test/elf/X86_64/Inputs/multi-weak.c create mode 100644 test/elf/X86_64/Inputs/multi-weak.o create mode 100644 test/elf/X86_64/Inputs/multiweaksyms.o create mode 100644 test/elf/X86_64/Inputs/nmagic.c create mode 100644 test/elf/X86_64/Inputs/nmagic.o create mode 100644 test/elf/X86_64/Inputs/no-interp-section.c create mode 100644 test/elf/X86_64/Inputs/no-interp-section.o create mode 100644 test/elf/X86_64/Inputs/note.o create mode 100644 test/elf/X86_64/Inputs/note.s create mode 100644 test/elf/X86_64/Inputs/note_ro_rw.o create mode 100644 test/elf/X86_64/Inputs/note_ro_rw.s create mode 100644 test/elf/X86_64/Inputs/ovrd.c create mode 100644 test/elf/X86_64/Inputs/ovrd.o create mode 100644 test/elf/X86_64/Inputs/rodata.c create mode 100644 test/elf/X86_64/Inputs/rodata.o create mode 100644 test/elf/X86_64/Inputs/rodata.s create mode 100644 test/elf/X86_64/Inputs/rwint.c create mode 100644 test/elf/X86_64/Inputs/rwint.o create mode 100644 test/elf/X86_64/Inputs/sectionmap.c create mode 100644 test/elf/X86_64/Inputs/sectionmap.o create mode 100644 test/elf/X86_64/Inputs/undefcpp.c create mode 100644 test/elf/X86_64/Inputs/undefcpp.o create mode 100644 test/elf/X86_64/Inputs/weak-zero-sized.o create mode 100644 test/elf/X86_64/Inputs/weak.c create mode 100644 test/elf/X86_64/Inputs/weak.o create mode 100644 test/elf/X86_64/Inputs/weak.s create mode 100644 test/elf/X86_64/Inputs/zerosizedsection.o create mode 100644 test/elf/X86_64/Inputs/zerosizedsection.s create mode 100644 test/elf/X86_64/alignoffset.test create mode 100644 test/elf/X86_64/debug.test create mode 100644 test/elf/X86_64/defsym.test create mode 100644 test/elf/X86_64/demangle.test create mode 100644 test/elf/X86_64/dontignorezerosize-sections.test create mode 100644 test/elf/X86_64/dynamicvars.test create mode 100644 test/elf/X86_64/dynlib-nointerp-section.test create mode 100644 test/elf/X86_64/dynlib-search.test create mode 100644 test/elf/X86_64/dynsym-weak.test create mode 100644 test/elf/X86_64/extern-tls.test create mode 100644 test/elf/X86_64/general-dynamic-tls.test create mode 100644 test/elf/X86_64/imagebase.test create mode 100644 test/elf/X86_64/initfini-order.test create mode 100644 test/elf/X86_64/initfini.test create mode 100644 test/elf/X86_64/largebss.test create mode 100644 test/elf/X86_64/layoutpass-order.test create mode 100644 test/elf/X86_64/maxpagesize.test create mode 100644 test/elf/X86_64/mergesimilarstrings.test create mode 100644 test/elf/X86_64/multi-weak-layout.test create mode 100644 test/elf/X86_64/multi-weak-override.test create mode 100644 test/elf/X86_64/multi-weak-syms-order.test create mode 100644 test/elf/X86_64/nmagic.test create mode 100644 test/elf/X86_64/noalignsegments.test create mode 100644 test/elf/X86_64/note-sections-ro_plus_rw.test create mode 100644 test/elf/X86_64/note-sections.test create mode 100644 test/elf/X86_64/omagic.test create mode 100644 test/elf/X86_64/outputsegments.test create mode 100644 test/elf/X86_64/reloc_r_x86_64_16.test create mode 100644 test/elf/X86_64/reloc_r_x86_64_pc16.test create mode 100644 test/elf/X86_64/reloc_r_x86_64_pc64.test create mode 100644 test/elf/X86_64/rodata.test create mode 100644 test/elf/X86_64/sectionchoice.test create mode 100644 test/elf/X86_64/sectionmap.test create mode 100644 test/elf/X86_64/startGroupEndGroup.test create mode 100644 test/elf/X86_64/startGroupEndGroupWithDynlib.test create mode 100644 test/elf/X86_64/staticlib-search.test create mode 100644 test/elf/X86_64/undef.test create mode 100644 test/elf/X86_64/underscore-end.test create mode 100644 test/elf/X86_64/weak-override.test create mode 100644 test/elf/X86_64/weak-zero-sized.test create mode 100644 test/elf/X86_64/weaksym.test create mode 100644 test/elf/X86_64/yamlinput.test create mode 100644 test/elf/abs-dup.objtxt create mode 100644 test/elf/abs.test create mode 100644 test/elf/allowduplicates.objtxt create mode 100644 test/elf/archive-elf-forceload.test create mode 100644 test/elf/archive-elf.test create mode 100644 test/elf/as-needed.test create mode 100644 test/elf/branch.test create mode 100644 test/elf/check.test create mode 100644 test/elf/checkrodata.test create mode 100644 test/elf/common.test create mode 100644 test/elf/consecutive-weak-sym-defs.test create mode 100644 test/elf/defsym.objtxt create mode 100644 test/elf/dynamic-segorder.test create mode 100644 test/elf/dynamic-undef.test create mode 100644 test/elf/dynamic.test create mode 100644 test/elf/eh_frame_hdr.test create mode 100644 test/elf/entry.objtxt create mode 100644 test/elf/export-dynamic.test create mode 100644 test/elf/filenotfound.test create mode 100644 test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test create mode 100644 test/elf/gnulinkonce/gnulinkonce-report-undef.test create mode 100644 test/elf/gnulinkonce/gnulinkonce.test create mode 100644 test/elf/gotpcrel.test create mode 100644 test/elf/gottpoff.test create mode 100644 test/elf/group-cmd-search.test create mode 100644 test/elf/hexagon-quickdata-sort.test create mode 100644 test/elf/hexagon-quickdata-sortcommon.test create mode 100644 test/elf/ifunc.test create mode 100644 test/elf/ignore-unknownoption.test create mode 100644 test/elf/init_array-order.test create mode 100644 test/elf/init_array.test create mode 100644 test/elf/initfini-options.test-1.test create mode 100644 test/elf/initfini-options.test-2.test create mode 100644 test/elf/initfini-options.test-3.test create mode 100644 test/elf/librarynotfound.test create mode 100644 test/elf/linker-as-ld.test create mode 100644 test/elf/linkerscript/Inputs/externs.ls create mode 100644 test/elf/linkerscript/Inputs/invalid.ls create mode 100644 test/elf/linkerscript/Inputs/prog1.o.yaml create mode 100644 test/elf/linkerscript/Inputs/prog2.o.yaml create mode 100644 test/elf/linkerscript/Inputs/prog3.o.yaml create mode 100644 test/elf/linkerscript/Inputs/simple.o.yaml create mode 100644 test/elf/linkerscript/Inputs/valid.ls create mode 100644 test/elf/linkerscript/externs.objtxt create mode 100644 test/elf/linkerscript/invalid-script-cli-1.test create mode 100644 test/elf/linkerscript/invalid-script-cli-2.test create mode 100644 test/elf/linkerscript/invalid.test create mode 100644 test/elf/linkerscript/sections-order.test create mode 100644 test/elf/linkerscript/sections-with-wildcards.test create mode 100644 test/elf/linkerscript/symbol-definition.test create mode 100644 test/elf/linkerscript/valid-script-cli.objtxt create mode 100644 test/elf/loginputfiles.test create mode 100644 test/elf/mergeatoms.test create mode 100644 test/elf/mergeconstants.test create mode 100644 test/elf/mergeglobalatoms.test create mode 100644 test/elf/note.test create mode 100644 test/elf/options/dynamic-linker.test create mode 100644 test/elf/phdr.test create mode 100644 test/elf/quickdata.test create mode 100644 test/elf/reloc.test create mode 100644 test/elf/responsefile.test create mode 100644 test/elf/rodata.test create mode 100644 test/elf/rosegment.test create mode 100644 test/elf/sectionGroups/sectiongroup-new-members.test create mode 100644 test/elf/sectionGroups/sectiongroup-simple.test create mode 100644 test/elf/sectionGroups/sectiongroup-undef-member-other.test create mode 100644 test/elf/sectionGroups/sectiongroup-undef-member.test create mode 100644 test/elf/sectionGroups/sectiongroup-with-globalsymbols.test create mode 100644 test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test create mode 100644 test/elf/sectionGroups/sectiongroup-with-undef-signature.test create mode 100644 test/elf/sections.test create mode 100644 test/elf/sh_addralign.test create mode 100644 test/elf/soname.test create mode 100644 test/elf/strip-all.test create mode 100644 test/elf/stripped-empty.test create mode 100644 test/elf/symbols.test create mode 100644 test/elf/tls.test create mode 100644 test/elf/tlsAddr.test create mode 100644 test/elf/undef-from-dso-to-main.test create mode 100644 test/elf/undef-from-main-dso.test create mode 100644 test/elf/weaksym.test create mode 100644 test/elf/wrap.test create mode 100644 test/elf/x86-64-dynamic-relocs.test create mode 100644 test/elf/x86-64-dynamic.test create mode 100644 test/elf/x86.test create mode 100644 test/elf/x86_64-kinds.test create mode 100644 test/lit.cfg create mode 100644 test/lit.site.cfg.in create mode 100755 test/mach-o/Inputs/DependencyDump.py create mode 100644 test/mach-o/Inputs/bar.yaml create mode 100644 test/mach-o/Inputs/exported_symbols_list.exp create mode 100644 test/mach-o/Inputs/full.filelist create mode 100755 test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib create mode 100644 test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a create mode 100644 test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o create mode 100644 test/mach-o/Inputs/libSystem.yaml create mode 100644 test/mach-o/Inputs/libbar.a create mode 100644 test/mach-o/Inputs/libfoo.a create mode 100644 test/mach-o/Inputs/order_file-basic.order create mode 100644 test/mach-o/Inputs/partial.filelist create mode 100644 test/mach-o/Inputs/use-dylib-install-names.yaml create mode 100644 test/mach-o/PIE.yaml create mode 100644 test/mach-o/align_text.yaml create mode 100644 test/mach-o/arm-interworking-movw.yaml create mode 100644 test/mach-o/arm-interworking.yaml create mode 100644 test/mach-o/arm-shims.yaml create mode 100644 test/mach-o/arm-subsections-via-symbols.yaml create mode 100644 test/mach-o/cstring-sections.yaml create mode 100644 test/mach-o/data-only-dylib.yaml create mode 100644 test/mach-o/demangle.yaml create mode 100644 test/mach-o/dependency_info.yaml create mode 100644 test/mach-o/dso_handle.yaml create mode 100644 test/mach-o/dylib-exports.yaml create mode 100644 test/mach-o/dylib-install-names.yaml create mode 100644 test/mach-o/exe-offsets.yaml create mode 100644 test/mach-o/exe-segment-overlap.yaml create mode 100644 test/mach-o/exported_symbols_list-dylib.yaml create mode 100644 test/mach-o/exported_symbols_list-obj.yaml create mode 100644 test/mach-o/exported_symbols_list-undef.yaml create mode 100644 test/mach-o/fat-archive.yaml create mode 100644 test/mach-o/filelist.yaml create mode 100644 test/mach-o/force_load-dylib.yaml create mode 100644 test/mach-o/force_load-x86_64.yaml create mode 100644 test/mach-o/framework-user-paths.yaml create mode 100644 test/mach-o/got-order.yaml create mode 100644 test/mach-o/hello-world-arm64.yaml create mode 100644 test/mach-o/hello-world-armv6.yaml create mode 100644 test/mach-o/hello-world-armv7.yaml create mode 100644 test/mach-o/hello-world-x86.yaml create mode 100644 test/mach-o/hello-world-x86_64.yaml create mode 100644 test/mach-o/image-base.yaml create mode 100644 test/mach-o/infer-arch.yaml create mode 100644 test/mach-o/interposing-section.yaml create mode 100644 test/mach-o/keep_private_externs.yaml create mode 100644 test/mach-o/lazy-bind-x86_64.yaml create mode 100644 test/mach-o/lib-search-paths.yaml create mode 100644 test/mach-o/library-order.yaml create mode 100644 test/mach-o/library-rescan.yaml create mode 100644 test/mach-o/libresolve-bizarre-root-override.yaml create mode 100644 test/mach-o/libresolve-multiple-syslibroots.yaml create mode 100644 test/mach-o/libresolve-one-syslibroot.yaml create mode 100644 test/mach-o/libresolve-simple.yaml create mode 100644 test/mach-o/libresolve-user-paths.yaml create mode 100644 test/mach-o/libresolve-z.yaml create mode 100644 test/mach-o/linker-as-ld.yaml create mode 100644 test/mach-o/lit.local.cfg create mode 100644 test/mach-o/mh_bundle_header.yaml create mode 100644 test/mach-o/mh_dylib_header.yaml create mode 100644 test/mach-o/objc_export_list.yaml create mode 100644 test/mach-o/order_file-basic.yaml create mode 100644 test/mach-o/parse-aliases.yaml create mode 100644 test/mach-o/parse-arm-relocs.yaml create mode 100644 test/mach-o/parse-cfstring32.yaml create mode 100644 test/mach-o/parse-cfstring64.yaml create mode 100644 test/mach-o/parse-compact-unwind32.yaml create mode 100644 test/mach-o/parse-compact-unwind64.yaml create mode 100644 test/mach-o/parse-data-in-code-armv7.yaml create mode 100644 test/mach-o/parse-data-in-code-x86.yaml create mode 100644 test/mach-o/parse-data-relocs-arm64.yaml create mode 100644 test/mach-o/parse-data-relocs-x86_64.yaml create mode 100644 test/mach-o/parse-data.yaml create mode 100644 test/mach-o/parse-eh-frame-x86-anon.yaml create mode 100644 test/mach-o/parse-eh-frame-x86-labeled.yaml create mode 100644 test/mach-o/parse-eh-frame.yaml create mode 100644 test/mach-o/parse-function.yaml create mode 100644 test/mach-o/parse-initializers32.yaml create mode 100644 test/mach-o/parse-initializers64.yaml create mode 100644 test/mach-o/parse-literals-error.yaml create mode 100644 test/mach-o/parse-literals.yaml create mode 100644 test/mach-o/parse-non-lazy-pointers.yaml create mode 100644 test/mach-o/parse-relocs-x86.yaml create mode 100644 test/mach-o/parse-section-no-symbol.yaml create mode 100644 test/mach-o/parse-tentative-defs.yaml create mode 100644 test/mach-o/parse-text-relocs-arm64.yaml create mode 100644 test/mach-o/parse-text-relocs-x86_64.yaml create mode 100644 test/mach-o/re-exported-dylib-ordinal.yaml create mode 100644 test/mach-o/rpath.yaml create mode 100644 test/mach-o/sectalign.yaml create mode 100644 test/mach-o/unwind-info-simple-arm64.yaml create mode 100644 test/mach-o/unwind-info-simple-x86_64.yaml create mode 100644 test/mach-o/upward-dylib-load-command.yaml create mode 100644 test/mach-o/upward-dylib-paths.yaml create mode 100644 test/mach-o/usage.yaml create mode 100644 test/mach-o/use-simple-dylib.yaml create mode 100644 test/mach-o/write-final-sections.yaml create mode 100644 test/mach-o/wrong-arch-error.yaml create mode 100644 test/pecoff/Inputs/abs.obj.yaml create mode 100644 test/pecoff/Inputs/alignment.obj.yaml create mode 100644 test/pecoff/Inputs/alternatename1.obj.yaml create mode 100644 test/pecoff/Inputs/alternatename2.obj.yaml create mode 100644 test/pecoff/Inputs/alternatename3.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-ImageBase.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-ImageBase.s create mode 100644 test/pecoff/Inputs/armnt-addr32-exec.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-addr32-exec.s create mode 100644 test/pecoff/Inputs/armnt-addr32.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-addr32.s create mode 100644 test/pecoff/Inputs/armnt-blx23t.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-blx23t.s create mode 100644 test/pecoff/Inputs/armnt-branch24t.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-branch24t.s create mode 100644 test/pecoff/Inputs/armnt-exports.def create mode 100644 test/pecoff/Inputs/armnt-exports.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-import.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-import.s create mode 100644 test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-mov32t-exec.s create mode 100644 test/pecoff/Inputs/armnt-mov32t.obj.yaml create mode 100644 test/pecoff/Inputs/armnt-mov32t.s create mode 100644 test/pecoff/Inputs/armnt-obj.s create mode 100644 test/pecoff/Inputs/armnt-obj.yaml create mode 100644 test/pecoff/Inputs/associative1.obj.yaml create mode 100644 test/pecoff/Inputs/associative3.obj.yaml create mode 100644 test/pecoff/Inputs/basereloc.obj.yaml create mode 100644 test/pecoff/Inputs/bss.asm create mode 100644 test/pecoff/Inputs/bss.obj create mode 100644 test/pecoff/Inputs/comdat.obj.yaml create mode 100644 test/pecoff/Inputs/common-symbol.obj.yaml create mode 100644 test/pecoff/Inputs/drectve.obj.yaml create mode 100644 test/pecoff/Inputs/drectve2.obj.yaml create mode 100644 test/pecoff/Inputs/drectve3.lib create mode 100644 test/pecoff/Inputs/entry.obj.yaml create mode 100644 test/pecoff/Inputs/executable.obj.yaml create mode 100644 test/pecoff/Inputs/executable.s create mode 100644 test/pecoff/Inputs/export.obj.yaml create mode 100644 test/pecoff/Inputs/exports.def create mode 100644 test/pecoff/Inputs/exports2.def create mode 100644 test/pecoff/Inputs/grouped-sections.asm create mode 100644 test/pecoff/Inputs/grouped-sections.obj.yaml create mode 100644 test/pecoff/Inputs/hello.asm create mode 100644 test/pecoff/Inputs/hello.obj.yaml create mode 100644 test/pecoff/Inputs/hello64.asm create mode 100644 test/pecoff/Inputs/hello64.obj.yaml create mode 100644 test/pecoff/Inputs/hello64lib.asm create mode 100644 test/pecoff/Inputs/hello64lib.lib create mode 100644 test/pecoff/Inputs/imagebase.obj.yaml create mode 100755 test/pecoff/Inputs/library.lib create mode 100644 test/pecoff/Inputs/machine-type-unknown.obj.yaml create mode 100644 test/pecoff/Inputs/main.obj.yaml create mode 100644 test/pecoff/Inputs/merge-largest1.obj.yaml create mode 100644 test/pecoff/Inputs/merge-largest2.obj.yaml create mode 100644 test/pecoff/Inputs/merge-same-size1.obj.yaml create mode 100644 test/pecoff/Inputs/merge-same-size2.obj.yaml create mode 100644 test/pecoff/Inputs/merge-same-size3.obj.yaml create mode 100644 test/pecoff/Inputs/nonstandard-sections.obj.yaml create mode 100644 test/pecoff/Inputs/nop.asm create mode 100644 test/pecoff/Inputs/nop.obj.yaml create mode 100644 test/pecoff/Inputs/nop64.obj.yaml create mode 100644 test/pecoff/Inputs/reloc.obj.yaml create mode 100644 test/pecoff/Inputs/reloc64.obj.yaml create mode 100644 test/pecoff/Inputs/resource.rc create mode 100755 test/pecoff/Inputs/resource.res create mode 100644 test/pecoff/Inputs/responsefile.txt create mode 100644 test/pecoff/Inputs/secrel1.obj.yaml create mode 100644 test/pecoff/Inputs/secrel2.obj.yaml create mode 100644 test/pecoff/Inputs/seh.c create mode 100644 test/pecoff/Inputs/seh.obj.yaml create mode 100644 test/pecoff/Inputs/static-data1.obj.yaml create mode 100644 test/pecoff/Inputs/static-data2.obj.yaml create mode 100644 test/pecoff/Inputs/static.lib create mode 100644 test/pecoff/Inputs/subsystem.main.yaml create mode 100644 test/pecoff/Inputs/subsystem.winmain.yaml create mode 100644 test/pecoff/Inputs/tlsused.obj.yaml create mode 100644 test/pecoff/Inputs/unknown-drectve.obj.yaml create mode 100644 test/pecoff/Inputs/unwind.obj.yaml create mode 100644 test/pecoff/Inputs/vars-main-x64.obj.yaml create mode 100644 test/pecoff/Inputs/vars-main-x86.obj.yaml create mode 100644 test/pecoff/Inputs/vars-main.c create mode 100644 test/pecoff/Inputs/vars.c create mode 100644 test/pecoff/Inputs/vars.dll.yaml create mode 100644 test/pecoff/Inputs/vars.lib create mode 100644 test/pecoff/Inputs/vars64.lib create mode 100644 test/pecoff/Inputs/weak-externals.asm create mode 100644 test/pecoff/Inputs/weak-externals.obj.yaml create mode 100644 test/pecoff/alignment.test create mode 100644 test/pecoff/alternatename.test create mode 100644 test/pecoff/armnt-ImageBase.test create mode 100644 test/pecoff/armnt-addr32-exec.test create mode 100644 test/pecoff/armnt-addr32.test create mode 100644 test/pecoff/armnt-address-of-entry-point.test create mode 100644 test/pecoff/armnt-blx23t.test create mode 100644 test/pecoff/armnt-branch24t.test create mode 100644 test/pecoff/armnt-exports.s create mode 100644 test/pecoff/armnt-exports.test create mode 100644 test/pecoff/armnt-imports.test create mode 100644 test/pecoff/armnt-mov32t-exec.test create mode 100644 test/pecoff/armnt-movt32t.test create mode 100644 test/pecoff/armnt.test create mode 100644 test/pecoff/associative.test create mode 100644 test/pecoff/base-reloc.test create mode 100644 test/pecoff/baseaddr.test create mode 100644 test/pecoff/bss-section.test create mode 100644 test/pecoff/comdat.test create mode 100644 test/pecoff/common-symbol.test create mode 100644 test/pecoff/conflicting-machine.test create mode 100644 test/pecoff/delayimport.test create mode 100644 test/pecoff/dll.test create mode 100644 test/pecoff/dosstub.test create mode 100644 test/pecoff/drectve.test create mode 100644 test/pecoff/dynamic.test create mode 100644 test/pecoff/dynamicbase.test create mode 100644 test/pecoff/entry.test create mode 100644 test/pecoff/export-warning.test create mode 100644 test/pecoff/export.test create mode 100644 test/pecoff/exportlib.test create mode 100644 test/pecoff/exportlib2.test create mode 100644 test/pecoff/grouped-sections.test create mode 100644 test/pecoff/hello.test create mode 100644 test/pecoff/hello64.test create mode 100644 test/pecoff/help.test create mode 100644 test/pecoff/imagebase.test create mode 100644 test/pecoff/importlib.test create mode 100644 test/pecoff/include.test create mode 100644 test/pecoff/lib.test create mode 100644 test/pecoff/libarg.test create mode 100644 test/pecoff/localyimported.test create mode 100644 test/pecoff/long-section-name.test create mode 100644 test/pecoff/machinetype.test create mode 100644 test/pecoff/manifest.test create mode 100644 test/pecoff/merge-largest.test create mode 100644 test/pecoff/merge-same-size.test create mode 100644 test/pecoff/multi.test create mode 100644 test/pecoff/noentry.test create mode 100644 test/pecoff/nonstandard-sections.test create mode 100644 test/pecoff/options.test create mode 100644 test/pecoff/pe32plus.test create mode 100644 test/pecoff/reloc.test create mode 100644 test/pecoff/reloc64.test create mode 100644 test/pecoff/resource.test create mode 100644 test/pecoff/responsefile.test create mode 100644 test/pecoff/safeseh.test create mode 100644 test/pecoff/secrel.test create mode 100644 test/pecoff/section-attribute.test create mode 100644 test/pecoff/section-renaming.test create mode 100644 test/pecoff/seh.test create mode 100644 test/pecoff/seh64.test create mode 100644 test/pecoff/subsystem.test create mode 100644 test/pecoff/tls.test create mode 100644 test/pecoff/trivial.test create mode 100644 test/pecoff/unknown-drectve.test create mode 100644 test/pecoff/weak-external.test create mode 100644 tools/CMakeLists.txt create mode 100644 tools/Makefile create mode 100644 tools/linker-script-test/CMakeLists.txt create mode 100644 tools/linker-script-test/Makefile create mode 100644 tools/linker-script-test/linker-script-test.cpp create mode 100644 tools/lld/CMakeLists.txt create mode 100644 tools/lld/Makefile create mode 100644 tools/lld/TODO.txt create mode 100644 tools/lld/lld.cpp create mode 100644 unittests/CMakeLists.txt create mode 100644 unittests/CoreTests/CMakeLists.txt create mode 100644 unittests/CoreTests/Makefile create mode 100644 unittests/CoreTests/ParallelTest.cpp create mode 100644 unittests/CoreTests/RangeTest.cpp create mode 100644 unittests/DriverTests/CMakeLists.txt create mode 100644 unittests/DriverTests/DarwinLdDriverTest.cpp create mode 100644 unittests/DriverTests/DriverTest.h create mode 100644 unittests/DriverTests/GnuLdDriverTest.cpp create mode 100644 unittests/DriverTests/Makefile create mode 100644 unittests/DriverTests/UniversalDriverTest.cpp create mode 100644 unittests/DriverTests/WinLinkDriverTest.cpp create mode 100644 unittests/DriverTests/WinLinkModuleDefTest.cpp create mode 100644 unittests/MachOTests/CMakeLists.txt create mode 100644 unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp create mode 100644 unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp create mode 100644 unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp create mode 100644 unittests/MachOTests/MachONormalizedFileYAMLTests.cpp create mode 100644 unittests/MachOTests/empty_obj_x86_armv7.txt create mode 100644 unittests/Makefile create mode 100644 utils/astyle-options diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 000000000000..787b339a9f20 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "project_id" : "lld", + "conduit_uri" : "http://reviews.llvm.org/" +} diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000000..9b3aa8b7213b --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: LLVM diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..0a288ee8ce96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +#==============================================================================# +# This file specifies intentionally untracked files that git should ignore. +# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html +#==============================================================================# + +#==============================================================================# +# File extensions to be ignored anywhere in the tree. +#==============================================================================# +# Temp files created by most text editors. +*~ +# Merge files created by git. +*.orig +# Byte compiled python modules. +*.pyc +# vim swap files +.*.swp +# Mac OS X Finder layout info +.DS_Store + +#==============================================================================# +# Directories to be ignored. +#==============================================================================# +# Sphinx build files. +docs/_build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000000..30ef47a692d2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,98 @@ +set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +# Compute the LLD version from the LLVM version. +string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION + ${PACKAGE_VERSION}) +message(STATUS "LLD version: ${LLD_VERSION}") + +string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR + ${LLD_VERSION}) +string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR + ${LLD_VERSION}) + +# Determine LLD revision and repository. +# TODO: Figure out a way to get the revision and the repository on windows. +if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" ) + execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR} + OUTPUT_VARIABLE LLD_REVISION) + + execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR} + OUTPUT_VARIABLE LLD_REPOSITORY) + if ( LLD_REPOSITORY ) + # Replace newline characters with spaces + string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY}) + # Remove leading spaces + STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" ) + # Remove trailing spaces + string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY}) + endif() + + if ( LLD_REVISION ) + # Replace newline characters with spaces + string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION}) + # Remove leading spaces + STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" ) + # Remove trailing spaces + string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION}) + endif() +endif () + +# Configure the Version.inc file. +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Config/Version.inc.in + ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Config/Version.inc) + + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite " +"the makefiles distributed with LLVM. Please create a directory and run cmake " +"from there, passing the path to this source directory as the last argument. " +"This process created the file `CMakeCache.txt' and the directory " +"`CMakeFiles'. Please delete them.") +endif() + +list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules") + +option(LLD_USE_VTUNE + "Enable VTune user task tracking." + OFF) +if (LLD_USE_VTUNE) + find_package(VTune) + if (VTUNE_FOUND) + include_directories(${VTune_INCLUDE_DIRS}) + list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES}) + add_definitions(-DLLD_HAS_VTUNE) + endif() +endif() + + +if (MSVC) + add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.' + add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header. +endif() + +include_directories(BEFORE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include + ) + +if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + install(DIRECTORY include/ + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN ".svn" EXCLUDE + ) +endif() + +add_subdirectory(lib) +add_subdirectory(tools) + +add_subdirectory(test) + +if (LLVM_INCLUDE_TESTS) + add_subdirectory(unittests) +endif() + +add_subdirectory(docs) diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 000000000000..bcb83b211422 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,62 @@ +============================================================================== +lld License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2011-2015 by the contributors listed in CREDITS.TXT +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +The lld software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the lld Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- + diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..e1b6a678fc23 --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +##===- Makefile --------------------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +# If LLD_LEVEL is not set, then we are the top-level Makefile. Otherwise, we +# are being included from a subdirectory makefile. + +ifndef LLD_LEVEL + +IS_TOP_LEVEL := 1 +LLD_LEVEL := . +DIRS := include lib tools unittests + +PARALLEL_DIRS := + +endif + +ifeq ($(MAKECMDGOALS),libs-only) + DIRS := $(filter-out tools docs, $(DIRS)) + OPTIONAL_DIRS := +endif +ifeq ($(BUILD_LLD_ONLY),YES) + DIRS := $(filter-out docs unittests, $(DIRS)) + OPTIONAL_DIRS := +endif + +### +# Common Makefile code, shared by all lld Makefiles. + +# Set LLVM source root level. +LEVEL := $(LLD_LEVEL)/../.. + +# Include LLVM common makefile. +include $(LEVEL)/Makefile.common + +ifneq ($(ENABLE_DOCS),1) + DIRS := $(filter-out docs, $(DIRS)) +endif + +CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/include +CPP.Flags += -I$(PROJ_OBJ_DIR)/$(LLD_LEVEL)/include + +### +# lld Top Level specific stuff. + +ifeq ($(IS_TOP_LEVEL),1) + +ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) +$(RecursiveTargets):: + $(Verb) for dir in test unittests; do \ + if [ -f $(PROJ_SRC_DIR)/$${dir}/Makefile ] && [ ! -f $${dir}/Makefile ]; then \ + $(MKDIR) $${dir}; \ + $(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \ + fi \ + done +endif + +test:: + @ $(MAKE) -C test + +report:: + @ $(MAKE) -C test report + +clean:: + @ $(MAKE) -C test clean + +libs-only: all + +tags:: + $(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \ + grep -v /lib/Headers | grep -v /test/` + +cscope.files: + find tools lib include -name '*.cpp' \ + -or -name '*.def' \ + -or -name '*.td' \ + -or -name '*.h' > cscope.files + +.PHONY: test report clean cscope.files + +endif diff --git a/README.md b/README.md new file mode 100644 index 000000000000..dc05cdea0a12 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ + +LLVM Linker (lld) +============================== + +This directory and its subdirectories contain source code for the LLVM Linker, a +modular cross platform linker which is built as part of the LLVM compiler +infrastructure project. + +lld is open source software. You may freely distribute it under the terms of +the license agreement found in LICENSE.txt. diff --git a/cmake/modules/FindVTune.cmake b/cmake/modules/FindVTune.cmake new file mode 100644 index 000000000000..bd0cbe9a38cb --- /dev/null +++ b/cmake/modules/FindVTune.cmake @@ -0,0 +1,31 @@ +# - Find VTune ittnotify. +# Defines: +# VTune_FOUND +# VTune_INCLUDE_DIRS +# VTune_LIBRARIES + +set(dirs + "$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/" + "C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/" + "$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/" + "C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/" + ) + +find_path(VTune_INCLUDE_DIRS ittnotify.h + PATHS ${dirs} + PATH_SUFFIXES include) + +if (CMAKE_SIZEOF_VOID_P MATCHES "8") + set(vtune_lib_dir lib64) +else() + set(vtune_lib_dir lib32) +endif() + +find_library(VTune_LIBRARIES libittnotify + HINTS "${VTune_INCLUDE_DIRS}/.." + PATHS ${dirs} + PATH_SUFFIXES ${vtune_lib_dir}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS) diff --git a/docs/C++11.rst b/docs/C++11.rst new file mode 100644 index 000000000000..0c4391e7b037 --- /dev/null +++ b/docs/C++11.rst @@ -0,0 +1,9 @@ +C++11 +===== + +Originally, LLD was developed in C++11 unlike the rest of LLVM. Now, all of +LLVM, LLD, and Clang are developed using C++11. See the `LLVM Coding +Standards`_ for details on the precise subset of C++11 supported by the various +host compilers. + +.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 000000000000..d4f3b058efb7 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,8 @@ +if (LLVM_ENABLE_SPHINX) + if (SPHINX_FOUND) + include(AddSphinxTarget) + if (${SPHINX_OUTPUT_HTML}) + add_sphinx_target(html lld) + endif() + endif() +endif() diff --git a/docs/Driver.rst b/docs/Driver.rst new file mode 100644 index 000000000000..5f2d946d36bd --- /dev/null +++ b/docs/Driver.rst @@ -0,0 +1,79 @@ +====== +Driver +====== + +.. contents:: + :local: + +Introduction +============ + +This document describes the lld driver. The purpose of this document is to +describe both the motivation and design goals for the driver, as well as details +of the internal implementation. + +Overview +======== + +The lld driver is designed to support a number of different command line +interfaces. The main interfaces we plan to support are binutils' ld, Apple's +ld, and Microsoft's link.exe. + +Flavors +------- + +Each of these different interfaces is referred to as a flavor. There is also an +extra flavor "core" which is used to exercise the core functionality of the +linker it the test suite. + +* gnu +* darwin +* link +* core + +Selecting a Flavor +^^^^^^^^^^^^^^^^^^ + +There are two different ways to tell lld which flavor to be. They are checked in +order, so the second overrides the first. The first is to symlink :program:`lld` +as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify +it as the first command line argument using ``-flavor``:: + + $ lld -flavor gnu + +There is a shortcut for ``-flavor core`` as ``-core``. + + +Adding an Option to an existing Flavor +====================================== + +#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`. + +#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method + for the option. + +#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file: + `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter + for corresponding to the option. + +#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option. + + +Adding a Flavor +=============== + +#. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to + :cpp:class:`lld::UniversalDriver::Flavor`. + +#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to + :cpp:func:`lld::Driver::strToFlavor` and + :cpp:func:`lld::UniversalDriver::link`. + This allows the flavor to be selected via symlink and :option:`-flavor`. + +#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that + describes the options. If the options are a superset of another driver, that + driver's td file can simply be included. The :file:`{flavor}Options.td` file + must also be added to :file:`lib/Driver/CMakeLists.txt`. + +#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver` + in :file:`lib/Driver/{flavor}Driver.cpp`. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000000..4c147eb11137 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,155 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +all: html + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lld.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lld.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/lld" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lld" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/README.txt b/docs/README.txt new file mode 100644 index 000000000000..eb09a2d2b7ea --- /dev/null +++ b/docs/README.txt @@ -0,0 +1,12 @@ +lld Documentation +================= + +The lld documentation is written using the Sphinx documentation generator. It is +currently tested with Sphinx 1.1.3. + +We currently use the 'nature' theme and a Beaker inspired structure. + +To rebuild documents into html: + + [/lld/docs]> make html + diff --git a/docs/Readers.rst b/docs/Readers.rst new file mode 100644 index 000000000000..e00406b8c4ce --- /dev/null +++ b/docs/Readers.rst @@ -0,0 +1,172 @@ +.. _Readers: + +Developing lld Readers +====================== + +Introduction +------------ + +The purpose of a "Reader" is to take an object file in a particular format +and create an `lld::File`:cpp:class: (which is a graph of Atoms) +representing the object file. A Reader inherits from +`lld::Reader`:cpp:class: which lives in +:file:`include/lld/Core/Reader.h` and +:file:`lib/Core/Reader.cpp`. + +The Reader infrastructure for an object format ``Foo`` requires the +following pieces in order to fit into lld: + +:file:`include/lld/ReaderWriter/ReaderFoo.h` + + .. cpp:class:: ReaderOptionsFoo : public ReaderOptions + + This Options class is the only way to configure how the Reader will + parse any file into an `lld::Reader`:cpp:class: object. This class + should be declared in the `lld`:cpp:class: namespace. + + .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader) + + This factory function configures and create the Reader. This function + should be declared in the `lld`:cpp:class: namespace. + +:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp` + + .. cpp:class:: ReaderFoo : public Reader + + This is the concrete Reader class which can be called to parse + object files. It should be declared in an anonymous namespace or + if there is shared code with the `lld::WriterFoo`:cpp:class: you + can make a nested namespace (e.g. `lld::foo`:cpp:class:). + +You may have noticed that :cpp:class:`ReaderFoo` is not declared in the +``.h`` file. An important design aspect of lld is that all Readers are +created *only* through an object-format-specific +:cpp:func:`createReaderFoo` factory function. The creation of the Reader is +parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options +class is the one-and-only way to control how the Reader operates when +parsing an input file into an Atom graph. For instance, you may want the +Reader to only accept certain architectures. The options class can be +instantiated from command line options or be programmatically configured. + +Where to start +-------------- + +The lld project already has a skeleton of source code for Readers for +``ELF``, ``PECOFF``, ``MachO``, and lld's native Atom graph format +(both binary ``Native`` and ``YAML`` representations). If your file format +is a variant of one of those, you should modify the existing Reader to +support your variant. This is done by customizing the Options +class for the Reader and making appropriate changes to the ``.cpp`` file to +interpret those options and act accordingly. + +If your object file format is not a variant of any existing Reader, you'll need +to create a new Reader subclass with the organization described above. + +Readers are factories +--------------------- + +The linker will usually only instantiate your Reader once. That one Reader will +have its loadFile() method called many times with different input files. +To support multithreaded linking, the Reader may be parsing multiple input +files in parallel. Therefore, there should be no parsing state in you Reader +object. Any parsing state should be in ivars of your File subclass or in +some temporary object. + +The key method to implement in a reader is:: + + virtual error_code loadFile(LinkerInput &input, + std::vector> &result); + +It takes a memory buffer (which contains the contents of the object file +being read) and returns an instantiated lld::File object which is +a collection of Atoms. The result is a vector of File pointers (instead of +simple a File pointer) because some file formats allow multiple object +"files" to be encoded in one file system file. + + +Memory Ownership +---------------- + +Atoms are always owned by their File object. During core linking when Atoms +are coalesced or stripped away, core linking does not delete them. +Core linking just removes those unused Atoms from its internal list. +The destructor of a File object is responsible for deleting all Atoms it +owns, and if ownership of the MemoryBuffer was passed to it, the File +destructor needs to delete that too. + +Making Atoms +------------ + +The internal model of lld is purely Atom based. But most object files do not +have an explicit concept of Atoms, instead most have "sections". The way +to think of this is that a section is just a list of Atoms with common +attributes. + +The first step in parsing section-based object files is to cleave each +section into a list of Atoms. The technique may vary by section type. For +code sections (e.g. .text), there are usually symbols at the start of each +function. Those symbol addresses are the points at which the section is +cleaved into discrete Atoms. Some file formats (like ELF) also include the +length of each symbol in the symbol table. Otherwise, the length of each +Atom is calculated to run to the start of the next symbol or the end of the +section. + +Other sections types can be implicitly cleaved. For instance c-string literals +or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at +the content of the section. It is important to cleave sections into Atoms +to remove false dependencies. For instance the .eh_frame section often +has no symbols, but contains "pointers" to the functions for which it +has unwind info. If the .eh_frame section was not cleaved (but left as one +big Atom), there would always be a reference (from the eh_frame Atom) to +each function. So the linker would be unable to coalesce or dead stripped +away the function atoms. + +The lld Atom model also requires that a reference to an undefined symbol be +modeled as a Reference to an UndefinedAtom. So the Reader also needs to +create an UndefinedAtom for each undefined symbol in the object file. + +Once all Atoms have been created, the second step is to create References +(recall that Atoms are "nodes" and References are "edges"). Most References +are created by looking at the "relocation records" in the object file. If +a function contains a call to "malloc", there is usually a relocation record +specifying the address in the section and the symbol table index. Your +Reader will need to convert the address to an Atom and offset and the symbol +table index into a target Atom. If "malloc" is not defined in the object file, +the target Atom of the Reference will be an UndefinedAtom. + + +Performance +----------- +Once you have the above working to parse an object file into Atoms and +References, you'll want to look at performance. Some techniques that can +help performance are: + +* Use llvm::BumpPtrAllocator or pre-allocate one big vector and then + just have each atom point to its subrange of References in that vector. + This can be faster that allocating each Reference as separate object. +* Pre-scan the symbol table and determine how many atoms are in each section + then allocate space for all the Atom objects at once. +* Don't copy symbol names or section content to each Atom, instead use + StringRef and ArrayRef in each Atom to point to its name and content in the + MemoryBuffer. + + +Testing +------- + +We are still working on infrastructure to test Readers. The issue is that +you don't want to check in binary files to the test suite. And the tools +for creating your object file from assembly source may not be available on +every OS. + +We are investigating a way to use YAML to describe the section, symbols, +and content of a file. Then have some code which will write out an object +file from that YAML description. + +Once that is in place, you can write test cases that contain section/symbols +YAML and is run through the linker to produce Atom/References based YAML which +is then run through FileCheck to verify the Atoms and References are as +expected. + + + diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico new file mode 100644 index 000000000000..724ad6e12dd4 Binary files /dev/null and b/docs/_static/favicon.ico differ diff --git a/docs/_templates/indexsidebar.html b/docs/_templates/indexsidebar.html new file mode 100644 index 000000000000..61968f22d5c5 --- /dev/null +++ b/docs/_templates/indexsidebar.html @@ -0,0 +1,4 @@ +

Bugs

+ +

lld bugs should be reported at the + LLVM Bugzilla.

diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 index 000000000000..519a24bce63a --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,12 @@ +{% extends "!layout.html" %} + +{% block extrahead %} + +{% endblock %} + +{% block rootrellink %} +
  • lld Home | 
  • +{% endblock %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000000..99866e1bd1e1 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- +# +# lld documentation build configuration file. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'lld' +copyright = u'2011-2014, LLVM Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3.2' +# The full version, including alpha/beta/rc tags. +release = '3.2' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'friendly' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'llvm-theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ["."] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# If given, this must be the name of an image file (path relative to the +# configuration directory) that is the favicon of the docs. Modern browsers use +# this as icon for tabs, windows and bookmarks. It should be a Windows-style +# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None. The +# image file will be copied to the _static directory of the output HTML, but +# only if the file does not already exist there. +html_favicon = '_static/favicon.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%Y-%m-%d' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +html_sidebars = {'index': 'indexsidebar.html'} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {'index': 'index.html'} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'llddoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('contents', 'lld.tex', u'lld Documentation', + u'LLVM project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('contents', 'lld', u'lld Documentation', + [u'LLVM project'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('contents', 'lld', u'lld Documentation', + u'LLVM project', 'lld', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# FIXME: Define intersphinx configration. +intersphinx_mapping = {} + + +# -- Options for extensions ---------------------------------------------------- + +# Enable this if you want TODOs to show up in the generated documentation. +todo_include_todos = True diff --git a/docs/design.rst b/docs/design.rst new file mode 100644 index 000000000000..06d356527f58 --- /dev/null +++ b/docs/design.rst @@ -0,0 +1,500 @@ +.. _design: + +Linker Design +============= + +Introduction +------------ + +lld is a new generation of linker. It is not "section" based like traditional +linkers which mostly just interlace sections from multiple object files into the +output file. Instead, lld is based on "Atoms". Traditional section based +linking work well for simple linking, but their model makes advanced linking +features difficult to implement. Features like dead code stripping, reordering +functions for locality, and C++ coalescing require the linker to work at a finer +grain. + +An atom is an indivisible chunk of code or data. An atom has a set of +attributes, such as: name, scope, content-type, alignment, etc. An atom also +has a list of References. A Reference contains: a kind, an optional offset, an +optional addend, and an optional target atom. + +The Atom model allows the linker to use standard graph theory models for linking +data structures. Each atom is a node, and each Reference is an edge. The +feature of dead code stripping is implemented by following edges to mark all +live atoms, and then delete the non-live atoms. + + +Atom Model +---------- + +An atom is an indivisible chunk of code or data. Typically each user written +function or global variable is an atom. In addition, the compiler may emit +other atoms, such as for literal c-strings or floating point constants, or for +runtime data structures like dwarf unwind info or pointers to initializers. + +A simple "hello world" object file would be modeled like this: + +.. image:: hello.png + +There are three atoms: main, a proxy for printf, and an anonymous atom +containing the c-string literal "hello world". The Atom "main" has two +references. One is the call site for the call to printf, and the other is a +reference for the instruction that loads the address of the c-string literal. + +There are only four different types of atoms: + + * DefinedAtom + 95% of all atoms. This is a chunk of code or data + + * UndefinedAtom + This is a place holder in object files for a reference to some atom + outside the translation unit.During core linking it is usually replaced + by (coalesced into) another Atom. + + * SharedLibraryAtom + If a required symbol name turns out to be defined in a dynamic shared + library (and not some object file). A SharedLibraryAtom is the + placeholder Atom used to represent that fact. + + It is similar to an UndefinedAtom, but it also tracks information + about the associated shared library. + + * AbsoluteAtom + This is for embedded support where some stuff is implemented in ROM at + some fixed address. This atom has no content. It is just an address + that the Writer needs to fix up any references to point to. + + +File Model +---------- + +The linker views the input files as basically containers of Atoms and +References, and just a few attributes of their own. The linker works with three +kinds of files: object files, static libraries, and dynamic shared libraries. +Each kind of file has reader object which presents the file in the model +expected by the linker. + +Object File +~~~~~~~~~~~ + +An object file is just a container of atoms. When linking an object file, a +reader is instantiated which parses the object file and instantiates a set of +atoms representing all content in the .o file. The linker adds all those atoms +to a master graph. + +Static Library (Archive) +~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the traditional unix static archive which is just a collection of object +files with a "table of contents". When linking with a static library, by default +nothing is added to the master graph of atoms. Instead, if after merging all +atoms from object files into a master graph, if any "undefined" atoms are left +remaining in the master graph, the linker reads the table of contents for each +static library to see if any have the needed definitions. If so, the set of +atoms from the specified object file in the static library is added to the +master graph of atoms. + +Dynamic Library (Shared Object) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dynamic libraries are different than object files and static libraries in that +they don't directly add any content. Their purpose is to check at build time +that the remaining undefined references can be resolved at runtime, and provide +a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way +this is modeled in the linker is that a dynamic library contributes no atoms to +the initial graph of atoms. Instead, (like static libraries) if there are +"undefined" atoms in the master graph of all atoms, then each dynamic library is +checked to see if exports the required symbol. If so, a "shared library" atom is +instantiated by the by the reader which the linker uses to replace the +"undefined" atom. + +Linking Steps +------------- + +Through the use of abstract Atoms, the core of linking is architecture +independent and file format independent. All command line parsing is factored +out into a separate "options" abstraction which enables the linker to be driven +with different command line sets. + +The overall steps in linking are: + + #. Command line processing + + #. Parsing input files + + #. Resolving + + #. Passes/Optimizations + + #. Generate output file + +The Resolving and Passes steps are done purely on the master graph of atoms, so +they have no notion of file formats such as mach-o or ELF. + + +Input Files +~~~~~~~~~~~ + +Existing developer tools using different file formats for object files. +A goal of lld is to be file format independent. This is done +through a plug-in model for reading object files. The lld::Reader is the base +class for all object file readers. A Reader follows the factory method pattern. +A Reader instantiates an lld::File object (which is a graph of Atoms) from a +given object file (on disk or in-memory). + +Every Reader subclass defines its own "options" class (for instance the mach-o +Reader defines the class ReaderOptionsMachO). This options class is the +one-and-only way to control how the Reader operates when parsing an input file +into an Atom graph. For instance, you may want the Reader to only accept +certain architectures. The options class can be instantiated from command +line options, or it can be subclassed and the ivars programmatically set. + +ELF Section Groups +~~~~~~~~~~~~~~~~~~ +Reference : `ELF Section Groups `_ + +C++ has many situations where the compiler may need to emit code or data, +but may not be able to identify a unique compilation unit where it should be +emitted. The approach chosen by the C++ ABI group to deal with this problem, is +to allow the compiler to emit the required information in multiple compilation +units, in a form which allows the linker to remove all but one copy. This is +essentially the feature called COMDAT in several existing implementations. + +The COMDAT sections in ELF are modeled by using '.group' sections in the input +files. Each '.group' section is associated with a signature. The '.group' +section has a list of members that are part of the the '.group' which the linker +selects to appear in the input file(Whichever .group section appeared first +in the link). References to any of the '.group' members can also appear from +outside the '.group'. + +In lld the the '.group' sections with COMDAT are identified by contentType( +typeGroupComdat). The '.group' members are identified by using +**kindGroupChild** references. + +The point to be noted here is the 'group child' members would need to be emitted +in the output file **iff** the group was selected by the resolver. + +This is modeled in lld by removing the 'group child' members from the +definedAtom List. + +Any reference to the group-child from **outside the group** is referenced using +a 'undefined' atom. + +Resolving +~~~~~~~~~ + +The resolving step takes all the atoms' graphs from each object file and +combines them into one master object graph. Unfortunately, it is not as simple +as appending the atom list from each file into one big list. There are many +cases where atoms need to be coalesced. That is, two or more atoms need to be +coalesced into one atom. This is necessary to support: C language "tentative +definitions", C++ weak symbols for templates and inlines defined in headers, +replacing undefined atoms with actual definition atoms, and for merging copies +of constants like c-strings and floating point constants. + +The linker support coalescing by-name and by-content. By-name is used for +tentative definitions and weak symbols. By-content is used for constant data +that can be merged. + +The resolving process maintains some global linking "state", including a "symbol +table" which is a map from llvm::StringRef to lld::Atom*. With these data +structures, the linker iterates all atoms in all input files. For each atom, it +checks if the atom is named and has a global or hidden scope. If so, the atom +is added to the symbol table map. If there already is a matching atom in that +table, that means the current atom needs to be coalesced with the found atom, or +it is a multiple definition error. + +When all initial input file atoms have been processed by the resolver, a scan is +made to see if there are any undefined atoms in the graph. If there are, the +linker scans all libraries (both static and dynamic) looking for definitions to +replace the undefined atoms. It is an error if any undefined atoms are left +remaining. + +Dead code stripping (if requested) is done at the end of resolving. The linker +does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main +executable) and follows each references and marks each Atom that it visits as +"live". When done, all atoms not marked "live" are removed. + +The result of the Resolving phase is the creation of an lld::File object. The +goal is that the lld::File model is **the** internal representation +throughout the linker. The file readers parse (mach-o, ELF, COFF) into an +lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce +their file kind, and every Pass only operates on an lld::File. This is not only +a simpler, consistent model, but it enables the state of the linker to be dumped +at any point in the link for testing purposes. + + +Passes +~~~~~~ + +The Passes step is an open ended set of routines that each get a change to +modify or enhance the current lld::File object. Some example Passes are: + + * stub (PLT) generation + + * GOT instantiation + + * order_file optimization + + * branch island generation + + * branch shim generation + + * Objective-C optimizations (Darwin specific) + + * TLV instantiation (Darwin specific) + + * DTrace probe processing (Darwin specific) + + * compact unwind encoding (Darwin specific) + + +Some of these passes are specific to Darwin's runtime environments. But many of +the passes are applicable to any OS (such as generating branch island for out of +range branch instructions). + +The general structure of a pass is to iterate through the atoms in the current +lld::File object, inspecting each atom and doing something. For instance, the +stub pass, looks for call sites to shared library atoms (e.g. call to printf). +It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for +each proxy atom needed, and these new atoms are added to the current lld::File +object. Next, all the noted call sites to shared library atoms have their +References altered to point to the stub atom instead of the shared library atom. + + +Generate Output File +~~~~~~~~~~~~~~~~~~~~ + +Once the passes are done, the output file writer is given current lld::File +object. The writer's job is to create the executable content file wrapper and +place the content of the atoms into it. + +lld uses a plug-in model for writing output files. All concrete writers (e.g. +ELF, mach-o, etc) are subclasses of the lld::Writer class. + +Unlike the Reader class which has just one method to instantiate an lld::File, +the Writer class has multiple methods. The crucial method is to generate the +output file, but there are also methods which allow the Writer to contribute +Atoms to the resolver and specify passes to run. + +An example of contributing +atoms is that if the Writer knows a main executable is being linked and such +an executable requires a specially named entry point (e.g. "_main"), the Writer +can add an UndefinedAtom with that special name to the resolver. This will +cause the resolver to issue an error if that symbol is not defined. + +Sometimes a Writer supports lazily created symbols, such as names for the start +of sections. To support this, the Writer can create a File object which vends +no initial atoms, but does lazily supply atoms by name as needed. + +Every Writer subclass defines its own "options" class (for instance the mach-o +Writer defines the class WriterOptionsMachO). This options class is the +one-and-only way to control how the Writer operates when producing an output +file from an Atom graph. For instance, you may want the Writer to optimize +the output for certain OS versions, or strip local symbols, etc. The options +class can be instantiated from command line options, or it can be subclassed +and the ivars programmatically set. + + +lld::File representations +------------------------- + +Just as LLVM has three representations of its IR model, lld has three +representations of its File/Atom/Reference model: + + * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File). + + * textual (in YAML) + + * binary format ("native") + +Binary File Format +~~~~~~~~~~~~~~~~~~ + +In theory, lld::File objects could be written to disk in an existing Object File +format standard (e.g. ELF). Instead we choose to define a new binary file +format. There are two main reasons for this: fidelity and performance. In order +for lld to work as a linker on all platforms, its internal model must be rich +enough to model all CPU and OS linking features. But if we choose an existing +Object File format as the lld binary format, that means an on going need to +retrofit each platform specific feature needed from alternate platforms into the +existing Object File format. Having our own "native" binary format side steps +that issue. We still need to be able to binary encode all the features, but +once the in-memory model can represent the feature, it is straight forward to +binary encode it. + +The reason to use a binary file format at all, instead of a textual file format, +is speed. You want the binary format to be as fast as possible to read into the +in-memory model. Given that we control the in-memory model and the binary +format, the obvious way to make reading super fast it to make the file format be +basically just an array of atoms. The reader just mmaps in the file and looks +at the header to see how many atoms there are and instantiate that many atom +objects with the atom attribute information coming from that array. The trick +is designing this in a way that can be extended as the Atom mode evolves and new +attributes are added. + +The native object file format starts with a header that lists how many "chunks" +are in the file. A chunk is an array of "ivar data". The native file reader +instantiates an array of Atom objects (with one large malloc call). Each atom +contains just a pointer to its vtable and a pointer to its ivar data. All +methods on lld::Atom are virtual, so all the method implementations return +values based on the ivar data to which it has a pointer. If a new linking +features is added which requires a change to the lld::Atom model, a new native +reader class (e.g. version 2) is defined which knows how to read the new feature +information from the new ivar data. The old reader class (e.g. version 1) is +updated to do its best to model (the lack of the new feature) given the old ivar +data in existing native object files. + +With this model for the native file format, files can be read and turned +into the in-memory graph of lld::Atoms with just a few memory allocations. +And the format can easily adapt over time to new features. + +The binary file format follows the ReaderWriter patterns used in lld. The lld +library comes with the classes: ReaderNative and WriterNative. So, switching +between file formats is as easy as switching which Reader subclass is used. + + +Textual representations in YAML +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In designing a textual format we want something easy for humans to read and easy +for the linker to parse. Since an atom has lots of attributes most of which are +usually just the default, we should define default values for every attribute so +that those can be omitted from the text representation. Here is the atoms for a +simple hello world program expressed in YAML:: + + target-triple: x86_64-apple-darwin11 + + atoms: + - name: _main + scope: global + type: code + content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00, + 00, 00, 31, c0, 5d, c3 ] + fixups: + - offset: 07 + kind: pcrel32 + target: 2 + - offset: 0E + kind: call32 + target: _fprintf + + - type: c-string + content: [ 73, 5A, 00 ] + + ... + +The biggest use for the textual format will be writing test cases. Writing test +cases in C is problematic because the compiler may vary its output over time for +its own optimization reasons which my inadvertently disable or break the linker +feature trying to be tested. By writing test cases in the linkers own textual +format, we can exactly specify every attribute of every atom and thus target +specific linker logic. + +The textual/YAML format follows the ReaderWriter patterns used in lld. The lld +library comes with the classes: ReaderYAML and WriterYAML. + + +Testing +------- + +The lld project contains a test suite which is being built up as new code is +added to lld. All new lld functionality should have a tests added to the test +suite. The test suite is `lit `_ driven. Each +test is a text file with comments telling lit how to run the test and check the +result To facilitate testing, the lld project builds a tool called lld-core. +This tool reads a YAML file (default from stdin), parses it into one or more +lld::File objects in memory and then feeds those lld::File objects to the +resolver phase. The output of the resolver is written as a native object file. +It is then read back in using the native object file reader and then pass to the +YAML writer. This round-about path means that all three representations +(in-memory, binary, and text) are exercised, and any new feature has to work in +all the representations to pass the test. + + +Resolver testing +~~~~~~~~~~~~~~~~ + +Basic testing is the "core linking" or resolving phase. That is where the +linker merges object files. All test cases are written in YAML. One feature of +YAML is that it allows multiple "documents" to be encoding in one YAML stream. +That means one text file can appear to the linker as multiple .o files - the +normal case for the linker. + +Here is a simple example of a core linking test case. It checks that an +undefined atom from one file will be replaced by a definition from another +file:: + + # RUN: lld-core %s | FileCheck %s + + # + # Test that undefined atoms are replaced with defined atoms. + # + + --- + atoms: + - name: foo + definition: undefined + --- + atoms: + - name: foo + scope: global + type: code + ... + + # CHECK: name: foo + # CHECK: scope: global + # CHECK: type: code + # CHECK-NOT: name: foo + # CHECK: ... + + +Passes testing +~~~~~~~~~~~~~~ + +Since Passes just operate on an lld::File object, the lld-core tool has the +option to run a particular pass (after resolving). Thus, you can write a YAML +test case with carefully crafted input to exercise areas of a Pass and the check +the resulting lld::File object as represented in YAML. + + +Design Issues +------------- + +There are a number of open issues in the design of lld. The plan is to wait and +make these design decisions when we need to. + + +Debug Info +~~~~~~~~~~ + +Currently, the lld model says nothing about debug info. But the most popular +debug format is DWARF and there is some impedance mismatch with the lld model +and DWARF. In lld there are just Atoms and only Atoms that need to be in a +special section at runtime have an associated section. Also, Atoms do not have +addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go +into specially named sections and the DWARF references function code by address. + +CPU and OS specific functionality +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Currently, lld has an abstract "Platform" that deals with any CPU or OS specific +differences in linking. We just keep adding virtual methods to the base +Platform class as we find linking areas that might need customization. At some +point we'll need to structure this better. + + +File Attributes +~~~~~~~~~~~~~~~ + +Currently, lld::File just has a path and a way to iterate its atoms. We will +need to add more attributes on a File. For example, some equivalent to the +target triple. There is also a number of cached or computed attributes that +could make various Passes more efficient. For instance, on Darwin there are a +number of Objective-C optimizations that can be done by a Pass. But it would +improve the plain C case if the Objective-C optimization Pass did not have to +scan all atoms looking for any Objective-C data structures. This could be done +if the lld::File object had an attribute that said if the file had any +Objective-C data in it. The Resolving phase would then be required to "merge" +that attribute as object files are added. diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 000000000000..918e1778b801 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,48 @@ +.. _development: + +Development +=========== + +lld is developed as part of the `LLVM `_ project. + +Using C++11 in lld +------------------ + +:doc:`C++11`. + +Creating a Reader +----------------- + +See the :ref:`Creating a Reader ` guide. + + +Modifying the Driver +-------------------- + +See :doc:`Driver`. + + +Debugging +--------- + +You can run lld with ``-mllvm -debug`` command line options to enable debugging +printouts. If you want to enable debug information for some specific pass, you +can run it with ``-mllvm '-debug-only='``, where pass is a name used in +the ``DEBUG_WITH_TYPE()`` macro. + + + +Documentation +------------- + +The project documentation is written in reStructuredText and generated using the +`Sphinx `_ documentation generator. For more +information on writing documentation for the project, see the +:ref:`sphinx_intro`. + +.. toctree:: + :hidden: + + C++11 + Readers + Driver diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 000000000000..986a406c1cb7 --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,106 @@ +.. _getting_started: + +Getting Started: Building and Running lld +========================================= + +This page gives you the shortest path to checking out and building lld. If you +run into problems, please file bugs in the `LLVM Bugzilla`__ + +__ http://llvm.org/bugs/ + +Building lld +------------ + +On Unix-like Systems +~~~~~~~~~~~~~~~~~~~~ + +1. Get the required tools. + + * `CMake 2.8`_\+. + * make (or any build system CMake supports). + * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required). + + * If using Clang, you will also need `libc++`_. + * `Python 2.4`_\+ (not 3.x) for running tests. + +.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html +.. _Clang 3.1: http://clang.llvm.org/ +.. _libc++: http://libcxx.llvm.org/ +.. _Python 2.4: http://python.org/download/ + +2. Check out LLVM:: + + $ cd path/to/llvm-project + $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm + +3. Check out lld:: + + $ cd llvm/tools + $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld + + * lld can also be checked out to ``path/to/llvm-project`` and built as an external + project. + +4. Build LLVM and lld:: + + $ cd path/to/llvm-build/llvm (out of source build required) + $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm + $ make + + * If you want to build with clang and it is not the default compiler or + it is installed in an alternate location, you'll need to tell the cmake tool + the location of the C and C++ compiler via CMAKE_C_COMPILER and + CMAKE_CXX_COMPILER. For example:: + + $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ... + +5. Test:: + + $ make lld-test + +Using Visual Studio +~~~~~~~~~~~~~~~~~~~ + +#. Get the required tools. + + * `CMake 2.8`_\+. + * `Visual Studio 11 (2012) or later`_ (required for C++11 support) + * `Python 2.4`_\+ (not 3.x) for running tests. + +.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html +.. _Visual Studio 11 (2012) or later: http://www.microsoft.com/visualstudio/11/en-us +.. _Python 2.4: http://python.org/download/ + +#. Check out LLVM:: + + $ cd path/to/llvm-project + $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm + +#. Check out lld:: + + $ cd llvm/tools + $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld + + * lld can also be checked out to ``path/to/llvm-project`` and built as an external + project. + +#. Generate Visual Studio project files:: + + $ cd path/to/llvm-build/llvm (out of source build required) + $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm + +#. Build + + * Open LLVM.sln in Visual Studio. + * Build the ``ALL_BUILD`` target. + +#. Test + + * Build the ``lld-test`` target. + +More Information +~~~~~~~~~~~~~~~~ + +For more information on using CMake see the `LLVM CMake guide`_. + +.. _LLVM CMake guide: http://llvm.org/docs/CMake.html diff --git a/docs/hello.png b/docs/hello.png new file mode 100644 index 000000000000..70df111f1abd Binary files /dev/null and b/docs/hello.png differ diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000000..7a87ad8d0583 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,88 @@ +.. _index: + +lld - The LLVM Linker +===================== + +lld is a new set of modular code for creating linker tools. + +* End-User Features: + + * Compatible with existing linker options + * Reads standard Object Files (e.g. ELF, Mach-O, PE/COFF) + * Writes standard Executable Files (e.g. ELF, Mach-O, PE) + * Fast link times + * Minimal memory use + * Remove clang's reliance on "the system linker" + * Uses the LLVM `"UIUC" BSD-Style license`__. + +* Applications: + + * Modular design + * Support cross linking + * Easy to add new CPU support + * Can be built as static tool or library + +* Design and Implementation: + + * Extensive unit tests + * Internal linker model can be dumped/read to textual format + * Internal linker model can be dumped/read to a new native format + * Native format designed to be fast to read and write + * Additional linking features can be plugged in as "passes" + * OS specific and CPU specific code factored out + +Why a new linker? +----------------- + +The fact that clang relies on whatever linker tool you happen to have installed +means that clang has been very conservative adopting features which require a +recent linker. + +In the same way that the MC layer of LLVM has removed clang's reliance on the +system assembler tool, the lld project will remove clang's reliance on the +system linker tool. + + +Current Status +-------------- + +lld can self host on x86-64 FreeBSD and Linux and x86 Windows. + +All SingleSource tests in test-suite pass on x86-64 Linux. + +All SingleSource and MultiSource tests in the LLVM test-suite +pass on MIPS 32-bit little-endian Linux. + +Source +------ + +lld is available in the LLVM SVN repository:: + + svn co http://llvm.org/svn/llvm-project/lld/trunk lld + +lld is also available via the read-only git mirror:: + + git clone http://llvm.org/git/lld.git + +Put it in llvm's tools/ directory, rerun cmake, then build target lld. + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + design + getting_started + development + windows_support + open_projects + sphinx_intro + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`search` + +__ http://llvm.org/docs/DeveloperPolicy.html#license diff --git a/docs/llvm-theme/layout.html b/docs/llvm-theme/layout.html new file mode 100644 index 000000000000..0cd0918eac2a --- /dev/null +++ b/docs/llvm-theme/layout.html @@ -0,0 +1,22 @@ +{# + sphinxdoc/layout.html + ~~~~~~~~~~~~~~~~~~~~~ + + Sphinx layout template for the sphinxdoc theme. + + :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% extends "basic/layout.html" %} + +{% block relbar1 %} + +{{ super() }} +{% endblock %} + +{# put the sidebar before the body #} +{% block sidebar1 %}{{ sidebar() }}{% endblock %} +{% block sidebar2 %}{% endblock %} diff --git a/docs/llvm-theme/static/contents.png b/docs/llvm-theme/static/contents.png new file mode 100644 index 000000000000..7fb82154a174 Binary files /dev/null and b/docs/llvm-theme/static/contents.png differ diff --git a/docs/llvm-theme/static/llvm.css b/docs/llvm-theme/static/llvm.css new file mode 100644 index 000000000000..32802bb6a2d0 --- /dev/null +++ b/docs/llvm-theme/static/llvm.css @@ -0,0 +1,345 @@ +/* + * sphinxdoc.css_t + * ~~~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- sphinxdoc theme. Originally created by + * Armin Ronacher for Werkzeug. + * + * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + font-size: 14px; + letter-spacing: -0.01em; + line-height: 150%; + text-align: center; + background-color: #BFD1D4; + color: black; + padding: 0; + border: 1px solid #aaa; + + margin: 0px 80px 0px 80px; + min-width: 740px; +} + +div.logo { + background-color: white; + text-align: left; + padding: 10px 10px 15px 15px; +} + +div.document { + background-color: white; + text-align: left; + background-image: url(contents.png); + background-repeat: repeat-x; +} + +div.bodywrapper { + margin: 0 240px 0 0; + border-right: 1px solid #ccc; +} + +div.body { + margin: 0; + padding: 0.5em 20px 20px 20px; +} + +div.related { + font-size: 1em; +} + +div.related ul { + background-image: url(navigation.png); + height: 2em; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} + +div.related ul li { + margin: 0; + padding: 0; + height: 2em; + float: left; +} + +div.related ul li.right { + float: right; + margin-right: 5px; +} + +div.related ul li a { + margin: 0; + padding: 0 5px 0 5px; + line-height: 1.75em; + color: #EE9816; +} + +div.related ul li a:hover { + color: #3CA8E7; +} + +div.sphinxsidebarwrapper { + padding: 0; +} + +div.sphinxsidebar { + margin: 0; + padding: 0.5em 15px 15px 0; + width: 210px; + float: right; + font-size: 1em; + text-align: left; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin: 1em 0 0.5em 0; + font-size: 1em; + padding: 0.1em 0 0.1em 0.5em; + color: white; + border: 1px solid #86989B; + background-color: #AFC1C4; +} + +div.sphinxsidebar h3 a { + color: white; +} + +div.sphinxsidebar ul { + padding-left: 1.5em; + margin-top: 7px; + padding: 0; + line-height: 130%; +} + +div.sphinxsidebar ul ul { + margin-left: 20px; +} + +div.footer { + background-color: #E3EFF1; + color: #86989B; + padding: 3px 8px 3px 0; + clear: both; + font-size: 0.8em; + text-align: right; +} + +div.footer a { + color: #86989B; + text-decoration: underline; +} + +/* -- body styles ----------------------------------------------------------- */ + +p { + margin: 0.8em 0 0.5em 0; +} + +a { + color: #CA7900; + text-decoration: none; +} + +a:hover { + color: #2491CF; +} + +div.body a { + text-decoration: underline; +} + +h1 { + margin: 0; + padding: 0.7em 0 0.3em 0; + font-size: 1.5em; + color: #11557C; +} + +h2 { + margin: 1.3em 0 0.2em 0; + font-size: 1.35em; + padding: 0; +} + +h3 { + margin: 1em 0 -0.3em 0; + font-size: 1.2em; +} + +div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { + color: black!important; +} + +h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { + display: none; + margin: 0 0 0 0.3em; + padding: 0 0.2em 0 0.2em; + color: #aaa!important; +} + +h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, +h5:hover a.anchor, h6:hover a.anchor { + display: inline; +} + +h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, +h5 a.anchor:hover, h6 a.anchor:hover { + color: #777; + background-color: #eee; +} + +a.headerlink { + color: #c60f0f!important; + font-size: 1em; + margin-left: 6px; + padding: 0 4px 0 4px; + text-decoration: none!important; +} + +a.headerlink:hover { + background-color: #ccc; + color: white!important; +} + +cite, code, tt { + font-family: 'Consolas', 'Deja Vu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 0.95em; + letter-spacing: 0.01em; +} + +tt { + background-color: #f2f2f2; + border-bottom: 1px solid #ddd; + color: #333; +} + +tt.descname, tt.descclassname, tt.xref { + border: 0; +} + +hr { + border: 1px solid #abc; + margin: 2em; +} + +a tt { + border: 0; + color: #CA7900; +} + +a tt:hover { + color: #2491CF; +} + +pre { + font-family: 'Consolas', 'Deja Vu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 0.95em; + letter-spacing: 0.015em; + line-height: 120%; + padding: 0.5em; + border: 1px solid #ccc; + background-color: #f8f8f8; +} + +pre a { + color: inherit; + text-decoration: underline; +} + +td.linenos pre { + padding: 0.5em 0; +} + +div.quotebar { + background-color: #f8f8f8; + max-width: 250px; + float: right; + padding: 2px 7px; + border: 1px solid #ccc; +} + +div.topic { + background-color: #f8f8f8; +} + +table { + border-collapse: collapse; + margin: 0 -0.5em 0 -0.5em; +} + +table td, table th { + padding: 0.2em 0.5em 0.2em 0.5em; +} + +div.admonition, div.warning { + font-size: 0.9em; + margin: 1em 0 1em 0; + border: 1px solid #86989B; + background-color: #f7f7f7; + padding: 0; +} + +div.admonition p, div.warning p { + margin: 0.5em 1em 0.5em 1em; + padding: 0; +} + +div.admonition pre, div.warning pre { + margin: 0.4em 1em 0.4em 1em; +} + +div.admonition p.admonition-title, +div.warning p.admonition-title { + margin: 0; + padding: 0.1em 0 0.1em 0.5em; + color: white; + border-bottom: 1px solid #86989B; + font-weight: bold; + background-color: #AFC1C4; +} + +div.warning { + border: 1px solid #940000; +} + +div.warning p.admonition-title { + background-color: #CF0000; + border-bottom-color: #940000; +} + +div.admonition ul, div.admonition ol, +div.warning ul, div.warning ol { + margin: 0.1em 0.5em 0.5em 3em; + padding: 0; +} + +div.versioninfo { + margin: 1em 0 0 0; + border: 1px solid #ccc; + background-color: #DDEAF0; + padding: 8px; + line-height: 1.3em; + font-size: 0.9em; +} + +.viewcode-back { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} diff --git a/docs/llvm-theme/static/logo.png b/docs/llvm-theme/static/logo.png new file mode 100644 index 000000000000..4fc899028dc6 Binary files /dev/null and b/docs/llvm-theme/static/logo.png differ diff --git a/docs/llvm-theme/static/navigation.png b/docs/llvm-theme/static/navigation.png new file mode 100644 index 000000000000..1081dc1439fb Binary files /dev/null and b/docs/llvm-theme/static/navigation.png differ diff --git a/docs/llvm-theme/theme.conf b/docs/llvm-theme/theme.conf new file mode 100644 index 000000000000..330fc92ffa18 --- /dev/null +++ b/docs/llvm-theme/theme.conf @@ -0,0 +1,4 @@ +[theme] +inherit = basic +stylesheet = llvm.css +pygments_style = friendly diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 000000000000..8471252d709f --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/docs/open_projects.rst b/docs/open_projects.rst new file mode 100644 index 000000000000..eb146c8b7542 --- /dev/null +++ b/docs/open_projects.rst @@ -0,0 +1,17 @@ +.. _open_projects: + +Open Projects +============= + +.. include:: ../include/lld/Core/TODO.txt +.. include:: ../lib/Core/TODO.txt +.. include:: ../lib/Driver/TODO.rst +.. include:: ../lib/ReaderWriter/ELF/X86_64/TODO.rst +.. include:: ../lib/ReaderWriter/ELF/AArch64/TODO.rst +.. include:: ../lib/ReaderWriter/ELF/ARM/TODO.rst +.. include:: ../tools/lld/TODO.txt + +Documentation TODOs +~~~~~~~~~~~~~~~~~~~ + +.. todolist:: diff --git a/docs/sphinx_intro.rst b/docs/sphinx_intro.rst new file mode 100644 index 000000000000..6845bc812e78 --- /dev/null +++ b/docs/sphinx_intro.rst @@ -0,0 +1,147 @@ +.. _sphinx_intro: + +Sphinx Introduction for LLVM Developers +======================================= + +This document is intended as a short and simple introduction to the Sphinx +documentation generation system for LLVM developers. + +Quickstart +---------- + +To get started writing documentation, you will need to: + + 1. Have the Sphinx tools :ref:`installed `. + + 2. Understand how to :ref:`build the documentation + `. + + 3. Start :ref:`writing documentation `! + +.. _installing_sphinx: + +Installing Sphinx +~~~~~~~~~~~~~~~~~ + +You should be able to install Sphinx using the standard Python package +installation tool ``easy_install``, as follows:: + + $ sudo easy_install sphinx + Searching for sphinx + Reading http://pypi.python.org/simple/sphinx/ + Reading http://sphinx.pocoo.org/ + Best match: Sphinx 1.1.3 + ... more lines here .. + +If you do not have root access (or otherwise want to avoid installing Sphinx in +system directories) see the section on :ref:`installing_sphinx_in_a_venv` . + +If you do not have the ``easy_install`` tool on your system, you should be able +to install it using: + + Linux + Use your distribution's standard package management tool to install it, + i.e., ``apt-get install easy_install`` or ``yum install easy_install``. + + Mac OS X + All modern Mac OS X systems come with ``easy_install`` as part of the base + system. + + Windows + See the `setuptools `_ package web + page for instructions. + + +.. _building_the_documentation: + +Building the documentation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to build the documentation, all you should need to do is change to the +``docs`` directory and invoke make as follows:: + + $ cd path/to/project/docs + $ make html + +Note that on Windows there is a ``make.bat`` command in the docs directory which +supplies the same interface as the ``Makefile``. + +That command will invoke ``sphinx-build`` with the appropriate options for the +project, and generate the HTML documentation in a ``_build`` subdirectory. You +can browse it starting from the index page by visiting +``_build/html/index.html``. + +Sphinx supports a wide variety of generation formats (including LaTeX, man +pages, and plain text). The ``Makefile`` includes a number of convenience +targets for invoking ``sphinx-build`` appropriately, the common ones are: + + make html + Generate the HTML output. + + make latexpdf + Generate LaTeX documentation and convert to a PDF. + + make man + Generate man pages. + + +.. _writing_documentation: + +Writing documentation +~~~~~~~~~~~~~~~~~~~~~ + +The documentation itself is written in the reStructuredText (ReST) format, and Sphinx +defines additional tags to support features like cross-referencing. + +The ReST format itself is organized around documents mostly being readable +plaintext documents. You should generally be able to write new documentation +easily just by following the style of the existing documentation. + +If you want to understand the formatting of the documents more, the best place +to start is Sphinx's own `ReST Primer `_. + + +Learning More +------------- + +If you want to learn more about the Sphinx system, the best place to start is +the Sphinx documentation itself, available `here +`_. + + +.. _installing_sphinx_in_a_venv: + +Installing Sphinx in a Virtual Environment +------------------------------------------ + +Most Python developers prefer to work with tools inside a *virtualenv* (virtual +environment) instance, which functions as an application sandbox. This avoids +polluting your system installation with different packages used by various +projects (and ensures that dependencies for different packages don't conflict +with one another). Of course, you need to first have the virtualenv software +itself which generally would be installed at the system level:: + + $ sudo easy_install virtualenv + +but after that you no longer need to install additional packages in the system +directories. + +Once you have the *virtualenv* tool itself installed, you can create a +virtualenv for Sphinx using:: + + $ virtualenv ~/my-sphinx-install + New python executable in /Users/dummy/my-sphinx-install/bin/python + Installing setuptools............done. + Installing pip...............done. + + $ ~/my-sphinx-install/bin/easy_install sphinx + ... install messages here ... + +and from now on you can "activate" the *virtualenv* using:: + + $ source ~/my-sphinx-install/bin/activate + +which will change your PATH to ensure the sphinx-build tool from inside the +virtual environment will be used. See the `virtualenv website +`_ for more information on using +virtual environments. diff --git a/docs/windows_support.rst b/docs/windows_support.rst new file mode 100644 index 000000000000..d9906a72ea1e --- /dev/null +++ b/docs/windows_support.rst @@ -0,0 +1,118 @@ +.. raw:: html + + + +.. role:: none +.. role:: partial +.. role:: good + +=============== +Windows support +=============== + +LLD has some experimental Windows support. When invoked as ``link.exe`` or with +``-flavor link``, the driver for Windows operating system is used to parse +command line options, and it drives further linking processes. LLD accepts +almost all command line options that the linker shipped with Microsoft Visual +C++ (link.exe) supports. + +The current status is that LLD can link itself on Windows x86 using Visual C++ +2012 or 2013 as the compiler. + +Development status +================== + +Driver + :good:`Mostly done`. Some exotic command line options that are not usually + used for application develompent, such as ``/DRIVER``, are not supported. + Options for Windows 8 app store are not recognized too + (e.g. ``/APPCONTAINER``). + +Linking against DLL + :good:`Done`. LLD can read import libraries needed to link against DLL. Both + export-by-name and export-by-ordinal are supported. + +Linking against static library + :good:`Done`. The format of static library (.lib) on Windows is actually the + same as on Unix (.a). LLD can read it. + +Creating DLL + :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported + functions can be specified either via command line (``/EXPORT``) or via + module-definition file (.def). Both export-by-name and export-by-ordinal are + supported. LLD uses Microsoft ``lib.exe`` tool to create an import library + file. + +Windows resource files support + :good:`Done`. If an ``.rc`` file is given, LLD converts the file to a COFF + file using some external commands and link it. Specifically, ``rc.exe`` is + used to compile a resource file (.rc) to a compiled resource (.res) + file. ``rescvt.exe`` is then used to convert a compiled resource file to a + COFF object file section. Both tools are shipped with MSVC. + +Safe Structured Exception Handler (SEH) + :good:`Done` for x86. :partial:`Work in progress` for x64. + +Module-definition file + :partial:`Partially done`. LLD currently recognizes these directives: + ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. + +x64 (x86-64) + :partial:`Work in progress`. LLD can create PE32+ executable but the generated + file does not work unless source object files are very simple because of the + lack of SEH handler table. + +Debug info + :none:`No progress has been made`. Microsoft linker can interpret the CodeGen + debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't + support neither. + + +Building LLD +============ + +Using Visual Studio IDE/MSBuild +------------------------------- + +1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), +#. run ``cmake -G "Visual Studio 12" `` from VS command prompt, +#. open LLVM.sln with Visual Studio, and +#. build ``lld`` target in ``lld executables`` folder + +Alternatively, you can use msbuild if you don't like to work in an IDE:: + + msbuild LLVM.sln /m /target:"lld executables\lld" + +MSBuild.exe had been shipped as a component of the .NET framework, but since +2013 it's part of Visual Studio. You can find it at "C:\\Program Files +(x86)\\msbuild". + +You can build LLD as a 64 bit application. To do that, open VS2013 x64 command +prompt and run cmake for "Visual Studio 12 Win64" target. + +Using Ninja +----------- + +1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), +#. run ``cmake -G ninja `` from VS command prompt, +#. run ``ninja lld`` + +Known issues +============ + +Note that LLD is still in early stage in development, so there are still many +bugs. Here is a list of notable bugs. + +* Symbol name resolution from library files sometimes fails. On Windows, the + order of library files in command line does not matter, but LLD sometimes + fails to simulate the semantics. A workaround for it is to explicitly add + library files to command line with ``/DEFAULTLIB``. + +* Subsystem inference is not very reliable. Linker is supposed to set + ``subsystem`` field in the PE/COFF header according to entry function name, + but LLD sometimes ended up with ``unknown`` subsystem type. You need to give + ``/SUBSYSTEM`` option if it fails to infer it. diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 000000000000..d8903356d9fb --- /dev/null +++ b/include/Makefile @@ -0,0 +1,4 @@ +LLD_LEVEL := .. +DIRS := lld + +include $(LLD_LEVEL)/Makefile diff --git a/include/lld/Config/Makefile b/include/lld/Config/Makefile new file mode 100644 index 000000000000..e2139220e3df --- /dev/null +++ b/include/lld/Config/Makefile @@ -0,0 +1,32 @@ +LLD_LEVEL := ../../.. + +BUILT_SOURCES = Version.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(LLD_LEVEL)/Makefile + +# Compute the lld version from the LLVM version, unless specified explicitly. +ifndef LLD_VERSION +LLD_VERSION := $(subst svn,,$(LLVMVersion)) +LLD_VERSION := $(subst rc,,$(LLD_VERSION)) +endif + +LLD_VERSION_COMPONENTS := $(subst ., ,$(LLD_VERSION)) +LLD_VERSION_MAJOR := $(word 1,$(LLD_VERSION_COMPONENTS)) +LLD_VERSION_MINOR := $(word 2,$(LLD_VERSION_COMPONENTS)) + +LLD_REVISION := $(strip \ + $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(LLVM_SRC_ROOT)/tools/lld)) + +LLD_REPOSITORY := $(strip \ + $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(LLVM_SRC_ROOT)/tools/lld)) + +$(ObjDir)/Version.inc.tmp : Version.inc.in Makefile $(LLVM_OBJ_ROOT)/Makefile.config $(ObjDir)/.dir + $(Echo) "Updating LLD version info." + $(Verb)sed -e "s#@LLD_VERSION@#$(LLD_VERSION)#g" \ + -e "s#@LLD_VERSION_MAJOR@#$(LLD_VERSION_MAJOR)#g" \ + -e "s#@LLD_VERSION_MINOR@#$(LLD_VERSION_MINOR)#g" \ + -e "s#@LLD_REVISION@#$(LLD_REVISION)#g" \ + -e "s#@LLD_REPOSITORY@#$(LLD_REPOSITORY)#g" \ + $< > $@ diff --git a/include/lld/Config/Version.h b/include/lld/Config/Version.h new file mode 100644 index 000000000000..41433c1175ef --- /dev/null +++ b/include/lld/Config/Version.h @@ -0,0 +1,51 @@ +//===- lld/Config/Version.h - LLD Version Number ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines version macros and version-related utility functions +/// for lld. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_VERSION_H +#define LLD_VERSION_H + +#include "lld/Config/Version.inc" +#include "llvm/ADT/StringRef.h" +#include + +/// \brief Helper macro for LLD_VERSION_STRING. +#define LLD_MAKE_VERSION_STRING2(X) #X + +/// \brief Helper macro for LLD_VERSION_STRING. +#define LLD_MAKE_VERSION_STRING(X, Y) LLD_MAKE_VERSION_STRING2(X.Y) + +/// \brief A string that describes the lld version number, e.g., "1.0". +#define LLD_VERSION_STRING \ + LLD_MAKE_VERSION_STRING(LLD_VERSION_MAJOR, LLD_VERSION_MINOR) + +namespace lld { +/// \brief Retrieves the repository path (e.g., Subversion path) that +/// identifies the particular lld branch, tag, or trunk from which this +/// lld was built. +llvm::StringRef getLLDRepositoryPath(); + +/// \brief Retrieves the repository revision number (or identifer) from which +/// this lld was built. +llvm::StringRef getLLDRevision(); + +/// \brief Retrieves the full repository version that is an amalgamation of +/// the information in getLLDRepositoryPath() and getLLDRevision(). +std::string getLLDRepositoryVersion(); + +/// \brief Retrieves a string representing the complete lld version. +llvm::StringRef getLLDVersion(); +} + +#endif // LLD_VERSION_H diff --git a/include/lld/Config/Version.inc.in b/include/lld/Config/Version.inc.in new file mode 100644 index 000000000000..c893a56686c0 --- /dev/null +++ b/include/lld/Config/Version.inc.in @@ -0,0 +1,5 @@ +#define LLD_VERSION @LLD_VERSION@ +#define LLD_VERSION_MAJOR @LLD_VERSION_MAJOR@ +#define LLD_VERSION_MINOR @LLD_VERSION_MINOR@ +#define LLD_REVISION_STRING "@LLD_REVISION@" +#define LLD_REPOSITORY_STRING "@LLD_REPOSITORY@" diff --git a/include/lld/Core/AbsoluteAtom.h b/include/lld/Core/AbsoluteAtom.h new file mode 100644 index 000000000000..ed25297cea81 --- /dev/null +++ b/include/lld/Core/AbsoluteAtom.h @@ -0,0 +1,43 @@ +//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ABSOLUTE_ATOM_H +#define LLD_CORE_ABSOLUTE_ATOM_H + +#include "lld/Core/Atom.h" + +namespace lld { + +/// An AbsoluteAtom has no content. +/// It exists to represent content at fixed addresses in memory. +class AbsoluteAtom : public Atom { +public: + + virtual uint64_t value() const = 0; + + /// scope - The visibility of this atom to other atoms. C static functions + /// have scope scopeTranslationUnit. Regular C functions have scope + /// scopeGlobal. Functions compiled with visibility=hidden have scope + /// scopeLinkageUnit so they can be see by other atoms being linked but not + /// by the OS loader. + virtual Scope scope() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionAbsolute; + } + + static bool classof(const AbsoluteAtom *) { return true; } + +protected: + AbsoluteAtom() : Atom(definitionAbsolute) {} +}; + +} // namespace lld + +#endif // LLD_CORE_ABSOLUTE_ATOM_H diff --git a/include/lld/Core/Alias.h b/include/lld/Core/Alias.h new file mode 100644 index 000000000000..610022525ecb --- /dev/null +++ b/include/lld/Core/Alias.h @@ -0,0 +1,102 @@ +//===- lld/Core/Alias.h - Alias atoms -------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provide alias atoms. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ALIAS_H +#define LLD_CORE_ALIAS_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Simple.h" +#include "llvm/ADT/Optional.h" +#include + +namespace lld { + +// An AliasAtom is a zero-size atom representing an alias for other atom. It has +// a LayoutAfter reference to the target atom, so that this atom and the target +// atom will be laid out at the same location in the final result. Initially +// the target atom is an undefined atom. Resolver will replace it with a defined +// one. +// +// It does not have attributes itself. Most member function calls are forwarded +// to the target atom. +class AliasAtom : public SimpleDefinedAtom { +public: + AliasAtom(const File &file, StringRef name) + : SimpleDefinedAtom(file), _target(nullptr), _name(name), + _merge(DefinedAtom::mergeNo), _deadStrip(DefinedAtom::deadStripNormal) { + } + + StringRef name() const override { return _name; } + uint64_t size() const override { return 0; } + ArrayRef rawContent() const override { return ArrayRef(); } + + Scope scope() const override { + getTarget(); + return _target ? _target->scope() : scopeLinkageUnit; + } + + Merge merge() const override { + if (_merge.hasValue()) + return _merge.getValue(); + getTarget(); + return _target ? _target->merge() : mergeNo; + } + + void setMerge(Merge val) { _merge = val; } + + ContentType contentType() const override { + getTarget(); + return _target ? _target->contentType() : typeUnknown; + } + + Interposable interposable() const override { + getTarget(); + return _target ? _target->interposable() : interposeNo; + } + + SectionChoice sectionChoice() const override { + getTarget(); + return _target ? _target->sectionChoice() : sectionBasedOnContent; + } + + StringRef customSectionName() const override { + getTarget(); + return _target ? _target->customSectionName() : StringRef(""); + } + + DeadStripKind deadStrip() const override { return _deadStrip; } + void setDeadStrip(DeadStripKind val) { _deadStrip = val; } + +private: + void getTarget() const { + if (_target) + return; + for (const Reference *r : *this) { + if (r->kindNamespace() == lld::Reference::KindNamespace::all && + r->kindValue() == lld::Reference::kindLayoutAfter) { + _target = dyn_cast(r->target()); + return; + } + } + } + + mutable const DefinedAtom *_target; + std::string _name; + llvm::Optional _merge; + DeadStripKind _deadStrip; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/Core/ArchiveLibraryFile.h b/include/lld/Core/ArchiveLibraryFile.h new file mode 100644 index 000000000000..ff379d4f3ecf --- /dev/null +++ b/include/lld/Core/ArchiveLibraryFile.h @@ -0,0 +1,60 @@ +//===- Core/ArchiveLibraryFile.h - Models static library ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H +#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H + +#include "lld/Core/File.h" +#include "lld/Core/Parallel.h" +#include + +namespace lld { + +/// +/// The ArchiveLibraryFile subclass of File is used to represent unix +/// static library archives. These libraries provide no atoms to the +/// initial set of atoms linked. Instead, when the Resolver will query +/// ArchiveLibraryFile instances for specific symbols names using the +/// find() method. If the archive contains an object file which has a +/// DefinedAtom whose scope is not translationUnit, then that entire +/// object file File is returned. +/// +class ArchiveLibraryFile : public File { +public: + static bool classof(const File *f) { + return f->kind() == kindArchiveLibrary; + } + + /// Check if any member of the archive contains an Atom with the + /// specified name and return the File object for that member, or nullptr. + virtual File *find(StringRef name, bool dataSymbolOnly) = 0; + + virtual std::error_code + parseAllMembers(std::vector> &result) = 0; + + // Parses a member file containing a given symbol, so that when you + // need the file find() can return that immediately. Calling this function + // has no side effect other than pre-instantiating a file. Calling this + // function doesn't affect correctness. + virtual void preload(TaskGroup &group, StringRef symbolName) {} + + /// Returns a set of all defined symbols in the archive, i.e. all + /// resolvable symbol using this file. + virtual std::set getDefinedSymbols() { + return std::set(); + } + +protected: + /// only subclasses of ArchiveLibraryFile can be instantiated + ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {} +}; + +} // namespace lld + +#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h new file mode 100644 index 000000000000..27fdde022ba7 --- /dev/null +++ b/include/lld/Core/Atom.h @@ -0,0 +1,76 @@ +//===- Core/Atom.h - A node in linking graph ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ATOM_H +#define LLD_CORE_ATOM_H + +#include "lld/Core/LLVM.h" + +namespace lld { + +class File; + +/// +/// The linker has a Graph Theory model of linking. An object file is seen +/// as a set of Atoms with References to other Atoms. Each Atom is a node +/// and each Reference is an edge. An Atom can be a DefinedAtom which has +/// content or a UndefinedAtom which is a placeholder and represents an +/// undefined symbol (extern declaration). +/// +class Atom { +public: + /// Whether this atom is defined or a proxy for an undefined symbol + enum Definition { + definitionRegular, ///< Normal C/C++ function or global variable. + definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content. + definitionUndefined, ///< Only in .o files to model reference to undef. + definitionSharedLibrary ///< Only in shared libraries to model export. + }; + + /// The scope in which this atom is acessible to other atoms. + enum Scope { + scopeTranslationUnit, ///< Accessible only to atoms in the same translation + /// unit (e.g. a C static). + scopeLinkageUnit, ///< Accessible to atoms being linked but not visible + /// to runtime loader (e.g. visibility=hidden). + scopeGlobal ///< Accessible to all atoms and visible to runtime + /// loader (e.g. visibility=default). + }; + + + /// file - returns the File that produced/owns this Atom + virtual const File& file() const = 0; + + /// name - The name of the atom. For a function atom, it is the (mangled) + /// name of the function. + virtual StringRef name() const = 0; + + /// definition - Whether this atom is a definition or represents an undefined + /// symbol. + Definition definition() const { return _definition; } + + static bool classof(const Atom *a) { return true; } + +protected: + /// Atom is an abstract base class. Only subclasses can access constructor. + explicit Atom(Definition def) : _definition(def) {} + + /// The memory for Atom objects is always managed by the owning File + /// object. Therefore, no one but the owning File object should call + /// delete on an Atom. In fact, some File objects may bulk allocate + /// an array of Atoms, so they cannot be individually deleted by anyone. + virtual ~Atom() {} + +private: + Definition _definition; +}; + +} // namespace lld + +#endif // LLD_CORE_ATOM_H diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h new file mode 100644 index 000000000000..86d880c659b4 --- /dev/null +++ b/include/lld/Core/DefinedAtom.h @@ -0,0 +1,368 @@ +//===- Core/DefinedAtom.h - An Atom with content --------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_DEFINED_ATOM_H +#define LLD_CORE_DEFINED_ATOM_H + +#include "lld/Core/Atom.h" +#include "lld/Core/LLVM.h" + +namespace lld { +class File; +class Reference; + +/// \brief The fundamental unit of linking. +/// +/// A C function or global variable is an atom. An atom has content and +/// attributes. The content of a function atom is the instructions that +/// implement the function. The content of a global variable atom is its +/// initial bytes. +/// +/// Here are some example attribute sets for common atoms. If a particular +/// attribute is not listed, the default values are: definition=regular, +/// sectionChoice=basedOnContent, scope=translationUnit, merge=no, +/// deadStrip=normal, interposable=no +/// +/// C function: void foo() {}
    +/// name=foo, type=code, perm=r_x, scope=global +/// +/// C static function: staic void func() {}
    +/// name=func, type=code, perm=r_x +/// +/// C global variable: int count = 1;
    +/// name=count, type=data, perm=rw_, scope=global +/// +/// C tentative definition: int bar;
    +/// name=bar, type=zerofill, perm=rw_, scope=global, +/// merge=asTentative, interposable=yesAndRuntimeWeak +/// +/// Uninitialized C static variable: static int stuff;
    +/// name=stuff, type=zerofill, perm=rw_ +/// +/// Weak C function: __attribute__((weak)) void foo() {}
    +/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak +/// +/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}
    +/// name=foo, type=code, perm=r_x, scope=linkageUnit +/// +/// No-dead-strip function: __attribute__((used)) void foo() {}
    +/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never +/// +/// Non-inlined C++ inline method: inline void Foo::doit() {}
    +/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global, +/// mergeDupes=asWeak +/// +/// Non-inlined C++ inline method whose address is taken: +/// inline void Foo::doit() {}
    +/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global, +/// mergeDupes=asAddressedWeak +/// +/// literal c-string: "hello"
    +/// name="" type=cstring, perm=r__, scope=linkageUnit +/// +/// literal double: 1.234
    +/// name="" type=literal8, perm=r__, scope=linkageUnit +/// +/// constant: { 1,2,3 }
    +/// name="" type=constant, perm=r__, scope=linkageUnit +/// +/// Pointer to initializer function:
    +/// name="" type=initializer, perm=rw_l, +/// sectionChoice=customRequired +/// +/// C function place in custom section: __attribute__((section("__foo"))) +/// void foo() {}
    +/// name=foo, type=code, perm=r_x, scope=global, +/// sectionChoice=customRequired, customSectionName=__foo +/// +class DefinedAtom : public Atom { +public: + enum Interposable { + interposeNo, // linker can directly bind uses of this atom + interposeYes, // linker must indirect (through GOT) uses + interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final + // linked image + }; + + enum Merge { + mergeNo, // Another atom with same name is error + mergeAsTentative, // Is ANSI C tentative definition, can be coalesced + mergeAsWeak, // Is C++ inline definition that was not inlined, + // but address was not taken, so atom can be hidden + // by linker + mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose + // address was taken. + mergeSameNameAndSize, // Another atom with different size is error + mergeByLargestSection, // Choose an atom whose section is the largest. + mergeByContent, // Merge with other constants with same content. + }; + + enum ContentType { + typeUnknown, // for use with definitionUndefined + typeCode, // executable code + typeResolver, // function which returns address of target + typeBranchIsland, // linker created for large binaries + typeBranchShim, // linker created to switch thumb mode + typeStub, // linker created for calling external function + typeStubHelper, // linker created for initial stub binding + typeConstant, // a read-only constant + typeCString, // a zero terminated UTF8 C string + typeUTF16String, // a zero terminated UTF16 string + typeCFI, // a FDE or CIE from dwarf unwind info + typeLSDA, // extra unwinding info + typeLiteral4, // a four-btye read-only constant + typeLiteral8, // an eight-btye read-only constant + typeLiteral16, // a sixteen-btye read-only constant + typeData, // read-write data + typeDataFast, // allow data to be quickly accessed + typeZeroFill, // zero-fill data + typeZeroFillFast, // allow zero-fill data to be quicky accessed + typeConstData, // read-only data after dynamic linker is done + typeObjC1Class, // ObjC1 class [Darwin] + typeLazyPointer, // pointer through which a stub jumps + typeLazyDylibPointer, // pointer through which a stub jumps [Darwin] + typeCFString, // NS/CFString object [Darwin] + typeGOT, // pointer to external symbol + typeInitializerPtr, // pointer to initializer function + typeTerminatorPtr, // pointer to terminator function + typeCStringPtr, // pointer to UTF8 C string [Darwin] + typeObjCClassPtr, // pointer to ObjC class [Darwin] + typeObjC2CategoryList, // pointers to ObjC category [Darwin] + typeDTraceDOF, // runtime data for Dtrace [Darwin] + typeInterposingTuples, // tuples of interposing info for dyld [Darwin] + typeTempLTO, // temporary atom for bitcode reader + typeCompactUnwindInfo, // runtime data for unwinder [Darwin] + typeProcessedUnwindInfo,// compressed compact unwind info [Darwin] + typeThunkTLV, // thunk used to access a TLV [Darwin] + typeTLVInitialData, // initial data for a TLV [Darwin] + typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin] + typeTLVInitializerPtr, // pointer to thread local initializer [Darwin] + typeMachHeader, // atom representing mach_header [Darwin] + typeThreadZeroFill, // Uninitialized thread local data(TBSS) [ELF] + typeThreadData, // Initialized thread local data(TDATA) [ELF] + typeRONote, // Identifies readonly note sections [ELF] + typeRWNote, // Identifies readwrite note sections [ELF] + typeNoAlloc, // Identifies non allocatable sections [ELF] + typeGroupComdat, // Identifies a section group [ELF, COFF] + typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF] + }; + + // Permission bits for atoms and segments. The order of these values are + // important, because the layout pass may sort atoms by permission if other + // attributes are the same. + enum ContentPermissions { + perm___ = 0, // mapped as unaccessible + permR__ = 8, // mapped read-only + permRW_ = 8 + 2, // mapped readable and writable + permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only + // loader writable + permR_X = 8 + 4, // mapped readable and executable + permRWX = 8 + 2 + 4, // mapped readable and writable and executable + permUnknown = 16 // unknown or invalid permissions + }; + + enum SectionChoice { + sectionBasedOnContent, // linker infers final section based on content + sectionCustomPreferred, // linker may place in specific section + sectionCustomRequired // linker must place in specific section + }; + + enum DeadStripKind { + deadStripNormal, // linker may dead strip this atom + deadStripNever, // linker must never dead strip this atom + deadStripAlways // linker must remove this atom if unused + }; + + enum DynamicExport { + /// \brief The linker may or may not export this atom dynamically depending + /// on the output type and other context of the link. + dynamicExportNormal, + /// \brief The linker will always export this atom dynamically. + dynamicExportAlways, + }; + + // Attributes describe a code model used by the atom. + enum CodeModel { + codeNA, // no specific code model + codeMipsPIC, // PIC function in a PIC / non-PIC mixed file + codeMipsMicro, // microMIPS instruction encoding + codeMipsMicroPIC, // microMIPS instruction encoding + PIC + codeMips16, // MIPS-16 instruction encoding + codeARMThumb, // ARM Thumb instruction set + }; + + struct Alignment { + Alignment(int p2, int m = 0) + : powerOf2(p2) + , modulus(m) {} + + uint16_t powerOf2; + uint16_t modulus; + + bool operator==(const Alignment &rhs) const { + return (powerOf2 == rhs.powerOf2) && (modulus == rhs.modulus); + } + }; + + /// \brief returns a value for the order of this Atom within its file. + /// + /// This is used by the linker to order the layout of Atoms so that the + /// resulting image is stable and reproducible. + /// + /// Note that this should not be confused with ordinals of exported symbols in + /// Windows DLLs. In Windows terminology, ordinals are symbols' export table + /// indices (small integers) which can be used instead of symbol names to + /// refer items in a DLL. + virtual uint64_t ordinal() const = 0; + + /// \brief the number of bytes of space this atom's content will occupy in the + /// final linked image. + /// + /// For a function atom, it is the number of bytes of code in the function. + virtual uint64_t size() const = 0; + + /// \brief The size of the section from which the atom is instantiated. + /// + /// Merge::mergeByLargestSection is defined in terms of section size + /// and not in terms of atom size, so we need this function separate + /// from size(). + virtual uint64_t sectionSize() const { return 0; } + + /// \brief The visibility of this atom to other atoms. + /// + /// C static functions have scope scopeTranslationUnit. Regular C functions + /// have scope scopeGlobal. Functions compiled with visibility=hidden have + /// scope scopeLinkageUnit so they can be see by other atoms being linked but + /// not by the OS loader. + virtual Scope scope() const = 0; + + /// \brief Whether the linker should use direct or indirect access to this + /// atom. + virtual Interposable interposable() const = 0; + + /// \brief how the linker should handle if multiple atoms have the same name. + virtual Merge merge() const = 0; + + /// \brief The type of this atom, such as code or data. + virtual ContentType contentType() const = 0; + + /// \brief The alignment constraints on how this atom must be laid out in the + /// final linked image (e.g. 16-byte aligned). + virtual Alignment alignment() const = 0; + + /// \brief Whether this atom must be in a specially named section in the final + /// linked image, or if the linker can infer the section based on the + /// contentType(). + virtual SectionChoice sectionChoice() const = 0; + + /// \brief If sectionChoice() != sectionBasedOnContent, then this return the + /// name of the section the atom should be placed into. + virtual StringRef customSectionName() const = 0; + + /// \brief constraints on whether the linker may dead strip away this atom. + virtual DeadStripKind deadStrip() const = 0; + + /// \brief Under which conditions should this atom be dynamically exported. + virtual DynamicExport dynamicExport() const { + return dynamicExportNormal; + } + + /// \brief Code model used by the atom. + virtual CodeModel codeModel() const { return codeNA; } + + /// \brief Returns the OS memory protections required for this atom's content + /// at runtime. + /// + /// A function atom is R_X, a global variable is RW_, and a read-only constant + /// is R__. + virtual ContentPermissions permissions() const; + + /// \brief returns a reference to the raw (unrelocated) bytes of this Atom's + /// content. + virtual ArrayRef rawContent() const = 0; + + /// This class abstracts iterating over the sequence of References + /// in an Atom. Concrete instances of DefinedAtom must implement + /// the derefIterator() and incrementIterator() methods. + class reference_iterator { + public: + reference_iterator(const DefinedAtom &a, const void *it) + : _atom(a), _it(it) { } + + const Reference *operator*() const { + return _atom.derefIterator(_it); + } + + const Reference *operator->() const { + return _atom.derefIterator(_it); + } + + bool operator!=(const reference_iterator &other) const { + return _it != other._it; + } + + reference_iterator &operator++() { + _atom.incrementIterator(_it); + return *this; + } + private: + const DefinedAtom &_atom; + const void *_it; + }; + + /// \brief Returns an iterator to the beginning of this Atom's References. + virtual reference_iterator begin() const = 0; + + /// \brief Returns an iterator to the end of this Atom's References. + virtual reference_iterator end() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionRegular; + } + + /// Utility for deriving permissions from content type + static ContentPermissions permissions(ContentType type); + + /// Utility function to check if the atom occupies file space + bool occupiesDiskSpace() const { + ContentType atomContentType = contentType(); + return !(atomContentType == DefinedAtom::typeZeroFill || + atomContentType == DefinedAtom::typeZeroFillFast || + atomContentType == DefinedAtom::typeTLVInitialZeroFill || + atomContentType == DefinedAtom::typeThreadZeroFill); + } + + /// Utility function to check if the atom belongs to a group section + /// that represents section groups or .gnu.linkonce sections. + bool isGroupParent() const { + ContentType atomContentType = contentType(); + return (atomContentType == DefinedAtom::typeGroupComdat || + atomContentType == DefinedAtom::typeGnuLinkOnce); + } + + // Returns true if lhs should be placed before rhs in the final output. + static bool compareByPosition(const DefinedAtom *lhs, + const DefinedAtom *rhs); + +protected: + // DefinedAtom is an abstract base class. Only subclasses can access + // constructor. + DefinedAtom() : Atom(definitionRegular) { } + + /// \brief Returns a pointer to the Reference object that the abstract + /// iterator "points" to. + virtual const Reference *derefIterator(const void *iter) const = 0; + + /// \brief Adjusts the abstract iterator to "point" to the next Reference + /// object for this Atom. + virtual void incrementIterator(const void *&iter) const = 0; +}; +} // end namespace lld + +#endif diff --git a/include/lld/Core/Error.h b/include/lld/Core/Error.h new file mode 100644 index 000000000000..7caa25018f40 --- /dev/null +++ b/include/lld/Core/Error.h @@ -0,0 +1,82 @@ +//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the lld library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ERROR_H +#define LLD_CORE_ERROR_H + +#include "lld/Core/LLVM.h" +#include + +namespace lld { + +const std::error_category &native_reader_category(); + +enum class NativeReaderError { + success = 0, + unknown_file_format, + file_too_short, + file_malformed, + unknown_chunk_type, + memory_error, + conflicting_target_machine, +}; + +inline std::error_code make_error_code(NativeReaderError e) { + return std::error_code(static_cast(e), native_reader_category()); +} + +const std::error_category &YamlReaderCategory(); + +enum class YamlReaderError { + success = 0, + unknown_keyword, + illegal_value +}; + +inline std::error_code make_error_code(YamlReaderError e) { + return std::error_code(static_cast(e), YamlReaderCategory()); +} + +const std::error_category &LinkerScriptReaderCategory(); + +enum class LinkerScriptReaderError { + success = 0, + parse_error, + unknown_symbol_in_expr, + unrecognized_function_in_expr +}; + +inline std::error_code make_error_code(LinkerScriptReaderError e) { + return std::error_code(static_cast(e), LinkerScriptReaderCategory()); +} + +/// Creates an error_code object that has associated with it an arbitrary +/// error messsage. The value() of the error_code will always be non-zero +/// but its value is meaningless. The messsage() will be (a copy of) the +/// supplied error string. +/// Note: Once ErrorOr<> is updated to work with errors other than error_code, +/// this can be updated to return some other kind of error. +std::error_code make_dynamic_error_code(StringRef msg); +std::error_code make_dynamic_error_code(const Twine &msg); + +} // end namespace lld + +namespace std { +template <> +struct is_error_code_enum : std::true_type {}; +template <> struct is_error_code_enum : std::true_type {}; +template <> +struct is_error_code_enum : std::true_type {}; +} + +#endif diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h new file mode 100644 index 000000000000..25b177ec879c --- /dev/null +++ b/include/lld/Core/File.h @@ -0,0 +1,324 @@ +//===- Core/File.h - A Container of Atoms ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_FILE_H +#define LLD_CORE_FILE_H + +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "lld/Core/range.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include + +namespace lld { + +class LinkingContext; + +/// Every Atom is owned by some File. A common scenario is for a single +/// object file (.o) to be parsed by some reader and produce a single +/// File object that represents the content of that object file. +/// +/// To iterate through the Atoms in a File there are four methods that +/// return collections. For instance to iterate through all the DefinedAtoms +/// in a File object use: +/// for (const DefinedAtoms *atom : file->defined()) { +/// } +/// +/// The Atom objects in a File are owned by the File object. The Atom objects +/// are destroyed when the File object is destroyed. +class File { +public: + virtual ~File(); + + /// \brief Kinds of files that are supported. + enum Kind { + kindObject, ///< object file (.o) + kindSharedLibrary, ///< shared library (.so) + kindArchiveLibrary ///< archive (.a) + }; + + /// \brief Returns file kind. Need for dyn_cast<> on File objects. + Kind kind() const { + return _kind; + } + + /// This returns the path to the file which was used to create this object + /// (e.g. "/tmp/foo.o"). If the file is a member of an archive file, the + /// returned string includes the archive file name. + StringRef path() const { + if (_archivePath.empty()) + return _path; + if (_archiveMemberPath.empty()) + _archiveMemberPath = (_archivePath + "(" + _path + ")").str(); + return _archiveMemberPath; + } + + /// Returns the path of the archive file name if this file is instantiated + /// from an archive file. Otherwise returns the empty string. + StringRef archivePath() const { return _archivePath; } + void setArchivePath(StringRef path) { _archivePath = path; } + + /// Returns the path name of this file. It doesn't include archive file name. + StringRef memberPath() const { return _path; } + + /// Returns the command line order of the file. + uint64_t ordinal() const { + assert(_ordinal != UINT64_MAX); + return _ordinal; + } + + /// Returns true/false depending on whether an ordinal has been set. + bool hasOrdinal() const { return (_ordinal != UINT64_MAX); } + + /// Sets the command line order of the file. + void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; } + + template class atom_iterator; // forward reference + + /// For allocating any objects owned by this File. + llvm::BumpPtrAllocator &allocator() const { + return _allocator; + } + + /// \brief For use interating over DefinedAtoms in this File. + typedef atom_iterator defined_iterator; + + /// \brief For use interating over UndefinedAtoms in this File. + typedef atom_iterator undefined_iterator; + + /// \brief For use interating over SharedLibraryAtoms in this File. + typedef atom_iterator shared_library_iterator; + + /// \brief For use interating over AbsoluteAtoms in this File. + typedef atom_iterator absolute_iterator; + + /// \brief Different object file readers may instantiate and manage atoms with + /// different data structures. This class is a collection abstraction. + /// Each concrete File instance must implement these atom_collection + /// methods to enable clients to interate the File's atoms. + template + class atom_collection { + public: + virtual ~atom_collection() { } + virtual atom_iterator begin() const = 0; + virtual atom_iterator end() const = 0; + virtual const T *deref(const void *it) const = 0; + virtual void next(const void *&it) const = 0; + virtual uint64_t size() const = 0; + bool empty() const { return size() == 0; } + }; + + /// \brief The class is the iterator type used to iterate through a File's + /// Atoms. This iterator delegates the work to the associated atom_collection + /// object. There are four kinds of Atoms, so this iterator is templated on + /// the four base Atom kinds. + template + class atom_iterator : public std::iterator { + public: + atom_iterator(const atom_collection &c, const void *it) + : _collection(&c), _it(it) { } + + const T *operator*() const { + return _collection->deref(_it); + } + const T *operator->() const { + return _collection->deref(_it); + } + + friend bool operator==(const atom_iterator &lhs, const atom_iterator &rhs) { + return lhs._it == rhs._it; + } + + friend bool operator!=(const atom_iterator &lhs, const atom_iterator &rhs) { + return !(lhs == rhs); + } + + atom_iterator &operator++() { + _collection->next(_it); + return *this; + } + private: + const atom_collection *_collection; + const void *_it; + }; + + /// \brief Must be implemented to return the atom_collection object for + /// all DefinedAtoms in this File. + virtual const atom_collection &defined() const = 0; + + /// \brief Must be implemented to return the atom_collection object for + /// all UndefinedAtomw in this File. + virtual const atom_collection &undefined() const = 0; + + /// \brief Must be implemented to return the atom_collection object for + /// all SharedLibraryAtoms in this File. + virtual const atom_collection &sharedLibrary() const = 0; + + /// \brief Must be implemented to return the atom_collection object for + /// all AbsoluteAtoms in this File. + virtual const atom_collection &absolute() const = 0; + + /// \brief If a file is parsed using a different method than doParse(), + /// one must use this method to set the last error status, so that + /// doParse will not be called twice. Only YAML reader uses this + /// (because YAML reader does not read blobs but structured data). + void setLastError(std::error_code err) { _lastError = err; } + + std::error_code parse(); + + // This function is called just before the core linker tries to use + // a file. Currently the PECOFF reader uses this to trigger the + // driver to parse .drectve section (which contains command line options). + // If you want to do something having side effects, don't do that in + // doParse() because a file could be pre-loaded speculatively. + // Use this hook instead. + virtual void beforeLink() {} + + // Usually each file owns a std::unique_ptr. + // However, there's one special case. If a file is an archive file, + // the archive file and its children all shares the same memory buffer. + // This method is used by the ArchiveFile to give its children + // co-ownership of the buffer. + void setSharedMemoryBuffer(std::shared_ptr mb) { + _sharedMemoryBuffer = mb; + } + +protected: + /// \brief only subclasses of File can be instantiated + File(StringRef p, Kind kind) + : _path(p), _kind(kind), _ordinal(UINT64_MAX) {} + + /// \brief Subclasses should override this method to parse the + /// memory buffer passed to this file's constructor. + virtual std::error_code doParse() { return std::error_code(); } + + /// \brief This is a convenience class for File subclasses which manage their + /// atoms as a simple std::vector<>. + template + class atom_collection_vector : public atom_collection { + public: + atom_iterator begin() const override { + auto *it = _atoms.empty() ? nullptr + : reinterpret_cast(_atoms.data()); + return atom_iterator(*this, it); + } + + atom_iterator end() const override { + auto *it = _atoms.empty() ? nullptr : reinterpret_cast( + _atoms.data() + _atoms.size()); + return atom_iterator(*this, it); + } + + const T *deref(const void *it) const override { + return *reinterpret_cast(it); + } + + void next(const void *&it) const override { + const T *const *p = reinterpret_cast(it); + ++p; + it = reinterpret_cast(p); + } + + uint64_t size() const override { return _atoms.size(); } + + std::vector _atoms; + }; + + /// \brief This is a convenience class for File subclasses which need to + /// return an empty collection. + template + class atom_collection_empty : public atom_collection { + public: + atom_iterator begin() const override { + return atom_iterator(*this, nullptr); + } + atom_iterator end() const override { + return atom_iterator(*this, nullptr); + } + const T *deref(const void *it) const override { + llvm_unreachable("empty collection should never be accessed"); + } + void next(const void *&it) const override {} + uint64_t size() const override { return 0; } + }; + + static atom_collection_empty _noDefinedAtoms; + static atom_collection_empty _noUndefinedAtoms; + static atom_collection_empty _noSharedLibraryAtoms; + static atom_collection_empty _noAbsoluteAtoms; + mutable llvm::BumpPtrAllocator _allocator; + +private: + StringRef _path; + std::string _archivePath; + mutable std::string _archiveMemberPath; + Kind _kind; + mutable uint64_t _ordinal; + std::shared_ptr _sharedMemoryBuffer; + llvm::Optional _lastError; + std::mutex _parseMutex; +}; + +/// \brief A mutable File. +class MutableFile : public File { +public: + /// \brief Add an atom to the file. Invalidates iterators for all returned + /// containters. + virtual void addAtom(const Atom&) = 0; + + typedef range::iterator> DefinedAtomRange; + virtual DefinedAtomRange definedAtoms() = 0; + + virtual void + removeDefinedAtomsIf(std::function pred) = 0; + +protected: + /// \brief only subclasses of MutableFile can be instantiated + MutableFile(StringRef p) : File(p, kindObject) {} +}; + +/// An ErrorFile represents a file that doesn't exist. +/// If you try to parse a file which doesn't exist, an instance of this +/// class will be returned. That's parse method always returns an error. +/// This is useful to delay erroring on non-existent files, so that we +/// can do unit testing a driver using non-existing file paths. +class ErrorFile : public File { +public: + ErrorFile(StringRef path, std::error_code ec) + : File(path, kindObject), _ec(ec) {} + + std::error_code doParse() override { return _ec; } + + const atom_collection &defined() const override { + llvm_unreachable("internal error"); + } + const atom_collection &undefined() const override { + llvm_unreachable("internal error"); + } + const atom_collection &sharedLibrary() const override { + llvm_unreachable("internal error"); + } + const atom_collection &absolute() const override { + llvm_unreachable("internal error"); + } + +private: + std::error_code _ec; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h new file mode 100644 index 000000000000..162375905e17 --- /dev/null +++ b/include/lld/Core/Instrumentation.h @@ -0,0 +1,132 @@ +//===- include/Core/Instrumentation.h - Instrumentation API ---------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provide an Instrumentation API that optionally uses VTune interfaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_INSTRUMENTATION_H +#define LLD_CORE_INSTRUMENTATION_H + +#include "llvm/Support/Compiler.h" +#include + +#ifdef LLD_HAS_VTUNE +# include +#endif + +namespace lld { +#ifdef LLD_HAS_VTUNE +/// \brief A unique global scope for instrumentation data. +/// +/// Domains last for the lifetime of the application and cannot be destroyed. +/// Multiple Domains created with the same name represent the same domain. +class Domain { + __itt_domain *_domain; + +public: + explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {} + + operator __itt_domain *() const { return _domain; } + __itt_domain *operator->() const { return _domain; } +}; + +/// \brief A global reference to a string constant. +/// +/// These are uniqued by the ITT runtime and cannot be deleted. They are not +/// specific to a domain. +/// +/// Prefer reusing a single StringHandle over passing a ntbs when the same +/// string will be used often. +class StringHandle { + __itt_string_handle *_handle; + +public: + StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {} + + operator __itt_string_handle *() const { return _handle; } +}; + +/// \brief A task on a single thread. Nests within other tasks. +/// +/// Each thread has its own task stack and tasks nest recursively on that stack. +/// A task cannot transfer threads. +/// +/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of +/// a task is either the lifetime of this object, or until end is called. +class ScopedTask { + __itt_domain *_domain; + + ScopedTask(const ScopedTask &) = delete; + ScopedTask &operator=(const ScopedTask &) = delete; + +public: + /// \brief Create a task in Domain \p d named \p s. + ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) { + __itt_task_begin(d, __itt_null, __itt_null, s); + } + + ScopedTask(ScopedTask &&other) { + *this = std::move(other); + } + + ScopedTask &operator=(ScopedTask &&other) { + _domain = other._domain; + other._domain = nullptr; + return *this; + } + + /// \brief Prematurely end this task. + void end() { + if (_domain) + __itt_task_end(_domain); + _domain = nullptr; + } + + ~ScopedTask() { end(); } +}; + +/// \brief A specific point in time. Allows metadata to be associated. +class Marker { +public: + Marker(const Domain &d, const StringHandle &s) { + __itt_marker(d, __itt_null, s, __itt_scope_global); + } +}; +#else +class Domain { +public: + Domain(const char *name) {} +}; + +class StringHandle { +public: + StringHandle(const char *name) {} +}; + +class ScopedTask { +public: + ScopedTask(const Domain &d, const StringHandle &s) {} + void end() {} +}; + +class Marker { +public: + Marker(const Domain &d, const StringHandle &s) {} +}; +#endif + +inline const Domain &getDefaultDomain() { + static Domain domain("org.llvm.lld"); + return domain; +} +} // end namespace lld. + +#endif diff --git a/include/lld/Core/LLVM.h b/include/lld/Core/LLVM.h new file mode 100644 index 000000000000..1bc1173bd48b --- /dev/null +++ b/include/lld/Core/LLVM.h @@ -0,0 +1,75 @@ +//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file forward declares and imports various common LLVM datatypes that +// lld wants to use unqualified. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_LLVM_H +#define LLD_CORE_LLVM_H + +// This should be the only #include, force #includes of all the others on +// clients. +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Casting.h" +#include + +namespace llvm { + // ADT's. + class StringRef; + class Twine; + class MemoryBuffer; + template class ArrayRef; + template class SmallString; + template class SmallVector; + template class SmallVectorImpl; + + template + struct SaveAndRestore; + + template + class ErrorOr; + + class raw_ostream; + // TODO: DenseMap, ... +} + +namespace lld { + // Casting operators. + using llvm::isa; + using llvm::cast; + using llvm::dyn_cast; + using llvm::dyn_cast_or_null; + using llvm::cast_or_null; + + // ADT's. + using llvm::StringRef; + using llvm::Twine; + using llvm::MemoryBuffer; + using llvm::ArrayRef; + using llvm::SmallString; + using llvm::SmallVector; + using llvm::SmallVectorImpl; + using llvm::SaveAndRestore; + using llvm::ErrorOr; + + using llvm::raw_ostream; +} // end namespace lld. + +namespace std { +template <> struct hash { +public: + size_t operator()(const llvm::StringRef &s) const { + return llvm::hash_value(s); + } +}; +} + +#endif diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h new file mode 100644 index 000000000000..81a3b4b4eb71 --- /dev/null +++ b/include/lld/Core/LinkingContext.h @@ -0,0 +1,364 @@ +//===- lld/Core/LinkingContext.h - Linker Target Info Interface -----------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_LINKING_CONTEXT_H +#define LLD_CORE_LINKING_CONTEXT_H + +#include "lld/Core/Error.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Node.h" +#include "lld/Core/Parallel.h" +#include "lld/Core/Reference.h" +#include "lld/Core/range.h" +#include "lld/Core/Reader.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +namespace lld { +class PassManager; +class File; +class Writer; +class Node; +class SharedLibraryFile; + +/// \brief The LinkingContext class encapsulates "what and how" to link. +/// +/// The base class LinkingContext contains the options needed by core linking. +/// Subclasses of LinkingContext have additional options needed by specific +/// Writers. For example, ELFLinkingContext has methods that supplies +/// options to the ELF Writer and ELF Passes. +class LinkingContext { +public: + /// \brief The types of output file that the linker creates. + enum class OutputFileType : uint8_t { + Default, // The default output type for this target + YAML, // The output type is set to YAML + Native // The output file format is Native (Atoms) + }; + + virtual ~LinkingContext(); + + /// \name Methods needed by core linking + /// @{ + + /// Name of symbol linker should use as "entry point" to program, + /// usually "main" or "start". + virtual StringRef entrySymbolName() const { return _entrySymbolName; } + + /// Whether core linking should remove Atoms not reachable by following + /// References from the entry point Atom or from all global scope Atoms + /// if globalsAreDeadStripRoots() is true. + bool deadStrip() const { return _deadStrip; } + + /// Only used if deadStrip() returns true. Means all global scope Atoms + /// should be marked live (along with all Atoms they reference). Usually + /// this method returns false for main executables, but true for dynamic + /// shared libraries. + bool globalsAreDeadStripRoots() const { return _globalsAreDeadStripRoots; }; + + /// Only used if deadStrip() returns true. This method returns the names + /// of DefinedAtoms that should be marked live (along with all Atoms they + /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can + /// be kept live using this method. + const std::vector &deadStripRoots() const { + return _deadStripRoots; + } + + /// Add the given symbol name to the dead strip root set. Only used if + /// deadStrip() returns true. + void addDeadStripRoot(StringRef symbolName) { + assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root"); + _deadStripRoots.push_back(symbolName); + } + + /// Archive files (aka static libraries) are normally lazily loaded. That is, + /// object files within an archive are only loaded and linked in, if the + /// object file contains a DefinedAtom which will replace an existing + /// UndefinedAtom. If this method returns true, core linking will also look + /// for archive members to replace existing tentative definitions in addition + /// to replacing undefines. Note: a "tentative definition" (also called a + /// "common" symbols) is a C (but not C++) concept. They are modeled in lld + /// as a DefinedAtom with merge() of mergeAsTentative. + bool searchArchivesToOverrideTentativeDefinitions() const { + return _searchArchivesToOverrideTentativeDefinitions; + } + + /// Normally core linking will turn a tentative definition into a real + /// definition if not replaced by a real DefinedAtom from some object file. + /// If this method returns true, core linking will search all supplied + /// dynamic shared libraries for symbol names that match remaining tentative + /// definitions. If any are found, the corresponding tentative definition + /// atom is replaced with SharedLibraryAtom. + bool searchSharedLibrariesToOverrideTentativeDefinitions() const { + return _searchSharedLibrariesToOverrideTentativeDefinitions; + } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking prints out a list of remaining UndefinedAtoms. + /// + /// \todo This should be a method core linking calls with a list of the + /// UndefinedAtoms so that different drivers can format the error message + /// as needed. + bool printRemainingUndefines() const { return _printRemainingUndefines; } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines to be an error. + bool allowRemainingUndefines() const { return _allowRemainingUndefines; } + + /// In the lld model, a SharedLibraryAtom is a proxy atom for something + /// that will be found in a dynamic shared library when the program runs. + /// A SharedLibraryAtom optionally contains the name of the shared library + /// in which to find the symbol name at runtime. Core linking may merge + /// two SharedLibraryAtom with the same name. If this method returns true, + /// when merging core linking will also verify that they both have the same + /// loadName() and if not print a warning. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the warning as needed. + bool warnIfCoalesableAtomsHaveDifferentLoadName() const { + return _warnIfCoalesableAtomsHaveDifferentLoadName; + } + + /// In C/C++ you can mark a function's prototype with + /// __attribute__((weak_import)) or __attribute__((weak)) to say the function + /// may not be available at runtime and/or build time and in which case its + /// address will evaluate to NULL. In lld this is modeled using the + /// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom + /// with the same name are automatically merged. If this method returns + /// true, core link also verfies that the canBeNull() value for merged + /// UndefinedAtoms are the same and warns if not. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the warning as needed. + bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const { + return _warnIfCoalesableAtomsHaveDifferentCanBeNull; + } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines from the shared library + /// to be an error. + bool allowShlibUndefines() const { return _allowShlibUndefines; } + + /// If true, core linking will write the path to each input file to stdout + /// (i.e. llvm::outs()) as it is used. This is used to implement the -t + /// linker option. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the line as needed. + bool logInputFiles() const { return _logInputFiles; } + + /// Parts of LLVM use global variables which are bound to command line + /// options (see llvm::cl::Options). This method returns "command line" + /// options which are used to configure LLVM's command line settings. + /// For instance the -debug-only XXX option can be used to dynamically + /// trace different parts of LLVM and lld. + const std::vector &llvmOptions() const { return _llvmOptions; } + + /// \name Methods used by Drivers to configure TargetInfo + /// @{ + void setOutputPath(StringRef str) { _outputPath = str; } + + // Set the entry symbol name. You may also need to call addDeadStripRoot() for + // the symbol if your platform supports dead-stripping, so that the symbol + // will not be removed from the output. + void setEntrySymbolName(StringRef name) { + _entrySymbolName = name; + } + + void setDeadStripping(bool enable) { _deadStrip = enable; } + void setAllowDuplicates(bool enable) { _allowDuplicates = enable; } + void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; } + void setSearchArchivesToOverrideTentativeDefinitions(bool search) { + _searchArchivesToOverrideTentativeDefinitions = search; + } + void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) { + _searchSharedLibrariesToOverrideTentativeDefinitions = search; + } + void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) { + _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn; + } + void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) { + _warnIfCoalesableAtomsHaveDifferentLoadName = warn; + } + void setPrintRemainingUndefines(bool print) { + _printRemainingUndefines = print; + } + void setAllowRemainingUndefines(bool allow) { + _allowRemainingUndefines = allow; + } + void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; } + void setLogInputFiles(bool log) { _logInputFiles = log; } + + // Returns true if multiple definitions should not be treated as a + // fatal error. + bool getAllowDuplicates() const { return _allowDuplicates; } + + void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); } + + void addAlias(StringRef from, StringRef to) { _aliasSymbols[from] = to; } + const std::map &getAliases() const { + return _aliasSymbols; + } + + std::vector> &getNodes() { return _nodes; } + const std::vector> &getNodes() const { return _nodes; } + + /// Notify the LinkingContext when the symbol table found a name collision. + /// The useNew parameter specifies which the symbol table plans to keep, + /// but that can be changed by the LinkingContext. This is also an + /// opportunity for flavor specific processing. + virtual void notifySymbolTableCoalesce(const Atom *existingAtom, + const Atom *newAtom, bool &useNew) {} + + /// This method adds undefined symbols specified by the -u option to the to + /// the list of undefined symbols known to the linker. This option essentially + /// forces an undefined symbol to be created. You may also need to call + /// addDeadStripRoot() for the symbol if your platform supports dead + /// stripping, so that the symbol will not be removed from the output. + void addInitialUndefinedSymbol(StringRef symbolName) { + _initialUndefinedSymbols.push_back(symbolName); + } + + /// Iterators for symbols that appear on the command line. + typedef std::vector StringRefVector; + typedef StringRefVector::iterator StringRefVectorIter; + typedef StringRefVector::const_iterator StringRefVectorConstIter; + + /// Create linker internal files containing atoms for the linker to include + /// during link. Flavors can override this function in their LinkingContext + /// to add more internal files. These internal files are positioned before + /// the actual input files. + virtual void createInternalFiles(std::vector > &) const; + + /// Return the list of undefined symbols that are specified in the + /// linker command line, using the -u option. + range initialUndefinedSymbols() const { + return _initialUndefinedSymbols; + } + + /// After all set* methods are called, the Driver calls this method + /// to validate that there are no missing options or invalid combinations + /// of options. If there is a problem, a description of the problem + /// is written to the supplied stream. + /// + /// \returns true if there is an error with the current settings. + bool validate(raw_ostream &diagnostics); + + /// Formats symbol name for use in error messages. + virtual std::string demangle(StringRef symbolName) const { + return symbolName; + } + + /// @} + /// \name Methods used by Driver::link() + /// @{ + + /// Returns the file system path to which the linked output should be written. + /// + /// \todo To support in-memory linking, we need an abstraction that allows + /// the linker to write to an in-memory buffer. + StringRef outputPath() const { return _outputPath; } + + /// Set the various output file types that the linker would + /// create + bool setOutputFileType(StringRef outputFileType) { + if (outputFileType.equals_lower("yaml")) + _outputFileType = OutputFileType::YAML; + else if (outputFileType.equals_lower("native")) + _outputFileType = OutputFileType::YAML; + else + return false; + return true; + } + + /// Returns the output file type that that the linker needs to create. + OutputFileType outputFileType() const { return _outputFileType; } + + /// Accessor for Register object embedded in LinkingContext. + const Registry ®istry() const { return _registry; } + Registry ®istry() { return _registry; } + + /// This method is called by core linking to give the Writer a chance + /// to add file format specific "files" to set of files to be linked. This is + /// how file format specific atoms can be added to the link. + virtual bool createImplicitFiles(std::vector > &); + + /// This method is called by core linking to build the list of Passes to be + /// run on the merged/linked graph of all input files. + virtual void addPasses(PassManager &pm); + + /// Calls through to the writeFile() method on the specified Writer. + /// + /// \param linkedFile This is the merged/linked graph of all input file Atoms. + virtual std::error_code writeFile(const File &linkedFile) const; + + /// Return the next ordinal and Increment it. + virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; } + + // This function is called just before the Resolver kicks in. + // Derived classes may use it to change the list of input files. + virtual void finalizeInputFiles() {} + + TaskGroup &getTaskGroup() { return _taskGroup; } + + /// @} +protected: + LinkingContext(); // Must be subclassed + + /// Abstract method to lazily instantiate the Writer. + virtual Writer &writer() const = 0; + + /// Method to create an internal file for the entry symbol + virtual std::unique_ptr createEntrySymbolFile() const; + std::unique_ptr createEntrySymbolFile(StringRef filename) const; + + /// Method to create an internal file for an undefined symbol + virtual std::unique_ptr createUndefinedSymbolFile() const; + std::unique_ptr createUndefinedSymbolFile(StringRef filename) const; + + /// Method to create an internal file for alias symbols + std::unique_ptr createAliasSymbolFile() const; + + StringRef _outputPath; + StringRef _entrySymbolName; + bool _deadStrip; + bool _allowDuplicates; + bool _globalsAreDeadStripRoots; + bool _searchArchivesToOverrideTentativeDefinitions; + bool _searchSharedLibrariesToOverrideTentativeDefinitions; + bool _warnIfCoalesableAtomsHaveDifferentCanBeNull; + bool _warnIfCoalesableAtomsHaveDifferentLoadName; + bool _printRemainingUndefines; + bool _allowRemainingUndefines; + bool _logInputFiles; + bool _allowShlibUndefines; + OutputFileType _outputFileType; + std::vector _deadStripRoots; + std::map _aliasSymbols; + std::vector _llvmOptions; + StringRefVector _initialUndefinedSymbols; + std::vector> _nodes; + mutable llvm::BumpPtrAllocator _allocator; + mutable uint64_t _nextOrdinal; + Registry _registry; + +private: + /// Validate the subclass bits. Only called by validate. + virtual bool validateImpl(raw_ostream &diagnostics) = 0; + TaskGroup _taskGroup; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h new file mode 100644 index 000000000000..cd38fbd4a482 --- /dev/null +++ b/include/lld/Core/Node.h @@ -0,0 +1,78 @@ +//===- lld/Core/Node.h - Input file class ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// The classes in this file represents inputs to the linker. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_NODE_H +#define LLD_CORE_NODE_H + +#include "lld/Core/File.h" +#include "llvm/Option/ArgList.h" +#include +#include + +namespace lld { + +// A Node represents a FileNode or other type of Node. In the latter case, +// the node contains meta information about the input file list. +// Currently only GroupEnd node is defined as a meta node. +class Node { +public: + enum class Kind { File, GroupEnd }; + explicit Node(Kind type) : _kind(type) {} + virtual ~Node() {} + virtual Kind kind() const { return _kind; } + +private: + Kind _kind; +}; + +// This is a marker for --end-group. getSize() returns the number of +// files between the corresponding --start-group and this marker. +class GroupEnd : public Node { +public: + explicit GroupEnd(int size) : Node(Kind::GroupEnd), _size(size) {} + + int getSize() const { return _size; } + + static bool classof(const Node *a) { + return a->kind() == Kind::GroupEnd; + } + +private: + int _size; +}; + +// A container of File. +class FileNode : public Node { +public: + explicit FileNode(std::unique_ptr f) + : Node(Node::Kind::File), _file(std::move(f)), _asNeeded(false) {} + + static bool classof(const Node *a) { + return a->kind() == Node::Kind::File; + } + + File *getFile() { return _file.get(); } + + void setAsNeeded(bool val) { _asNeeded = val; } + bool asNeeded() const { return _asNeeded; } + +protected: + std::unique_ptr _file; + bool _asNeeded; +}; + +} // namespace lld + +#endif // LLD_CORE_NODE_H diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h new file mode 100644 index 000000000000..65176ac2b04d --- /dev/null +++ b/include/lld/Core/Parallel.h @@ -0,0 +1,309 @@ +//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PARALLEL_H +#define LLD_CORE_PARALLEL_H + +#include "lld/Core/Instrumentation.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/range.h" +#include "llvm/Support/MathExtras.h" + +#ifdef _MSC_VER +// concrt.h depends on eh.h for __uncaught_exception declaration +// even if we disable exceptions. +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#include +#endif + +namespace lld { +/// \brief Allows one or more threads to wait on a potentially unknown number of +/// events. +/// +/// A latch starts at \p count. inc() increments this, and dec() decrements it. +/// All calls to sync() will block while the count is not 0. +/// +/// Calling dec() on a Latch with a count of 0 has undefined behaivor. +class Latch { + uint32_t _count; + mutable std::mutex _condMut; + mutable std::condition_variable _cond; + +public: + explicit Latch(uint32_t count = 0) : _count(count) {} + ~Latch() { sync(); } + + void inc() { + std::unique_lock lock(_condMut); + ++_count; + } + + void dec() { + std::unique_lock lock(_condMut); + if (--_count == 0) + _cond.notify_all(); + } + + void sync() const { + std::unique_lock lock(_condMut); + _cond.wait(lock, [&] { + return _count == 0; + }); + } +}; + +/// \brief An implementation of future. std::future and std::promise in +/// old libstdc++ have a threading bug; there is a small chance that a +/// call of future::get throws an exception in the normal use case. +/// We want to use our own future implementation until we drop support +/// of old versions of libstdc++. +/// https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01389.html +template class Future { +public: + Future() : _hasValue(false) {} + + void set(T &&val) { + assert(!_hasValue); + { + std::unique_lock lock(_mutex); + _val = val; + _hasValue = true; + } + _cond.notify_all(); + } + + T &get() { + std::unique_lock lock(_mutex); + if (_hasValue) + return _val; + _cond.wait(lock, [&] { return _hasValue; }); + return _val; + } + +private: + T _val; + bool _hasValue; + std::mutex _mutex; + std::condition_variable _cond; +}; + +/// \brief An abstract class that takes closures and runs them asynchronously. +class Executor { +public: + virtual ~Executor() {} + virtual void add(std::function func) = 0; +}; + +/// \brief An implementation of an Executor that runs closures on a thread pool +/// in filo order. +class ThreadPoolExecutor : public Executor { +public: + explicit ThreadPoolExecutor(unsigned threadCount = + std::thread::hardware_concurrency()) + : _stop(false), _done(threadCount) { + // Spawn all but one of the threads in another thread as spawning threads + // can take a while. + std::thread([&, threadCount] { + for (std::size_t i = 1; i < threadCount; ++i) { + std::thread([=] { + work(); + }).detach(); + } + work(); + }).detach(); + } + + ~ThreadPoolExecutor() { + std::unique_lock lock(_mutex); + _stop = true; + lock.unlock(); + _cond.notify_all(); + // Wait for ~Latch. + } + + void add(std::function f) override { + std::unique_lock lock(_mutex); + _workStack.push(f); + lock.unlock(); + _cond.notify_one(); + } + +private: + void work() { + while (true) { + std::unique_lock lock(_mutex); + _cond.wait(lock, [&] { + return _stop || !_workStack.empty(); + }); + if (_stop) + break; + auto task = _workStack.top(); + _workStack.pop(); + lock.unlock(); + task(); + } + _done.dec(); + } + + std::atomic _stop; + std::stack> _workStack; + std::mutex _mutex; + std::condition_variable _cond; + Latch _done; +}; + +#ifdef _MSC_VER +/// \brief An Executor that runs tasks via ConcRT. +class ConcRTExecutor : public Executor { + struct Taskish { + Taskish(std::function task) : _task(task) {} + + std::function _task; + + static void run(void *p) { + Taskish *self = static_cast(p); + self->_task(); + concurrency::Free(self); + } + }; + +public: + virtual void add(std::function func) { + Concurrency::CurrentScheduler::ScheduleTask(Taskish::run, + new (concurrency::Alloc(sizeof(Taskish))) Taskish(func)); + } +}; + +inline Executor *getDefaultExecutor() { + static ConcRTExecutor exec; + return &exec; +} +#else +inline Executor *getDefaultExecutor() { + static ThreadPoolExecutor exec; + return &exec; +} +#endif + +/// \brief Allows launching a number of tasks and waiting for them to finish +/// either explicitly via sync() or implicitly on destruction. +class TaskGroup { + Latch _latch; + +public: + void spawn(std::function f) { + _latch.inc(); + getDefaultExecutor()->add([&, f] { + f(); + _latch.dec(); + }); + } + + void sync() const { _latch.sync(); } +}; + +#ifdef _MSC_VER +// Use ppl parallel_sort on Windows. +template +void parallel_sort( + RandomAccessIterator start, RandomAccessIterator end, + const Comp &comp = std::less< + typename std::iterator_traits::value_type>()) { + concurrency::parallel_sort(start, end, comp); +} +#else +namespace detail { +const ptrdiff_t minParallelSize = 1024; + +/// \brief Inclusive median. +template +RandomAccessIterator medianOf3(RandomAccessIterator start, + RandomAccessIterator end, const Comp &comp) { + RandomAccessIterator mid = start + (std::distance(start, end) / 2); + return comp(*start, *(end - 1)) + ? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start) + : end - 1) + : (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1) + : start); +} + +template +void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end, + const Comp &comp, TaskGroup &tg, size_t depth) { + // Do a sequential sort for small inputs. + if (std::distance(start, end) < detail::minParallelSize || depth == 0) { + std::sort(start, end, comp); + return; + } + + // Partition. + auto pivot = medianOf3(start, end, comp); + // Move pivot to end. + std::swap(*(end - 1), *pivot); + pivot = std::partition(start, end - 1, [&comp, end](decltype(*start) v) { + return comp(v, *(end - 1)); + }); + // Move pivot to middle of partition. + std::swap(*pivot, *(end - 1)); + + // Recurse. + tg.spawn([=, &comp, &tg] { + parallel_quick_sort(start, pivot, comp, tg, depth - 1); + }); + parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1); +} +} + +template +void parallel_sort( + RandomAccessIterator start, RandomAccessIterator end, + const Comp &comp = std::less< + typename std::iterator_traits::value_type>()) { + TaskGroup tg; + detail::parallel_quick_sort(start, end, comp, tg, + llvm::Log2_64(std::distance(start, end)) + 1); +} +#endif + +template void parallel_sort(T *start, T *end) { + parallel_sort(start, end, std::less()); +} + +#ifdef _MSC_VER +// Use ppl parallel_for_each on Windows. +template +void parallel_for_each(Iterator begin, Iterator end, Func func) { + concurrency::parallel_for_each(begin, end, func); +} +#else +template +void parallel_for_each(Iterator begin, Iterator end, Func func) { + TaskGroup tg; + ptrdiff_t taskSize = 1024; + while (taskSize <= std::distance(begin, end)) { + tg.spawn([=, &func] { std::for_each(begin, begin + taskSize, func); }); + begin += taskSize; + } + std::for_each(begin, end, func); +} +#endif +} // end namespace lld + +#endif diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h new file mode 100644 index 000000000000..7a9d2453f482 --- /dev/null +++ b/include/lld/Core/Pass.h @@ -0,0 +1,46 @@ +//===------ Core/Pass.h - Base class for linker passes --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PASS_H +#define LLD_CORE_PASS_H + +#include "lld/Core/Atom.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "lld/Core/range.h" +#include + +namespace lld { +class MutableFile; + +/// Once the core linking is done (which resolves references, coalesces atoms +/// and produces a complete Atom graph), the linker runs a series of passes +/// on the Atom graph. The graph is modeled as a File, which means the pass +/// has access to all the atoms and to File level attributes. Each pass does +/// a particular transformation to the Atom graph or to the File attributes. +/// +/// This is the abstract base class for all passes. A Pass does its +/// actual work in it perform() method. It can iterator over Atoms in the +/// graph using the *begin()/*end() atom iterator of the File. It can add +/// new Atoms to the graph using the File's addAtom() method. +class Pass { +public: + virtual ~Pass() { } + + /// Do the actual work of the Pass. + virtual void perform(std::unique_ptr &mergedFile) = 0; + +protected: + // Only subclassess can be instantiated. + Pass() { } +}; + +} // namespace lld + +#endif // LLD_CORE_PASS_H diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h new file mode 100644 index 000000000000..65fc4d806ceb --- /dev/null +++ b/include/lld/Core/PassManager.h @@ -0,0 +1,46 @@ +//===- lld/Core/PassManager.h - Manage linker passes ----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PASS_MANAGER_H +#define LLD_CORE_PASS_MANAGER_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Pass.h" +#include +#include + +namespace lld { +class MutableFile; +class Pass; + +/// \brief Owns and runs a collection of passes. +/// +/// This class is currently just a container for passes and a way to run them. +/// +/// In the future this should handle timing pass runs, running parallel passes, +/// and validate/satisfy pass dependencies. +class PassManager { +public: + void add(std::unique_ptr pass) { + _passes.push_back(std::move(pass)); + } + + std::error_code runOnFile(std::unique_ptr &file) { + for (std::unique_ptr &pass : _passes) + pass->perform(file); + return std::error_code(); + } + +private: + /// \brief Passes in the order they should run. + std::vector> _passes; +}; +} // end namespace lld + +#endif diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h new file mode 100644 index 000000000000..ac90c5a7e85c --- /dev/null +++ b/include/lld/Core/Reader.h @@ -0,0 +1,169 @@ +//===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_READER_H +#define LLD_CORE_READER_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/YAMLTraits.h" +#include +#include +#include + +using llvm::sys::fs::file_magic; + +namespace llvm { +namespace yaml { +class IO; +} +} + +namespace lld { +class ELFLinkingContext; +class File; +class LinkingContext; +class PECOFFLinkingContext; +class TargetHandlerBase; +class MachOLinkingContext; + +/// \brief An abstract class for reading object files, library files, and +/// executable files. +/// +/// Each file format (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete +/// subclass of Reader. +class Reader { +public: + virtual ~Reader() {} + + /// Sniffs the file to determine if this Reader can parse it. + /// The method is called with: + /// 1) the file_magic enumeration returned by identify_magic() + /// 2) the file extension (e.g. ".obj") + /// 3) the whole file content buffer if the above is not enough. + virtual bool canParse(file_magic magic, StringRef fileExtension, + const MemoryBuffer &mb) const = 0; + + /// \brief Parse a supplied buffer (already filled with the contents of a + /// file) and create a File object. + /// The resulting File object takes ownership of the MemoryBuffer. + virtual std::error_code + loadFile(std::unique_ptr mb, const class Registry &, + std::vector> &result) const = 0; +}; + + +/// \brief An abstract class for handling alternate yaml representations +/// of object files. +/// +/// The YAML syntax allows "tags" which are used to specify the type of +/// the YAML node. In lld, top level YAML documents can be in many YAML +/// representations (e.g mach-o encoded as yaml, etc). A tag is used to +/// specify which representation is used in the following YAML document. +/// To work, there must be a YamlIOTaggedDocumentHandler registered that +/// handles each tag type. +class YamlIOTaggedDocumentHandler { +public: + virtual ~YamlIOTaggedDocumentHandler(); + + /// This method is called on each registered YamlIOTaggedDocumentHandler + /// until one returns true. If the subclass handles tag type !xyz, then + /// this method should call io.mapTag("!xzy") to see if that is the current + /// document type, and if so, process the rest of the document using + /// YAML I/O, then convert the result into an lld::File* and return it. + virtual bool handledDocTag(llvm::yaml::IO &io, const lld::File *&f) const = 0; +}; + + +/// A registry to hold the list of currently registered Readers and +/// tables which map Reference kind values to strings. +/// The linker does not directly invoke Readers. Instead, it registers +/// Readers based on it configuration and command line options, then calls +/// the Registry object to parse files. +class Registry { +public: + Registry(); + + /// Walk the list of registered Readers and find one that can parse the + /// supplied file and parse it. + std::error_code loadFile(std::unique_ptr mb, + std::vector> &result) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// name to a value. + bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns, + Reference::KindArch &a, + Reference::KindValue &value) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// value to a string. + bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a, + Reference::KindValue value, StringRef &) const; + + /// Walk the list of registered tag handlers and have the one that handles + /// the current document type process the yaml into an lld::File*. + bool handleTaggedDoc(llvm::yaml::IO &io, const lld::File *&file) const; + + // These methods are called to dynamically add support for various file + // formats. The methods are also implemented in the appropriate lib*.a + // library, so that the code for handling a format is only linked in, if this + // method is used. Any options that a Reader might need must be passed + // as parameters to the addSupport*() method. + void addSupportArchives(bool logLoading); + void addSupportYamlFiles(); + void addSupportNativeObjects(); + void addSupportCOFFObjects(PECOFFLinkingContext &); + void addSupportCOFFImportLibraries(PECOFFLinkingContext &); + void addSupportMachOObjects(MachOLinkingContext &); + void addSupportELFObjects(ELFLinkingContext &); + void addSupportELFDynamicSharedObjects(ELFLinkingContext &); + + /// To convert between kind values and names, the registry walks the list + /// of registered kind tables. Each table is a zero terminated array of + /// KindStrings elements. + struct KindStrings { + Reference::KindValue value; + StringRef name; + }; + + /// A Reference Kind value is a tuple of . All + /// entries in a conversion table have the same . The + /// array then contains the value/name pairs. + void addKindTable(Reference::KindNamespace ns, Reference::KindArch arch, + const KindStrings array[]); + + +private: + struct KindEntry { + Reference::KindNamespace ns; + Reference::KindArch arch; + const KindStrings *array; + }; + + void add(std::unique_ptr); + void add(std::unique_ptr); + + std::vector> _readers; + std::vector> _yamlHandlers; + std::vector _kindEntries; +}; + +// Utilities for building a KindString table. For instance: +// static const Registry::KindStrings table[] = { +// LLD_KIND_STRING_ENTRY(R_VAX_ADDR16), +// LLD_KIND_STRING_ENTRY(R_VAX_DATA16), +// LLD_KIND_STRING_END +// }; +#define LLD_KIND_STRING_ENTRY(name) { name, #name } +#define LLD_KIND_STRING_END { 0, "" } + +} // end namespace lld + +#endif diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h new file mode 100644 index 000000000000..7a804c31e182 --- /dev/null +++ b/include/lld/Core/Reference.h @@ -0,0 +1,125 @@ +//===- Core/References.h - A Reference to Another Atom --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_REFERENCES_H +#define LLD_CORE_REFERENCES_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringSwitch.h" + +namespace lld { +class Atom; + +/// +/// The linker has a Graph Theory model of linking. An object file is seen +/// as a set of Atoms with References to other Atoms. Each Atom is a node +/// and each Reference is an edge. +/// +/// For example if a function contains a call site to "malloc" 40 bytes into +/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40, +/// kind=callsite, target=malloc, addend=0. +/// +/// Besides supporting traditional "relocations", References are also used +/// grouping atoms (group comdat), forcing layout (one atom must follow +/// another), marking data-in-code (jump tables or ARM constants), etc. +/// +/// The "kind" of a reference is a tuple of . This +/// enable us to re-use existing relocation types definded for various +/// file formats and architectures. For instance, in ELF the relocation type 10 +/// means R_X86_64_32 for x86_64, and R_386_GOTPC for i386. For PE/COFF +/// relocation 10 means IMAGE_REL_AMD64_SECTION. +/// +/// References and atoms form a directed graph. The dead-stripping pass +/// traverses them starting from dead-strip root atoms to garbage collect +/// unreachable ones. +/// +/// References of any kind are considered as directed edges. In addition to +/// that, references of some kind is considered as bidirected edges. +class Reference { +public: + /// Which universe defines the kindValue(). + enum class KindNamespace { + all = 0, + testing = 1, + ELF = 2, + COFF = 3, + mach_o = 4, + }; + + KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; } + void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; } + + // Which architecture the kind value is for. + enum class KindArch { all, AArch64, ARM, Hexagon, Mips, x86, x86_64 }; + + KindArch kindArch() const { return (KindArch)_kindArch; } + void setKindArch(KindArch a) { _kindArch = (uint8_t)a; } + + typedef uint16_t KindValue; + + KindValue kindValue() const { return _kindValue; } + + /// setKindValue() is needed because during linking, some optimizations may + /// change the codegen and hence the reference kind. + void setKindValue(KindValue value) { + _kindValue = value; + } + + /// KindValues used with KindNamespace::all and KindArch::all. + enum { + // kindLayoutAfter is treated as a bidirected edge by the dead-stripping + // pass. + kindLayoutAfter = 1, + // kindGroupChild is treated as a bidirected edge too. + kindGroupChild, + kindAssociate, + }; + + // A value to be added to the value of a target + typedef int64_t Addend; + + /// If the reference is a fixup in the Atom, then this returns the + /// byte offset into the Atom's content to do the fix up. + virtual uint64_t offsetInAtom() const = 0; + + /// Returns the atom this reference refers to. + virtual const Atom *target() const = 0; + + /// During linking, the linker may merge graphs which coalesces some nodes + /// (i.e. Atoms). To switch the target of a reference, this method is called. + virtual void setTarget(const Atom *) = 0; + + /// Some relocations require a symbol and a value (e.g. foo + 4). + virtual Addend addend() const = 0; + + /// During linking, some optimzations may change addend value. + virtual void setAddend(Addend) = 0; + + /// Returns target specific attributes of the reference. + virtual uint32_t tag() const { return 0; } + +protected: + /// Reference is an abstract base class. Only subclasses can use constructor. + Reference(KindNamespace ns, KindArch a, KindValue value) + : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {} + + /// The memory for Reference objects is always managed by the owning File + /// object. Therefore, no one but the owning File object should call + /// delete on an Reference. In fact, some File objects may bulk allocate + /// an array of References, so they cannot be individually deleted by anyone. + virtual ~Reference() {} + + KindValue _kindValue; + uint8_t _kindNamespace; + uint8_t _kindArch; +}; + +} // namespace lld + +#endif // LLD_CORE_REFERENCES_H diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h new file mode 100644 index 000000000000..e16c07b839fa --- /dev/null +++ b/include/lld/Core/Resolver.h @@ -0,0 +1,119 @@ +//===- Core/Resolver.h - Resolves Atom References -------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_RESOLVER_H +#define LLD_CORE_RESOLVER_H + +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/Simple.h" +#include "lld/Core/SymbolTable.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include +#include +#include +#include + +namespace lld { + +class Atom; +class LinkingContext; + +/// \brief The Resolver is responsible for merging all input object files +/// and producing a merged graph. +class Resolver { +public: + Resolver(LinkingContext &ctx) + : _ctx(ctx), _symbolTable(ctx), _result(new MergedFile()), + _fileIndex(0) {} + + // InputFiles::Handler methods + void doDefinedAtom(const DefinedAtom&); + bool doUndefinedAtom(const UndefinedAtom &); + void doSharedLibraryAtom(const SharedLibraryAtom &); + void doAbsoluteAtom(const AbsoluteAtom &); + + // Handle files, this adds atoms from the current file thats + // being processed by the resolver + bool handleFile(File &); + + // Handle an archive library file. + bool handleArchiveFile(File &); + + // Handle a shared library file. + void handleSharedLibrary(File &); + + /// @brief do work of merging and resolving and return list + bool resolve(); + + std::unique_ptr resultFile() { return std::move(_result); } + +private: + typedef std::function UndefCallback; + + bool undefinesAdded(int begin, int end); + File *getFile(int &index); + + /// \brief Add section group/.gnu.linkonce if it does not exist previously. + void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom); + + /// \brief The main function that iterates over the files to resolve + void updatePreloadArchiveMap(); + bool resolveUndefines(); + void updateReferences(); + void deadStripOptimize(); + bool checkUndefines(); + void removeCoalescedAwayAtoms(); + void checkDylibSymbolCollisions(); + void forEachUndefines(File &file, bool searchForOverrides, UndefCallback callback); + + void markLive(const Atom *atom); + void addAtoms(const std::vector&); + void maybePreloadArchiveMember(StringRef sym); + + class MergedFile : public SimpleFile { + public: + MergedFile() : SimpleFile("") {} + void addAtoms(std::vector& atoms); + }; + + LinkingContext &_ctx; + SymbolTable _symbolTable; + std::vector _atoms; + std::set _deadStripRoots; + llvm::DenseSet _liveAtoms; + llvm::DenseSet _deadAtoms; + std::unique_ptr _result; + std::unordered_multimap _reverseRef; + + // --start-group and --end-group + std::vector _files; + std::map _newUndefinesAdded; + size_t _fileIndex; + + // Preloading + llvm::StringMap _archiveMap; + llvm::DenseSet _archiveSeen; + + // List of undefined symbols. + std::vector _undefines; + + // Start position in _undefines for each archive/shared library file. + // Symbols from index 0 to the start position are already searched before. + // Searching them again would never succeed. When we look for undefined + // symbols from an archive/shared library file, start from its start + // position to save time. + std::map _undefineIndex; +}; + +} // namespace lld + +#endif // LLD_CORE_RESOLVER_H diff --git a/include/lld/Core/STDExtras.h b/include/lld/Core/STDExtras.h new file mode 100644 index 000000000000..4a6183891844 --- /dev/null +++ b/include/lld/Core/STDExtras.h @@ -0,0 +1,29 @@ +//===- lld/Core/STDExtra.h - Helpers for the stdlib -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_STD_EXTRA_H +#define LLD_CORE_STD_EXTRA_H + +namespace lld { +/// \brief Deleter for smart pointers that only calls the destructor. Memory is +/// managed elsewhere. A common use of this is for things allocated with a +/// BumpPtrAllocator. +template +struct destruct_delete { + void operator ()(T *ptr) { + ptr->~T(); + } +}; + +template +using unique_bump_ptr = std::unique_ptr>; + +} // end namespace lld + +#endif diff --git a/include/lld/Core/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h new file mode 100644 index 000000000000..1b0c37c41138 --- /dev/null +++ b/include/lld/Core/SharedLibraryAtom.h @@ -0,0 +1,53 @@ +//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H +#define LLD_CORE_SHARED_LIBRARY_ATOM_H + +#include "lld/Core/Atom.h" + +namespace lld { + +/// A SharedLibraryAtom has no content. +/// It exists to represent a symbol which will be bound at runtime. +class SharedLibraryAtom : public Atom { +public: + enum class Type : uint32_t { + Unknown, + Code, + Data, + }; + + /// Returns shared library name used to load it at runtime. + /// On linux that is the DT_NEEDED name. + /// On Darwin it is the LC_DYLIB_LOAD dylib name. + /// On Windows it is the DLL name that to be referred from .idata section. + virtual StringRef loadName() const = 0; + + /// Returns if shared library symbol can be missing at runtime and if + /// so the loader should silently resolve address of symbol to be nullptr. + virtual bool canBeNullAtRuntime() const = 0; + + virtual Type type() const = 0; + + virtual uint64_t size() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionSharedLibrary; + } + + static inline bool classof(const SharedLibraryAtom *) { return true; } + +protected: + SharedLibraryAtom() : Atom(definitionSharedLibrary) {} +}; + +} // namespace lld + +#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H diff --git a/include/lld/Core/SharedLibraryFile.h b/include/lld/Core/SharedLibraryFile.h new file mode 100644 index 000000000000..2f84624287d8 --- /dev/null +++ b/include/lld/Core/SharedLibraryFile.h @@ -0,0 +1,65 @@ +//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H +#define LLD_CORE_SHARED_LIBRARY_FILE_H + +#include "lld/Core/File.h" + +namespace lld { + +/// +/// The SharedLibraryFile subclass of File is used to represent dynamic +/// shared libraries being linked against. +/// +class SharedLibraryFile : public File { +public: + static bool classof(const File *f) { + return f->kind() == kindSharedLibrary; + } + + /// Check if the shared library exports a symbol with the specified name. + /// If so, return a SharedLibraryAtom which represents that exported + /// symbol. Otherwise return nullptr. + virtual const SharedLibraryAtom *exports(StringRef name, + bool dataSymbolOnly) const = 0; + + // Returns DSO name. It's the soname (ELF), the install name (MachO) or + // the import name (Windows). + virtual StringRef getDSOName() const = 0; + + const atom_collection &defined() const override { + return _definedAtoms; + } + + const atom_collection &undefined() const override { + return _undefinedAtoms; + } + + const atom_collection &sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const atom_collection &absolute() const override { + return _absoluteAtoms; + } + +protected: + /// only subclasses of SharedLibraryFile can be instantiated + explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {} + + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; +}; + +} // namespace lld + +#endif // LLD_CORE_SHARED_LIBRARY_FILE_H diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h new file mode 100644 index 000000000000..71d0c0702301 --- /dev/null +++ b/include/lld/Core/Simple.h @@ -0,0 +1,341 @@ +//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provide simple implementations for Atoms and File. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SIMPLE_H +#define LLD_CORE_SIMPLE_H + +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Reference.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" + +namespace lld { + +class SimpleFile : public MutableFile { +public: + SimpleFile(StringRef path) : MutableFile(path) {} + + void addAtom(const Atom &atom) override { + if (auto *defAtom = dyn_cast(&atom)) { + _definedAtoms._atoms.push_back(defAtom); + } else if (auto *undefAtom = dyn_cast(&atom)) { + _undefinedAtoms._atoms.push_back(undefAtom); + } else if (auto *shlibAtom = dyn_cast(&atom)) { + _sharedLibraryAtoms._atoms.push_back(shlibAtom); + } else if (auto *absAtom = dyn_cast(&atom)) { + _absoluteAtoms._atoms.push_back(absAtom); + } else { + llvm_unreachable("atom has unknown definition kind"); + } + } + + void + removeDefinedAtomsIf(std::function pred) override { + auto &atoms = _definedAtoms._atoms; + auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred); + atoms.erase(newEnd, atoms.end()); + } + + const atom_collection &defined() const override { + return _definedAtoms; + } + + const atom_collection &undefined() const override { + return _undefinedAtoms; + } + + const atom_collection &sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const atom_collection &absolute() const override { + return _absoluteAtoms; + } + + DefinedAtomRange definedAtoms() override { + return make_range(_definedAtoms._atoms); + } + +private: + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; +}; + +/// \brief Archive library file that may be used as a virtual container +/// for symbols that should be added dynamically in response to +/// call to find() method. +class SimpleArchiveLibraryFile : public ArchiveLibraryFile { +public: + SimpleArchiveLibraryFile(StringRef filename) + : ArchiveLibraryFile(filename) {} + + const atom_collection &defined() const override { + return _definedAtoms; + } + + const atom_collection &undefined() const override { + return _undefinedAtoms; + } + + const atom_collection &sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const atom_collection &absolute() const override { + return _absoluteAtoms; + } + + File *find(StringRef sym, bool dataSymbolOnly) override { + // For descendants: + // do some checks here and return dynamically generated files with atoms. + return nullptr; + } + + std::error_code + parseAllMembers(std::vector> &result) override { + return std::error_code(); + } + +private: + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; +}; + +class SimpleReference : public Reference { +public: + SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue value, uint64_t off, const Atom *t, + Reference::Addend a) + : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a), + _next(nullptr), _prev(nullptr) { + } + SimpleReference() + : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0), + _target(nullptr), _offsetInAtom(0), _addend(0), _next(nullptr), + _prev(nullptr) { + } + + uint64_t offsetInAtom() const override { return _offsetInAtom; } + + const Atom *target() const override { + assert(_target); + return _target; + } + + Addend addend() const override { return _addend; } + void setAddend(Addend a) override { _addend = a; } + void setTarget(const Atom *newAtom) override { _target = newAtom; } + SimpleReference *getNext() const { return _next; } + SimpleReference *getPrev() const { return _prev; } + void setNext(SimpleReference *n) { _next = n; } + void setPrev(SimpleReference *p) { _prev = p; } + +private: + const Atom *_target; + uint64_t _offsetInAtom; + Addend _addend; + SimpleReference *_next; + SimpleReference *_prev; +}; + +} + +// ilist will lazily create a sentinal (so end() can return a node past the +// end of the list). We need this trait so that the sentinal is allocated +// via the BumpPtrAllocator. +namespace llvm { +template<> +struct ilist_sentinel_traits { + + ilist_sentinel_traits() : _allocator(nullptr) { } + + void setAllocator(llvm::BumpPtrAllocator *alloc) { + _allocator = alloc; + } + + lld::SimpleReference *createSentinel() const { + return new (*_allocator) lld::SimpleReference(); + } + + static void destroySentinel(lld::SimpleReference*) {} + + static lld::SimpleReference *provideInitialHead() { return nullptr; } + + lld::SimpleReference *ensureHead(lld::SimpleReference *&head) const { + if (!head) { + head = createSentinel(); + noteHead(head, head); + ilist_traits::setNext(head, nullptr); + return head; + } + return ilist_traits::getPrev(head); + } + + void noteHead(lld::SimpleReference *newHead, + lld::SimpleReference *sentinel) const { + ilist_traits::setPrev(newHead, sentinel); + } + +private: + mutable llvm::BumpPtrAllocator *_allocator; +}; +} + +namespace lld { + +class SimpleDefinedAtom : public DefinedAtom { +public: + explicit SimpleDefinedAtom(const File &f) : _file(f) { + static uint32_t lastOrdinal = 0; + _ordinal = lastOrdinal++; + _references.setAllocator(&f.allocator()); + } + + const File &file() const override { return _file; } + + StringRef name() const override { return StringRef(); } + + uint64_t ordinal() const override { return _ordinal; } + + Scope scope() const override { return DefinedAtom::scopeLinkageUnit; } + + Interposable interposable() const override { + return DefinedAtom::interposeNo; + } + + Merge merge() const override { return DefinedAtom::mergeNo; } + + Alignment alignment() const override { return Alignment(0, 0); } + + SectionChoice sectionChoice() const override { + return DefinedAtom::sectionBasedOnContent; + } + + StringRef customSectionName() const override { return StringRef(); } + DeadStripKind deadStrip() const override { + return DefinedAtom::deadStripNormal; + } + + DefinedAtom::reference_iterator begin() const override { + const void *it = reinterpret_cast(&*_references.begin()); + return reference_iterator(*this, it); + } + + DefinedAtom::reference_iterator end() const override { + const void *it = reinterpret_cast(&*_references.end()); + return reference_iterator(*this, it); + } + + const Reference *derefIterator(const void *it) const override { + return reinterpret_cast(it); + } + + void incrementIterator(const void *&it) const override { + const SimpleReference* node = reinterpret_cast(it); + const SimpleReference* next = node->getNext(); + it = reinterpret_cast(next); + } + + void addReference(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t off, + const Atom *target, Reference::Addend a) { + assert(target && "trying to create reference to nothing"); + auto node = new (_file.allocator()) + SimpleReference(ns, arch, kindValue, off, target, a); + _references.push_back(node); + } + + /// Sort references in a canonical order (by offset, then by kind). + void sortReferences() const { + // Cannot sort a linked list, so move elements into a temporary vector, + // sort the vector, then reconstruct the list. + llvm::SmallVector elements; + for (SimpleReference &node : _references) { + elements.push_back(&node); + } + std::sort(elements.begin(), elements.end(), + [] (const SimpleReference *lhs, const SimpleReference *rhs) -> bool { + uint64_t lhsOffset = lhs->offsetInAtom(); + uint64_t rhsOffset = rhs->offsetInAtom(); + if (rhsOffset != lhsOffset) + return (lhsOffset < rhsOffset); + if (rhs->kindNamespace() != lhs->kindNamespace()) + return (lhs->kindNamespace() < rhs->kindNamespace()); + if (rhs->kindArch() != lhs->kindArch()) + return (lhs->kindArch() < rhs->kindArch()); + return (lhs->kindValue() < rhs->kindValue()); + }); + _references.clearAndLeakNodesUnsafely(); + for (SimpleReference *node : elements) { + _references.push_back(node); + } + } + void setOrdinal(uint64_t ord) { _ordinal = ord; } + +private: + typedef llvm::ilist RefList; + + const File &_file; + uint64_t _ordinal; + mutable RefList _references; +}; + +class SimpleUndefinedAtom : public UndefinedAtom { +public: + SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) { + assert(!name.empty() && "UndefinedAtoms must have a name"); + } + + /// file - returns the File that produced/owns this Atom + const File &file() const override { return _file; } + + /// name - The name of the atom. For a function atom, it is the (mangled) + /// name of the function. + StringRef name() const override { return _name; } + + CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; } + +private: + const File &_file; + StringRef _name; +}; + +class SimpleAbsoluteAtom : public AbsoluteAtom { +public: + SimpleAbsoluteAtom(const File &f, StringRef name, Scope s, uint64_t value) + : _file(f), _name(name), _scope(s), _value(value) {} + + const File &file() const override { return _file; } + StringRef name() const override { return _name; } + uint64_t value() const override { return _value; } + Scope scope() const override { return _scope; } + +private: + const File &_file; + StringRef _name; + Scope _scope; + uint64_t _value; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h new file mode 100644 index 000000000000..683ed65e3635 --- /dev/null +++ b/include/lld/Core/SymbolTable.h @@ -0,0 +1,117 @@ +//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SYMBOL_TABLE_H +#define LLD_CORE_SYMBOL_TABLE_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringExtras.h" +#include +#include +#include + +namespace lld { + +class AbsoluteAtom; +class Atom; +class DefinedAtom; +class LinkingContext; +class ResolverOptions; +class SharedLibraryAtom; +class UndefinedAtom; + +/// \brief The SymbolTable class is responsible for coalescing atoms. +/// +/// All atoms coalescable by-name or by-content should be added. +/// The method replacement() can be used to find the replacement atom +/// if an atom has been coalesced away. +class SymbolTable { +public: + explicit SymbolTable(LinkingContext &); + + /// @brief add atom to symbol table + bool add(const DefinedAtom &); + + /// @brief add atom to symbol table + bool add(const UndefinedAtom &); + + /// @brief add atom to symbol table + bool add(const SharedLibraryAtom &); + + /// @brief add atom to symbol table + bool add(const AbsoluteAtom &); + + /// @brief checks if name is in symbol table and if so atom is not + /// UndefinedAtom + bool isDefined(StringRef sym); + + /// @brief returns atom in symbol table for specified name (or nullptr) + const Atom *findByName(StringRef sym); + + /// @brief returns vector of remaining UndefinedAtoms + std::vector undefines(); + + /// returns vector of tentative definitions + std::vector tentativeDefinitions(); + + /// @brief add atom to replacement table + void addReplacement(const Atom *replaced, const Atom *replacement); + + /// @brief if atom has been coalesced away, return replacement, else return atom + const Atom *replacement(const Atom *); + + /// @brief if atom has been coalesced away, return true + bool isCoalescedAway(const Atom *); + + /// @brief Find a group atom. + const Atom *findGroup(StringRef name); + + /// @brief Add a group atom and returns true/false depending on whether the + /// previously existed. + bool addGroup(const DefinedAtom &da); + +private: + typedef llvm::DenseMap AtomToAtom; + + struct StringRefMappingInfo { + static StringRef getEmptyKey() { return StringRef(); } + static StringRef getTombstoneKey() { return StringRef(" ", 1); } + static unsigned getHashValue(StringRef const val) { + return llvm::HashString(val); + } + static bool isEqual(StringRef const lhs, StringRef const rhs) { + return lhs.equals(rhs); + } + }; + typedef llvm::DenseMap NameToAtom; + + struct AtomMappingInfo { + static const DefinedAtom * getEmptyKey() { return nullptr; } + static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); } + static unsigned getHashValue(const DefinedAtom * const Val); + static bool isEqual(const DefinedAtom * const LHS, + const DefinedAtom * const RHS); + }; + typedef llvm::DenseSet AtomContentSet; + + bool addByName(const Atom &); + bool addByContent(const DefinedAtom &); + + LinkingContext &_context; + AtomToAtom _replacedAtoms; + NameToAtom _nameTable; + NameToAtom _groupTable; + AtomContentSet _contentTable; +}; + +} // namespace lld + +#endif // LLD_CORE_SYMBOL_TABLE_H diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt new file mode 100644 index 000000000000..8888c763ef65 --- /dev/null +++ b/include/lld/Core/TODO.txt @@ -0,0 +1,17 @@ +include/lld/Core +~~~~~~~~~~~~~~~~ + +* The native/yaml reader/writer interfaces should be changed to return + an explanatory string if there is an error. The existing error_code + abstraction only works for returning low level OS errors. It does not + work for describing formatting issues. + +* We need to design a diagnostics interface. It would be nice to share code + with Clang_ where possible. + +* We need to add more attributes to File. In particular, we need cpu + and OS information (like target triples). We should also provide explicit + support for `LLVM IR module flags metadata`__. + +.. __: http://llvm.org/docs/LangRef.html#module_flags +.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics diff --git a/include/lld/Core/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h new file mode 100644 index 000000000000..7a835a4ebaa8 --- /dev/null +++ b/include/lld/Core/UndefinedAtom.h @@ -0,0 +1,74 @@ +//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_UNDEFINED_ATOM_H +#define LLD_CORE_UNDEFINED_ATOM_H + +#include "lld/Core/Atom.h" + +namespace lld { + +/// An UndefinedAtom has no content. +/// It exists as a placeholder for a future atom. +class UndefinedAtom : public Atom { +public: + /// Whether this undefined symbol needs to be resolved, + /// or whether it can just evaluate to nullptr. + /// This concept is often called "weak", but that term + /// is overloaded to mean other things too. + enum CanBeNull { + /// Normal symbols must be resolved at build time + canBeNullNever, + + /// This symbol can be missing at runtime and will evalute to nullptr. + /// That is, the static linker still must find a definition (usually + /// is some shared library), but at runtime, the dynamic loader + /// will allow the symbol to be missing and resolved to nullptr. + /// + /// On Darwin this is generated using a function prototype with + /// __attribute__((weak_import)). + /// On linux this is generated using a function prototype with + /// __attribute__((weak)). + /// On Windows this feature is not supported. + canBeNullAtRuntime, + + /// This symbol can be missing at build time. + /// That is, the static linker will not error if a definition for + /// this symbol is not found at build time. Instead, the linker + /// will build an executable that lets the dynamic loader find the + /// symbol at runtime. + /// This feature is not supported on Darwin nor Windows. + /// On linux this is generated using a function prototype with + /// __attribute__((weak)). + canBeNullAtBuildtime + }; + + virtual CanBeNull canBeNull() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionUndefined; + } + + static bool classof(const UndefinedAtom *) { return true; } + + /// Returns an undefined atom if this undefined symbol has a synonym. This is + /// mainly used in COFF. In COFF, an unresolved external symbol can have up to + /// one optional name (sym2) in addition to its regular name (sym1). If a + /// definition of sym1 exists, sym1 is resolved normally. Otherwise, all + /// references to sym1 refer to sym2 instead. In that case sym2 must be + /// resolved, or link will fail. + virtual const UndefinedAtom *fallback() const { return nullptr; } + +protected: + UndefinedAtom() : Atom(definitionUndefined) {} +}; + +} // namespace lld + +#endif // LLD_CORE_UNDEFINED_ATOM_H diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h new file mode 100644 index 000000000000..94c75d8d019f --- /dev/null +++ b/include/lld/Core/Writer.h @@ -0,0 +1,52 @@ +//===- lld/Core/Writer.h - Abstract File Format Interface -----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_WRITER_H +#define LLD_CORE_WRITER_H + +#include "lld/Core/LLVM.h" +#include +#include + +namespace lld { +class File; +class ELFLinkingContext; +class MachOLinkingContext; +class PECOFFLinkingContext; +class LinkingContext; +class TargetHandlerBase; + +/// \brief The Writer is an abstract class for writing object files, shared +/// library files, and executable files. Each file format (e.g. ELF, mach-o, +/// PECOFF, native, etc) have a concrete subclass of Writer. +class Writer { +public: + virtual ~Writer(); + + /// \brief Write a file from the supplied File object + virtual std::error_code writeFile(const File &linkedFile, StringRef path) = 0; + + /// \brief This method is called by Core Linking to give the Writer a chance + /// to add file format specific "files" to set of files to be linked. This is + /// how file format specific atoms can be added to the link. + virtual bool createImplicitFiles(std::vector > &); + +protected: + // only concrete subclasses can be instantiated + Writer(); +}; + +std::unique_ptr createWriterELF(TargetHandlerBase *handler); +std::unique_ptr createWriterMachO(const MachOLinkingContext &); +std::unique_ptr createWriterPECOFF(const PECOFFLinkingContext &); +std::unique_ptr createWriterNative(); +std::unique_ptr createWriterYAML(const LinkingContext &); +} // end namespace lld + +#endif diff --git a/include/lld/Core/range.h b/include/lld/Core/range.h new file mode 100644 index 000000000000..614c9672955c --- /dev/null +++ b/include/lld/Core/range.h @@ -0,0 +1,738 @@ +//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Iterator range type based on c++1y range proposal. +/// +/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_RANGE_H +#define LLD_CORE_RANGE_H + +#include "llvm/Support/Compiler.h" +#include +#include +#include +#include +#include +#include +#include + +namespace lld { +// Nothing in this namespace is part of the exported interface. +namespace detail { +using std::begin; +using std::end; +/// Used as the result type of undefined functions. +struct undefined {}; + +template class begin_result { + template static auto check(T &&t) -> decltype(begin(t)); + static undefined check(...); +public: + typedef decltype(check(std::declval())) type; +}; + +template class end_result { + template static auto check(T &&t) -> decltype(end(t)); + static undefined check(...); +public: + typedef decltype(check(std::declval())) type; +}; + +// Things that begin and end work on, in compatible ways, are +// ranges. [stmt.ranged] +template +struct is_range : std::is_same::type, + typename detail::end_result::type> {}; + +// This currently requires specialization and doesn't work for +// detecting \c range<>s or iterators. We should add +// \c contiguous_iterator_tag to fix that. +template struct is_contiguous_range : std::false_type {}; +template +struct is_contiguous_range : is_contiguous_range {}; +template +struct is_contiguous_range : is_contiguous_range {}; +template +struct is_contiguous_range : is_contiguous_range {}; + +template +struct is_contiguous_range : std::true_type {}; +template +struct is_contiguous_range : std::true_type {}; +template +struct is_contiguous_range > : std::true_type {}; +template +struct is_contiguous_range< + std::basic_string > : std::true_type {}; +template +struct is_contiguous_range > : std::true_type {}; + +// Removes cv qualifiers from all levels of a multi-level pointer +// type, not just the type level. +template struct remove_all_cv_ptr { + typedef T type; +}; +template struct remove_all_cv_ptr { + typedef typename remove_all_cv_ptr::type *type; +}; +template struct remove_all_cv_ptr { + typedef typename remove_all_cv_ptr::type type; +}; +template struct remove_all_cv_ptr { + typedef typename remove_all_cv_ptr::type type; +}; +template struct remove_all_cv_ptr { + typedef typename remove_all_cv_ptr::type type; +}; + +template +struct conversion_preserves_array_indexing : std::false_type {}; + +template +struct conversion_preserves_array_indexing : std::integral_constant< + bool, std::is_convertible::value && + std::is_same::type, + typename remove_all_cv_ptr::type>::value> {}; + +template +LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) { + return begin(std::forward(t)); +} + +template LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) { + return end(std::forward(t)); +} +} // end namespace detail + +/// A \c std::range represents a half-open iterator range +/// built from two iterators, \c 'begin', and \c 'end'. If \c end is +/// not reachable from \c begin, the behavior is undefined. +/// +/// The mutability of elements of the range is controlled by the +/// Iterator argument. Instantiate +/// range<Foo::iterator> or +/// range<T*>, or call +/// make_range(non_const_container), and you +/// get a mutable range. Instantiate +/// range<Foo::const_iterator> or +/// rangeT*>, or call +/// make_range(const_container), and you get a +/// constant range. +/// +/// \todo Inherit from std::pair? +/// +/// \todo This interface contains some functions that could be +/// provided as free algorithms rather than member functions, and all +/// of the pop_*() functions could be replaced by \c +/// slice() at the cost of some extra iterator copies. This makes +/// them more awkward to use, but makes it easier for users to write +/// their own types that follow the same interface. On the other hand, +/// a \c range_facade could be provided to help users write new +/// ranges, and it could provide the members. Such functions are +/// marked with a note in their documentation. (Of course, all of +/// these member functions could be provided as free functions using +/// the iterator access methods, but one goal here is to allow people +/// to program without touching iterators at all.) +template class range { + Iterator begin_, end_; +public: + /// \name types + /// @{ + + /// The iterator category of \c Iterator. + /// \todo Consider defining range categories. If they don't add + /// anything over the corresponding iterator categories, then + /// they're probably not worth defining. + typedef typename std::iterator_traits< + Iterator>::iterator_category iterator_category; + /// The type of elements of the range. Not cv-qualified. + typedef typename std::iterator_traits::value_type value_type; + /// The type of the size of the range and offsets within the range. + typedef typename std::iterator_traits< + Iterator>::difference_type difference_type; + /// The return type of element access methods: \c front(), \c back(), etc. + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::pointer pointer; + /// @} + + /// \name constructors + /// @{ + + /// Creates a range of default-constructed (not + /// value-initialized) iterators. For most \c Iterator types, this + /// will be an invalid range. + range() : begin_(), end_() {} + + /// \pre \c end is reachable from \c begin. + /// \post this->begin() == begin && this->end() == end + LLVM_CONSTEXPR range(Iterator begin, Iterator end) + : begin_(begin), end_(end) {} + + /// \par Participates in overload resolution if: + /// - \c Iterator is not a pointer type, + /// - \c begin(r) and \c end(r) return the same type, and + /// - that type is convertible to \c Iterator. + /// + /// \todo std::begin and std::end are overloaded between T& and + /// const T&, which means that if a container has only a non-const + /// begin or end method, then it's ill-formed to pass an rvalue to + /// the free function. To avoid that problem, we don't use + /// std::forward<> here, so begin() and end() are always called with + /// an lvalue. Another option would be to insist that rvalue + /// arguments to range() must have const begin() and end() methods. + template LLVM_CONSTEXPR range( + R &&r, + typename std::enable_if< + !std::is_pointer::value && + detail::is_range::value && + std::is_convertible::type, + Iterator>::value>::type* = 0) + : begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {} + + /// This constructor creates a \c range from any range with + /// contiguous iterators. Because dereferencing a past-the-end + /// iterator can be undefined behavior, empty ranges get initialized + /// with \c nullptr rather than \c &*begin(). + /// + /// \par Participates in overload resolution if: + /// - \c Iterator is a pointer type \c T*, + /// - \c begin(r) and \c end(r) return the same type, + /// - elements \c i of that type satisfy the invariant + /// &*(i + N) == (&*i) + N, and + /// - The result of &*begin() is convertible to \c T* + /// using only qualification conversions [conv.qual] (since + /// pointer conversions stop the pointer from pointing to an + /// array element). + /// + /// \todo The &*(i + N) == (&*i) + N invariant is + /// currently impossible to check for user-defined types. We need a + /// \c contiguous_iterator_tag to let users assert it. + template LLVM_CONSTEXPR range( + R &&r, + typename std::enable_if< + std::is_pointer::value && + detail::is_contiguous_range::value + // MSVC returns false for this in this context, but not if we lift it out of the + // constructor. +#ifndef _MSC_VER + && detail::conversion_preserves_array_indexing< + decltype(&*detail::adl_begin(r)), Iterator>::value +#endif + >::type* = 0) + : begin_((detail::adl_begin(r) == detail::adl_end(r) && + !std::is_pointer::value) + // For non-pointers, &*begin(r) is only defined behavior + // if there's an element there. Otherwise, use nullptr + // since the user can't dereference it anyway. This _is_ + // detectable. + ? nullptr : &*detail::adl_begin(r)), + end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {} + + /// @} + + /// \name iterator access + /// @{ + LLVM_CONSTEXPR Iterator begin() const { return begin_; } + LLVM_CONSTEXPR Iterator end() const { return end_; } + /// @} + + /// \name element access + /// @{ + + /// \par Complexity: + /// O(1) + /// \pre \c !empty() + /// \returns a reference to the element at the front of the range. + LLVM_CONSTEXPR reference front() const { return *begin(); } + + /// \par Ill-formed unless: + /// \c iterator_category is convertible to \c + /// std::bidirectional_iterator_tag. + /// + /// \par Complexity: + /// O(2) (Involves copying and decrementing an iterator, so not + /// quite as cheap as \c front()) + /// + /// \pre \c !empty() + /// \returns a reference to the element at the front of the range. + LLVM_CONSTEXPR reference back() const { + static_assert( + std::is_convertible::value, + "Can only retrieve the last element of a bidirectional range."); + using std::prev; + return *prev(end()); + } + + /// This method is drawn from scripting language indexing. It + /// indexes std::forward from the beginning of the range if the argument + /// is positive, or backwards from the end of the array if the + /// argument is negative. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to \c + /// std::random_access_iterator_tag. + /// + /// \par Complexity: + /// O(1) + /// + /// \pre abs(index) < size() || index == -size() + /// + /// \returns if index >= 0, a reference to the + /// index'th element in the range. Otherwise, a + /// reference to the size()+index'th element. + LLVM_CONSTEXPR reference operator[](difference_type index) const { + static_assert(std::is_convertible::value, + "Can only index into a random-access range."); + // Less readable construction for constexpr support. + return index < 0 ? end()[index] + : begin()[index]; + } + /// @} + + /// \name size + /// @{ + + /// \par Complexity: + /// O(1) + /// \returns \c true if the range contains no elements. + LLVM_CONSTEXPR bool empty() const { return begin() == end(); } + + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::forward_iterator_tag. + /// + /// \par Complexity: + /// O(1) if \c iterator_category is convertible to \c + /// std::random_access_iterator_tag. O(size()) + /// otherwise. + /// + /// \returns the number of times \c pop_front() can be called before + /// \c empty() becomes true. + LLVM_CONSTEXPR difference_type size() const { + static_assert(std::is_convertible::value, + "Calling size on an input range would destroy the range."); + return dispatch_size(iterator_category()); + } + /// @} + + /// \name traversal from the beginning of the range + /// @{ + + /// Advances the beginning of the range by one element. + /// \pre \c !empty() + void pop_front() { ++begin_; } + + /// Advances the beginning of the range by \c n elements. + /// + /// \par Complexity: + /// O(1) if \c iterator_category is convertible to \c + /// std::random_access_iterator_tag, O(n) otherwise. + /// + /// \pre n >= 0, and there must be at least \c n + /// elements in the range. + void pop_front(difference_type n) { advance(begin_, n); } + + /// Advances the beginning of the range by at most \c n elements, + /// stopping if the range becomes empty. A negative argument causes + /// no change. + /// + /// \par Complexity: + /// O(1) if \c iterator_category is convertible to \c + /// std::random_access_iterator_tag, O(min(n, + /// #-elements-in-range)) otherwise. + /// + /// \note Could be provided as a free function with little-to-no + /// loss in efficiency. + void pop_front_upto(difference_type n) { + advance_upto(begin_, std::max(0, n), end_, + iterator_category()); + } + + /// @} + + /// \name traversal from the end of the range + /// @{ + + /// Moves the end of the range earlier by one element. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::bidirectional_iterator_tag. + /// + /// \par Complexity: + /// O(1) + /// + /// \pre \c !empty() + void pop_back() { + static_assert(std::is_convertible::value, + "Can only access the end of a bidirectional range."); + --end_; + } + + /// Moves the end of the range earlier by \c n elements. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::bidirectional_iterator_tag. + /// + /// \par Complexity: + /// O(1) if \c iterator_category is convertible to \c + /// std::random_access_iterator_tag, O(n) otherwise. + /// + /// \pre n >= 0, and there must be at least \c n + /// elements in the range. + void pop_back(difference_type n) { + static_assert(std::is_convertible::value, + "Can only access the end of a bidirectional range."); + advance(end_, -n); + } + + /// Moves the end of the range earlier by min(n, + /// size()) elements. A negative argument causes no change. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::bidirectional_iterator_tag. + /// + /// \par Complexity: + /// O(1) if \c iterator_category is convertible to \c + /// std::random_access_iterator_tag, O(min(n, + /// #-elements-in-range)) otherwise. + /// + /// \note Could be provided as a free function with little-to-no + /// loss in efficiency. + void pop_back_upto(difference_type n) { + static_assert(std::is_convertible::value, + "Can only access the end of a bidirectional range."); + advance_upto(end_, -std::max(0, n), begin_, + iterator_category()); + } + + /// @} + + /// \name creating derived ranges + /// @{ + + /// Divides the range into two pieces at \c index, where a positive + /// \c index represents an offset from the beginning of the range + /// and a negative \c index represents an offset from the end. + /// range[index] is the first element in the second + /// piece. If index >= size(), the second piece + /// will be empty. If index < -size(), the first + /// piece will be empty. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::forward_iterator_tag. + /// + /// \par Complexity: + /// - If \c iterator_category is convertible to \c + /// std::random_access_iterator_tag: O(1) + /// - Otherwise, if \c iterator_category is convertible to \c + /// std::bidirectional_iterator_tag, \c abs(index) iterator increments + /// or decrements + /// - Otherwise, if index >= 0, \c index iterator + /// increments + /// - Otherwise, size() + (size() + index) + /// iterator increments. + /// + /// \returns a pair of adjacent ranges. + /// + /// \post + /// - result.first.size() == min(index, this->size()) + /// - result.first.end() == result.second.begin() + /// - result.first.size() + result.second.size() == + /// this->size() + /// + /// \todo split() could take an arbitrary number of indices and + /// return an N+1-element \c tuple<>. This is tricky to + /// implement with negative indices in the optimal number of + /// increments or decrements for a bidirectional iterator, but it + /// should be possible. Do we want it? + std::pair split(difference_type index) const { + static_assert( + std::is_convertible::value, + "Calling split on a non-std::forward range would return a useless " + "first result."); + if (index >= 0) { + range second = *this; + second.pop_front_upto(index); + return make_pair(range(begin(), second.begin()), second); + } else { + return dispatch_split_neg(index, iterator_category()); + } + } + + /// \returns A sub-range from \c start to \c stop (not including \c + /// stop, as usual). \c start and \c stop are interpreted as for + /// operator[], with negative values offsetting from + /// the end of the range. Omitting the \c stop argument makes the + /// sub-range continue to the end of the original range. Positive + /// arguments saturate to the end of the range, and negative + /// arguments saturate to the beginning. If \c stop is before \c + /// start, returns an empty range beginning and ending at \c start. + /// + /// \par Ill-formed unless: + /// \c iterator_category is convertible to + /// \c std::forward_iterator_tag. + /// + /// \par Complexity: + /// - If \c iterator_category is convertible to \c + /// std::random_access_iterator_tag: O(1) + /// - Otherwise, if \c iterator_category is convertible to \c + /// std::bidirectional_iterator_tag, at most min(abs(start), + /// size()) + min(abs(stop), size()) iterator + /// increments or decrements + /// - Otherwise, if start >= 0 && stop >= 0, + /// max(start, stop) iterator increments + /// - Otherwise, size() + max(start', stop') + /// iterator increments, where \c start' and \c stop' are the + /// offsets of the elements \c start and \c stop refer to. + /// + /// \note \c slice(start) should be implemented with a different + /// overload, rather than defaulting \c stop to + /// numeric_limits::max(), because + /// using a default would force non-random-access ranges to use an + /// O(size()) algorithm to compute the end rather + /// than the O(1) they're capable of. + range slice(difference_type start, difference_type stop) const { + static_assert( + std::is_convertible::value, + "Calling slice on a non-std::forward range would destroy the original " + "range."); + return dispatch_slice(start, stop, iterator_category()); + } + + range slice(difference_type start) const { + static_assert( + std::is_convertible::value, + "Calling slice on a non-std::forward range would destroy the original " + "range."); + return split(start).second; + } + + /// @} + +private: + // advance_upto: should be added to , but I'll use it as + // a helper function here. + // + // These return the number of increments that weren't applied + // because we ran into 'limit' (or 0 if we didn't run into limit). + static difference_type advance_upto(Iterator &it, difference_type n, + Iterator limit, std::input_iterator_tag) { + if (n < 0) + return 0; + while (it != limit && n > 0) { + ++it; + --n; + } + return n; + } + + static difference_type advance_upto(Iterator &it, difference_type n, + Iterator limit, + std::bidirectional_iterator_tag) { + if (n < 0) { + while (it != limit && n < 0) { + --it; + ++n; + } + } else { + while (it != limit && n > 0) { + ++it; + --n; + } + } + return n; + } + + static difference_type advance_upto(Iterator &it, difference_type n, + Iterator limit, + std::random_access_iterator_tag) { + difference_type distance = limit - it; + if (distance < 0) + assert(n <= 0); + else if (distance > 0) + assert(n >= 0); + + if (abs(distance) > abs(n)) { + it += n; + return 0; + } else { + it = limit; + return n - distance; + } + } + + // Dispatch functions. + difference_type dispatch_size(std::forward_iterator_tag) const { + return std::distance(begin(), end()); + } + + LLVM_CONSTEXPR difference_type dispatch_size( + std::random_access_iterator_tag) const { + return end() - begin(); + } + + std::pair dispatch_split_neg(difference_type index, + std::forward_iterator_tag) const { + assert(index < 0); + difference_type size = this->size(); + return split(std::max(0, size + index)); + } + + std::pair dispatch_split_neg( + difference_type index, std::bidirectional_iterator_tag) const { + assert(index < 0); + range first = *this; + first.pop_back_upto(-index); + return make_pair(first, range(first.end(), end())); + } + + range dispatch_slice(difference_type start, difference_type stop, + std::forward_iterator_tag) const { + if (start < 0 || stop < 0) { + difference_type size = this->size(); + if (start < 0) + start = std::max(0, size + start); + if (stop < 0) + stop = size + stop; // Possibly negative; will be fixed in 2 lines. + } + stop = std::max(start, stop); + + Iterator first = begin(); + advance_upto(first, start, end(), iterator_category()); + Iterator last = first; + advance_upto(last, stop - start, end(), iterator_category()); + return range(first, last); + } + + range dispatch_slice(const difference_type start, const difference_type stop, + std::bidirectional_iterator_tag) const { + Iterator first; + if (start < 0) { + first = end(); + advance_upto(first, start, begin(), iterator_category()); + } else { + first = begin(); + advance_upto(first, start, end(), iterator_category()); + } + Iterator last; + if (stop < 0) { + last = end(); + advance_upto(last, stop, first, iterator_category()); + } else { + if (start >= 0) { + last = first; + if (stop > start) + advance_upto(last, stop - start, end(), iterator_category()); + } else { + // Complicated: 'start' walked from the end of the sequence, + // but 'stop' needs to walk from the beginning. + Iterator dummy = begin(); + // Walk up to 'stop' increments from begin(), stopping when we + // get to 'first', and capturing the remaining number of + // increments. + difference_type increments_past_start = + advance_upto(dummy, stop, first, iterator_category()); + if (increments_past_start == 0) { + // If this is 0, then stop was before start. + last = first; + } else { + // Otherwise, count that many spaces beyond first. + last = first; + advance_upto(last, increments_past_start, end(), iterator_category()); + } + } + } + return range(first, last); + } + + range dispatch_slice(difference_type start, difference_type stop, + std::random_access_iterator_tag) const { + const difference_type size = this->size(); + if (start < 0) + start = size + start; + if (start < 0) + start = 0; + if (start > size) + start = size; + + if (stop < 0) + stop = size + stop; + if (stop < start) + stop = start; + if (stop > size) + stop = size; + + return range(begin() + start, begin() + stop); + } +}; + +/// \name deducing constructor wrappers +/// \relates std::range +/// \xmlonly \endxmlonly +/// +/// These functions do the same thing as the constructor with the same +/// signature. They just allow users to avoid writing the iterator +/// type. +/// @{ + +/// \todo I'd like to define a \c make_range taking a single iterator +/// argument representing the beginning of a range that ends with a +/// default-constructed \c Iterator. This would help with using +/// iterators like \c istream_iterator. However, using just \c +/// make_range() could be confusing and lead to people writing +/// incorrect ranges of more common iterators. Is there a better name? +template +LLVM_CONSTEXPR range make_range(Iterator begin, Iterator end) { + return range(begin, end); +} + +/// \par Participates in overload resolution if: +/// \c begin(r) and \c end(r) return the same type. +template LLVM_CONSTEXPR auto make_range( + Range &&r, + typename std::enable_if::value>::type* = 0) + -> range { + return range(r); +} + +/// \par Participates in overload resolution if: +/// - \c begin(r) and \c end(r) return the same type, +/// - that type satisfies the invariant that &*(i + N) == +/// (&*i) + N, and +/// - \c &*begin(r) has a pointer type. +template LLVM_CONSTEXPR auto make_ptr_range( + Range &&r, + typename std::enable_if< + detail::is_contiguous_range::value && + std::is_pointer::value>::type* = 0) + -> range { + return range(r); +} +/// @} +} // end namespace lld + +#endif diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h new file mode 100644 index 000000000000..300d2356d050 --- /dev/null +++ b/include/lld/Driver/Driver.h @@ -0,0 +1,162 @@ +//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Interface for Drivers which convert command line arguments into +/// LinkingContext objects, then perform the link. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_DRIVER_DRIVER_H +#define LLD_DRIVER_DRIVER_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Node.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +namespace lld { +class LinkingContext; +class CoreLinkingContext; +class MachOLinkingContext; +class PECOFFLinkingContext; +class ELFLinkingContext; + +typedef std::vector> FileVector; + +FileVector makeErrorFile(StringRef path, std::error_code ec); +FileVector parseMemberFiles(FileVector &files); +FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive); + +/// Base class for all Drivers. +class Driver { +protected: + + /// Performs link using specified options + static bool link(LinkingContext &context, + raw_ostream &diag = llvm::errs()); + +private: + Driver() = delete; +}; + +/// Driver for "universal" lld tool which can mimic any linker command line +/// parsing once it figures out which command line flavor to use. +class UniversalDriver : public Driver { +public: + /// Determine flavor and pass control to Driver for that flavor. + static bool link(int argc, const char *argv[], + raw_ostream &diag = llvm::errs()); + +private: + UniversalDriver() = delete; +}; + +/// Driver for gnu/binutil 'ld' command line options. +class GnuLdDriver : public Driver { +public: + /// Parses command line arguments same as gnu/binutils ld and performs link. + /// Returns true iff an error occurred. + static bool linkELF(int argc, const char *argv[], + raw_ostream &diag = llvm::errs()); + + /// Uses gnu/binutils style ld command line options to fill in options struct. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], + std::unique_ptr &context, + raw_ostream &diag = llvm::errs()); + + /// Parses a given memory buffer as a linker script and evaluate that. + /// Public function for testing. + static std::error_code evalLinkerScript(ELFLinkingContext &ctx, + std::unique_ptr mb, + raw_ostream &diag, bool nostdlib); + + /// A factory method to create an instance of ELFLinkingContext. + static std::unique_ptr + createELFLinkingContext(llvm::Triple triple); + +private: + static llvm::Triple getDefaultTarget(const char *progName); + static bool applyEmulation(llvm::Triple &triple, + llvm::opt::InputArgList &args, + raw_ostream &diag); + static void addPlatformSearchDirs(ELFLinkingContext &ctx, + llvm::Triple &triple, + llvm::Triple &baseTriple); + + GnuLdDriver() = delete; +}; + +/// Driver for darwin/ld64 'ld' command line options. +class DarwinLdDriver : public Driver { +public: + /// Parses command line arguments same as darwin's ld and performs link. + /// Returns true iff there was an error. + static bool linkMachO(int argc, const char *argv[], + raw_ostream &diag = llvm::errs()); + + /// Uses darwin style ld command line options to update LinkingContext object. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], MachOLinkingContext &info, + raw_ostream &diag = llvm::errs()); + +private: + DarwinLdDriver() = delete; +}; + +/// Driver for Windows 'link.exe' command line options +class WinLinkDriver : public Driver { +public: + /// Parses command line arguments same as Windows link.exe and performs link. + /// Returns true iff there was an error. + static bool linkPECOFF(int argc, const char *argv[], + raw_ostream &diag = llvm::errs()); + + /// Uses Windows style link command line options to fill in options struct. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], PECOFFLinkingContext &info, + raw_ostream &diag = llvm::errs(), + bool isDirective = false); + + // Same as parse(), but restricted to the context of directives. + static bool parseDirectives(int argc, const char *argv[], + PECOFFLinkingContext &info, + raw_ostream &diag = llvm::errs()) { + return parse(argc, argv, info, diag, true); + } + +private: + WinLinkDriver() = delete; +}; + +/// Driver for lld unit tests +class CoreDriver : public Driver { +public: + /// Parses command line arguments same as lld-core and performs link. + /// Returns true iff there was an error. + static bool link(int argc, const char *argv[], + raw_ostream &diag = llvm::errs()); + + /// Uses lld-core command line options to fill in options struct. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], CoreLinkingContext &info, + raw_ostream &diag = llvm::errs()); + +private: + CoreDriver() = delete; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/Driver/WinLinkModuleDef.h b/include/lld/Driver/WinLinkModuleDef.h new file mode 100644 index 000000000000..68c9a4bfef70 --- /dev/null +++ b/include/lld/Driver/WinLinkModuleDef.h @@ -0,0 +1,200 @@ +//===- lld/Driver/WinLinkModuleDef.h --------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Windows module definition file parser. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_DRIVER_WIN_LINK_MODULE_DEF_H +#define LLD_DRIVER_WIN_LINK_MODULE_DEF_H + +#include "lld/Core/LLVM.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Allocator.h" +#include + +namespace lld { +namespace moduledef { + +enum class Kind { + unknown, + eof, + identifier, + comma, + equal, + kw_base, + kw_data, + kw_exports, + kw_heapsize, + kw_library, + kw_name, + kw_noname, + kw_private, + kw_stacksize, + kw_version, +}; + +class Token { +public: + Token() : _kind(Kind::unknown) {} + Token(Kind kind, StringRef range) : _kind(kind), _range(range) {} + + Kind _kind; + StringRef _range; +}; + +class Lexer { +public: + explicit Lexer(std::unique_ptr mb) : _buffer(mb->getBuffer()) { + _sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc()); + } + + Token lex(); + const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; } + +private: + StringRef _buffer; + llvm::SourceMgr _sourceManager; +}; + +class Directive { +public: + enum class Kind { exports, heapsize, library, name, stacksize, version }; + + Kind getKind() const { return _kind; } + virtual ~Directive() {} + +protected: + explicit Directive(Kind k) : _kind(k) {} + +private: + Kind _kind; +}; + +class Exports : public Directive { +public: + explicit Exports(const std::vector &exports) + : Directive(Kind::exports), _exports(exports) {} + + static bool classof(const Directive *dir) { + return dir->getKind() == Kind::exports; + } + + const std::vector &getExports() const { + return _exports; + } + +private: + const std::vector _exports; +}; + +template +class MemorySize : public Directive { +public: + MemorySize(uint64_t reserve, uint64_t commit) + : Directive(kind), _reserve(reserve), _commit(commit) {} + + static bool classof(const Directive *dir) { + return dir->getKind() == kind; + } + + uint64_t getReserve() const { return _reserve; } + uint64_t getCommit() const { return _commit; } + +private: + const uint64_t _reserve; + const uint64_t _commit; +}; + +typedef MemorySize Heapsize; +typedef MemorySize Stacksize; + +class Name : public Directive { +public: + Name(StringRef outputPath, uint64_t baseaddr) + : Directive(Kind::name), _outputPath(outputPath), _baseaddr(baseaddr) {} + + static bool classof(const Directive *dir) { + return dir->getKind() == Kind::name; + } + + StringRef getOutputPath() const { return _outputPath; } + uint64_t getBaseAddress() const { return _baseaddr; } + +private: + const std::string _outputPath; + const uint64_t _baseaddr; +}; + +class Library : public Directive { +public: + Library(StringRef name, uint64_t baseaddr) + : Directive(Kind::library), _name(name), _baseaddr(baseaddr) {} + + static bool classof(const Directive *dir) { + return dir->getKind() == Kind::library; + } + + StringRef getName() const { return _name; } + uint64_t getBaseAddress() const { return _baseaddr; } + +private: + const std::string _name; + const uint64_t _baseaddr; +}; + +class Version : public Directive { +public: + Version(int major, int minor) + : Directive(Kind::version), _major(major), _minor(minor) {} + + static bool classof(const Directive *dir) { + return dir->getKind() == Kind::version; + } + + int getMajorVersion() const { return _major; } + int getMinorVersion() const { return _minor; } + +private: + const int _major; + const int _minor; +}; + +class Parser { +public: + Parser(Lexer &lex, llvm::BumpPtrAllocator &alloc) + : _lex(lex), _alloc(alloc) {} + + bool parse(std::vector &ret); + +private: + void consumeToken(); + bool consumeTokenAsInt(uint64_t &result); + bool expectAndConsume(Kind kind, Twine msg); + + void ungetToken(); + void error(const Token &tok, Twine msg); + + bool parseOne(Directive *&dir); + bool parseExport(PECOFFLinkingContext::ExportDesc &result); + bool parseMemorySize(uint64_t &reserve, uint64_t &commit); + bool parseName(std::string &outfile, uint64_t &baseaddr); + bool parseVersion(int &major, int &minor); + + Lexer &_lex; + llvm::BumpPtrAllocator &_alloc; + Token _tok; + std::vector _tokBuf; +}; +} +} + +#endif diff --git a/include/lld/Makefile b/include/lld/Makefile new file mode 100644 index 000000000000..5bfb8910313e --- /dev/null +++ b/include/lld/Makefile @@ -0,0 +1,44 @@ +LLD_LEVEL := ../.. +DIRS := Config + +include $(LLD_LEVEL)/Makefile + +install-local:: + $(Echo) Installing lld include files + $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) + $(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \ + cd $(PROJ_SRC_DIR)/.. && \ + for hdr in `find lld -type f \ + '(' -name LICENSE.TXT \ + -o -name '*.def' \ + -o -name '*.h' \ + -o -name '*.inc' \ + ')' -print \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) + $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/lld/include/lld" ; then \ + cd $(PROJ_OBJ_ROOT)/tools/lld/include && \ + for hdr in `find lld -type f \ + '(' -name LICENSE.TXT \ + -o -name '*.def' \ + -o -name '*.h' \ + -o -name '*.inc' \ + ')' -print \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +endif diff --git a/include/lld/ReaderWriter/AtomLayout.h b/include/lld/ReaderWriter/AtomLayout.h new file mode 100644 index 000000000000..ad4cd0607b88 --- /dev/null +++ b/include/lld/ReaderWriter/AtomLayout.h @@ -0,0 +1,39 @@ +//===- include/lld/ReaderWriter/AtomLayout.h ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ATOM_LAYOUT_H +#define LLD_READER_WRITER_ATOM_LAYOUT_H + +namespace lld { +class Atom; + +/// AtomLayouts are used by a writer to manage physical positions of atoms. +/// AtomLayout has two positions; one is file offset, and the other is the +/// address when loaded into memory. +/// +/// Construction of AtomLayouts is usually a multi-pass process. When an atom +/// is appended to a section, we don't know the starting address of the +/// section. Thus, we have no choice but to store the offset from the +/// beginning of the section as AtomLayout values. After all sections starting +/// address are fixed, AtomLayout is revisited to get the offsets updated by +/// adding the starting addresses of the section. +struct AtomLayout { + AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr) + : _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {} + + AtomLayout() : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {} + + const Atom *_atom; + uint64_t _fileOffset; + uint64_t _virtualAddr; +}; + +} + +#endif diff --git a/include/lld/ReaderWriter/CoreLinkingContext.h b/include/lld/ReaderWriter/CoreLinkingContext.h new file mode 100644 index 000000000000..d597ca46ddc7 --- /dev/null +++ b/include/lld/ReaderWriter/CoreLinkingContext.h @@ -0,0 +1,47 @@ +//===- lld/ReaderWriter/CoreLinkingContext.h ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_CORE_LINKER_CONTEXT_H +#define LLD_READER_WRITER_CORE_LINKER_CONTEXT_H + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Reader.h" +#include "lld/Core/Writer.h" +#include "llvm/Support/ErrorHandling.h" + +namespace lld { + +class CoreLinkingContext : public LinkingContext { +public: + CoreLinkingContext(); + + enum { + TEST_RELOC_CALL32 = 1, + TEST_RELOC_PCREL32 = 2, + TEST_RELOC_GOT_LOAD32 = 3, + TEST_RELOC_GOT_USE32 = 4, + TEST_RELOC_LEA32_WAS_GOT = 5, + }; + + bool validateImpl(raw_ostream &diagnostics) override; + void addPasses(PassManager &pm) override; + + void addPassNamed(StringRef name) { _passNames.push_back(name); } + +protected: + Writer &writer() const override; + +private: + std::unique_ptr _writer; + std::vector _passNames; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/ELFLinkingContext.h b/include/lld/ReaderWriter/ELFLinkingContext.h new file mode 100644 index 000000000000..d1cd3d9f3d6b --- /dev/null +++ b/include/lld/ReaderWriter/ELFLinkingContext.h @@ -0,0 +1,362 @@ +//===- lld/ReaderWriter/ELFLinkingContext.h -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H +#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Pass.h" +#include "lld/Core/PassManager.h" +#include "lld/Core/STDExtras.h" +#include "lld/Core/range.h" +#include "lld/Core/Reader.h" +#include "lld/Core/Writer.h" +#include "lld/ReaderWriter/LinkerScript.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" +#include +#include +#include + +namespace lld { +class DefinedAtom; +class Reference; +class File; + +namespace elf { +template class TargetHandler; +} + +class TargetHandlerBase { +public: + virtual ~TargetHandlerBase() {} + virtual void registerRelocationNames(Registry &) = 0; + + virtual std::unique_ptr getObjReader() = 0; + + virtual std::unique_ptr getDSOReader() = 0; + + virtual std::unique_ptr getWriter() = 0; +}; + +class ELFLinkingContext : public LinkingContext { +public: + /// \brief The type of ELF executable that the linker + /// creates. + enum class OutputMagic : uint8_t { + DEFAULT, // The default mode, no specific magic set + NMAGIC, // Disallow shared libraries and don't align sections + // PageAlign Data, Mark Text Segment/Data segment RW + OMAGIC // Disallow shared libraries and don't align sections, + // Mark Text Segment/Data segment RW + }; + + llvm::Triple getTriple() const { return _triple; } + + // Page size. + virtual uint64_t getPageSize() const { + if (_maxPageSize) + return *_maxPageSize; + return 0x1000; + } + virtual void setMaxPageSize(uint64_t pagesize) { + _maxPageSize = pagesize; + } + OutputMagic getOutputMagic() const { return _outputMagic; } + uint16_t getOutputELFType() const { return _outputELFType; } + uint16_t getOutputMachine() const; + bool mergeCommonStrings() const { return _mergeCommonStrings; } + virtual uint64_t getBaseAddress() const { return _baseAddress; } + virtual void setBaseAddress(uint64_t address) { _baseAddress = address; } + + void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom, + bool &useNew) override; + + /// This controls if undefined atoms need to be created for undefines that are + /// present in a SharedLibrary. If this option is set, undefined atoms are + /// created for every undefined symbol that are present in the dynamic table + /// in the shared library + bool useShlibUndefines() const { return _useShlibUndefines; } + /// @} + + /// \brief Does this relocation belong in the dynamic relocation table? + /// + /// This table is evaluated at loadtime by the dynamic loader and is + /// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table. + /// Relocations that return true will be added to the dynamic relocation + /// table. + virtual bool isDynamicRelocation(const Reference &) const { return false; } + + /// \brief Is this a copy relocation? + /// + /// If this is a copy relocation, its target must be an ObjectAtom. We must + /// include in DT_NEEDED the name of the library where this object came from. + virtual bool isCopyRelocation(const Reference &) const { + return false; + } + + bool validateImpl(raw_ostream &diagnostics) override; + + /// \brief Does the linker allow dynamic libraries to be linked with? + /// This is true when the output mode of the executable is set to be + /// having NMAGIC/OMAGIC + virtual bool allowLinkWithDynamicLibraries() const { + if (_outputMagic == OutputMagic::NMAGIC || + _outputMagic == OutputMagic::OMAGIC || _noAllowDynamicLibraries) + return false; + return true; + } + + /// \brief Use Elf_Rela format to output relocation tables. + virtual bool isRelaOutputFormat() const { return true; } + + /// \brief Does this relocation belong in the dynamic plt relocation table? + /// + /// This table holds all of the relocations used for delayed symbol binding. + /// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced + /// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table. + /// Relocations that return true will be added to the dynamic plt relocation + /// table. + virtual bool isPLTRelocation(const Reference &) const { return false; } + + /// \brief The path to the dynamic interpreter + virtual StringRef getDefaultInterpreter() const { + return "/lib64/ld-linux-x86-64.so.2"; + } + + /// \brief The dynamic linker path set by the --dynamic-linker option + virtual StringRef getInterpreter() const { + if (_dynamicLinkerArg) + return _dynamicLinkerPath; + return getDefaultInterpreter(); + } + + /// \brief Does the output have dynamic sections. + virtual bool isDynamic() const; + + /// \brief Are we creating a shared library? + virtual bool isDynamicLibrary() const { + return _outputELFType == llvm::ELF::ET_DYN; + } + + /// \brief Is the relocation a relative relocation + virtual bool isRelativeReloc(const Reference &r) const; + + template + lld::elf::TargetHandler &getTargetHandler() const { + assert(_targetHandler && "Got null TargetHandler!"); + return static_cast &>(*_targetHandler.get()); + } + + TargetHandlerBase *targetHandler() const { return _targetHandler.get(); } + void addPasses(PassManager &pm) override; + + void setTriple(llvm::Triple trip) { _triple = trip; } + void setNoInhibitExec(bool v) { _noInhibitExec = v; } + void setExportDynamic(bool v) { _exportDynamic = v; } + void setIsStaticExecutable(bool v) { _isStaticExecutable = v; } + void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; } + void setUseShlibUndefines(bool use) { _useShlibUndefines = use; } + void setOutputELFType(uint32_t type) { _outputELFType = type; } + + bool shouldExportDynamic() const { return _exportDynamic; } + + void createInternalFiles(std::vector> &) const override; + + void finalizeInputFiles() override; + + /// \brief Set the dynamic linker path + void setInterpreter(StringRef dynamicLinker) { + _dynamicLinkerArg = true; + _dynamicLinkerPath = dynamicLinker; + } + + /// \brief Set NMAGIC output kind when the linker specifies --nmagic + /// or -n in the command line + /// Set OMAGIC output kind when the linker specifies --omagic + /// or -N in the command line + virtual void setOutputMagic(OutputMagic magic) { _outputMagic = magic; } + + /// \brief Disallow dynamic libraries during linking + virtual void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; } + + /// Searches directories for a match on the input File + ErrorOr searchLibrary(StringRef libName) const; + + /// \brief Searches directories for a match on the input file. + /// If \p fileName is an absolute path and \p isSysRooted is true, check + /// the file under sysroot directory. If \p fileName is a relative path + /// and is not in the current directory, search the file through library + /// search directories. + ErrorOr searchFile(StringRef fileName, bool isSysRooted) const; + + /// Get the entry symbol name + StringRef entrySymbolName() const override; + + /// \brief Set new initializer function + void setInitFunction(StringRef name) { _initFunction = name; } + + /// \brief Return an initializer function name. + /// Either default "_init" or configured by the -init command line option. + StringRef initFunction() const { return _initFunction; } + + /// \brief Set new finalizer function + void setFiniFunction(StringRef name) { _finiFunction = name; } + + /// \brief Return a finalizer function name. + /// Either default "_fini" or configured by the -fini command line option. + StringRef finiFunction() const { return _finiFunction; } + + /// Add an absolute symbol. Used for --defsym. + void addInitialAbsoluteSymbol(StringRef name, uint64_t addr) { + _absoluteSymbols[name] = addr; + } + + void setSharedObjectName(StringRef soname) { + _soname = soname; + } + + StringRef sharedObjectName() const { return _soname; } + + StringRef getSysroot() const { return _sysrootPath; } + + /// \brief Set path to the system root + void setSysroot(StringRef path) { + _sysrootPath = path; + } + + void addRpath(StringRef path) { + _rpathList.push_back(path); + } + + range getRpathList() const { + return _rpathList; + } + + void addRpathLink(StringRef path) { + _rpathLinkList.push_back(path); + } + + range getRpathLinkList() const { + return _rpathLinkList; + } + + const std::map &getAbsoluteSymbols() const { + return _absoluteSymbols; + } + + /// \brief Helper function to allocate strings. + StringRef allocateString(StringRef ref) const { + char *x = _allocator.Allocate(ref.size() + 1); + memcpy(x, ref.data(), ref.size()); + x[ref.size()] = '\0'; + return x; + } + + // add search path to list. + virtual bool addSearchPath(StringRef ref) { + _inputSearchPaths.push_back(ref); + return true; + } + + // Retrieve search path list. + StringRefVector getSearchPaths() { return _inputSearchPaths; }; + + // By default, the linker would merge sections that are read only with + // segments that have read and execute permissions. When the user specifies a + // flag --rosegment, a separate segment needs to be created. + bool mergeRODataToTextSegment() const { return _mergeRODataToTextSegment; } + + void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; } + + bool isDynamicallyExportedSymbol(StringRef name) const { + return _dynamicallyExportedSymbols.count(name) != 0; + } + + /// \brief Demangle symbols. + std::string demangle(StringRef symbolName) const override; + bool demangleSymbols() const { return _demangle; } + void setDemangleSymbols(bool d) { _demangle = d; } + + /// \brief Align segments. + bool alignSegments() const { return _alignSegments; } + void setAlignSegments(bool align) { _alignSegments = align; } + + /// \brief Strip symbols. + bool stripSymbols() const { return _stripSymbols; } + void setStripSymbols(bool strip) { _stripSymbols = strip; } + + /// \brief Collect statistics. + bool collectStats() const { return _collectStats; } + void setCollectStats(bool s) { _collectStats = s; } + + // --wrap option. + void addWrapForSymbol(StringRef sym) { _wrapCalls.insert(sym); } + + const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; } + + void setUndefinesResolver(std::unique_ptr resolver); + + script::Sema &linkerScriptSema() { return _linkerScriptSema; } + const script::Sema &linkerScriptSema() const { return _linkerScriptSema; } + +private: + ELFLinkingContext() = delete; + +protected: + ELFLinkingContext(llvm::Triple, std::unique_ptr); + + Writer &writer() const override; + + /// Method to create a internal file for an undefined symbol + std::unique_ptr createUndefinedSymbolFile() const override; + + uint16_t _outputELFType; // e.g ET_EXEC + llvm::Triple _triple; + std::unique_ptr _targetHandler; + uint64_t _baseAddress; + bool _isStaticExecutable; + bool _noInhibitExec; + bool _exportDynamic; + bool _mergeCommonStrings; + bool _useShlibUndefines; + bool _dynamicLinkerArg; + bool _noAllowDynamicLibraries; + bool _mergeRODataToTextSegment; + bool _demangle; + bool _stripSymbols; + bool _alignSegments; + bool _nostdlib; + bool _collectStats; + llvm::Optional _maxPageSize; + + OutputMagic _outputMagic; + StringRefVector _inputSearchPaths; + std::unique_ptr _writer; + StringRef _dynamicLinkerPath; + StringRef _initFunction; + StringRef _finiFunction; + StringRef _sysrootPath; + StringRef _soname; + StringRefVector _rpathList; + StringRefVector _rpathLinkList; + llvm::StringSet<> _wrapCalls; + std::map _absoluteSymbols; + llvm::StringSet<> _dynamicallyExportedSymbols; + std::unique_ptr _resolver; + + // The linker script semantic object, which owns all script ASTs, is stored + // in the current linking context via _linkerScriptSema. + script::Sema _linkerScriptSema; +}; +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/ELFTargets.h b/include/lld/ReaderWriter/ELFTargets.h new file mode 100644 index 000000000000..3d00339818e2 --- /dev/null +++ b/include/lld/ReaderWriter/ELFTargets.h @@ -0,0 +1,38 @@ +//===- lld/ReaderWriter/ELFTargets.h --------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_TARGETS_H +#define LLD_READER_WRITER_ELF_TARGETS_H + +#include "ELFLinkingContext.h" + +namespace lld { +namespace elf { + +#define LLVM_TARGET(TargetName) \ + class TargetName##LinkingContext final : public ELFLinkingContext { \ + public: \ + static std::unique_ptr create(llvm::Triple); \ + }; + +// FIXME: #include "llvm/Config/Targets.def" +LLVM_TARGET(AArch64) +LLVM_TARGET(ARM) +LLVM_TARGET(Hexagon) +LLVM_TARGET(Mips) +LLVM_TARGET(X86) +LLVM_TARGET(Example) +LLVM_TARGET(X86_64) + +#undef LLVM_TARGET + +} // end namespace elf +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/LinkerScript.h b/include/lld/ReaderWriter/LinkerScript.h new file mode 100644 index 000000000000..ae8d18d830c6 --- /dev/null +++ b/include/lld/ReaderWriter/LinkerScript.h @@ -0,0 +1,1396 @@ +//===- ReaderWriter/LinkerScript.h ----------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Linker script parser. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H +#define LLD_READER_WRITER_LINKER_SCRIPT_H + +#include "lld/Core/Error.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/range.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +namespace lld { +namespace script { +class Token { +public: + enum Kind { + unknown, + eof, + exclaim, + exclaimequal, + amp, + ampequal, + l_paren, + r_paren, + star, + starequal, + plus, + plusequal, + comma, + minus, + minusequal, + slash, + slashequal, + number, + colon, + semicolon, + less, + lessequal, + lessless, + lesslessequal, + equal, + equalequal, + greater, + greaterequal, + greatergreater, + greatergreaterequal, + question, + identifier, + libname, + kw_align, + kw_align_with_input, + kw_as_needed, + kw_at, + kw_discard, + kw_entry, + kw_exclude_file, + kw_extern, + kw_group, + kw_hidden, + kw_input, + kw_keep, + kw_length, + kw_memory, + kw_origin, + kw_provide, + kw_provide_hidden, + kw_only_if_ro, + kw_only_if_rw, + kw_output, + kw_output_arch, + kw_output_format, + kw_overlay, + kw_search_dir, + kw_sections, + kw_sort_by_alignment, + kw_sort_by_init_priority, + kw_sort_by_name, + kw_sort_none, + kw_subalign, + l_brace, + pipe, + pipeequal, + r_brace, + tilde + }; + + Token() : _kind(unknown) {} + Token(StringRef range, Kind kind) : _range(range), _kind(kind) {} + + void dump(raw_ostream &os) const; + + StringRef _range; + Kind _kind; +}; + +class Lexer { +public: + explicit Lexer(std::unique_ptr mb) : _buffer(mb->getBuffer()) { + _sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc()); + } + + void lex(Token &tok); + + const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; } + +private: + bool canStartNumber(char c) const; + bool canContinueNumber(char c) const; + bool canStartName(char c) const; + bool canContinueName(char c) const; + void skipWhitespace(); + + Token _current; + /// \brief The current buffer state. + StringRef _buffer; + // Lexer owns the input files. + llvm::SourceMgr _sourceManager; +}; + +/// All linker scripts commands derive from this class. High-level, sections and +/// output section commands are all subclasses of this class. +/// Examples: +/// +/// OUTPUT_FORMAT("elf64-x86-64") /* A linker script command */ +/// OUTPUT_ARCH(i386:x86-64) /* Another command */ +/// ENTRY(_start) /* Another command */ +/// +/// SECTIONS /* Another command */ +/// { +/// .interp : { /* A sections-command */ +/// *(.interp) /* An output-section-command */ +/// } +/// } +/// +class Command { +public: + enum class Kind { + Entry, + Extern, + Group, + Input, + InputSectionsCmd, + InputSectionName, + Memory, + Output, + OutputArch, + OutputFormat, + OutputSectionDescription, + Overlay, + SearchDir, + Sections, + SortedGroup, + SymbolAssignment, + }; + + Kind getKind() const { return _kind; } + inline llvm::BumpPtrAllocator &getAllocator() const; + + virtual void dump(raw_ostream &os) const = 0; + + virtual ~Command() {} + +protected: + Command(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {} + +private: + Parser &_ctx; + Kind _kind; +}; + +class Output : public Command { +public: + Output(Parser &ctx, StringRef outputFileName) + : Command(ctx, Kind::Output), _outputFileName(outputFileName) {} + + static bool classof(const Command *c) { return c->getKind() == Kind::Output; } + + void dump(raw_ostream &os) const override { + os << "OUTPUT(" << _outputFileName << ")\n"; + } + + StringRef getOutputFileName() const { return _outputFileName; } + +private: + StringRef _outputFileName; +}; + +class OutputFormat : public Command { +public: + OutputFormat(Parser &ctx, const SmallVectorImpl &formats) + : Command(ctx, Kind::OutputFormat) { + size_t numFormats = formats.size(); + StringRef *formatsStart = getAllocator().Allocate(numFormats); + std::copy(std::begin(formats), std::end(formats), formatsStart); + _formats = llvm::makeArrayRef(formatsStart, numFormats); + } + + static bool classof(const Command *c) { + return c->getKind() == Kind::OutputFormat; + } + + void dump(raw_ostream &os) const override { + os << "OUTPUT_FORMAT("; + bool first = true; + for (StringRef format : _formats) { + if (!first) + os << ","; + first = false; + os << "\"" << format << "\""; + } + os << ")\n"; + } + + llvm::ArrayRef getFormats() { return _formats; } + +private: + llvm::ArrayRef _formats; +}; + +class OutputArch : public Command { +public: + OutputArch(Parser &ctx, StringRef arch) + : Command(ctx, Kind::OutputArch), _arch(arch) {} + + static bool classof(const Command *c) { + return c->getKind() == Kind::OutputArch; + } + + void dump(raw_ostream &os) const override { + os << "OUTPUT_ARCH(" << getArch() << ")\n"; + } + + StringRef getArch() const { return _arch; } + +private: + StringRef _arch; +}; + +struct Path { + StringRef _path; + bool _asNeeded; + bool _isDashlPrefix; + + Path() : _asNeeded(false), _isDashlPrefix(false) {} + Path(StringRef path, bool asNeeded = false, bool isLib = false) + : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {} +}; + +template +class PathList : public Command { +public: + PathList(Parser &ctx, StringRef name, const SmallVectorImpl &paths) + : Command(ctx, K), _name(name) { + size_t numPaths = paths.size(); + Path *pathsStart = getAllocator().template Allocate(numPaths); + std::copy(std::begin(paths), std::end(paths), pathsStart); + _paths = llvm::makeArrayRef(pathsStart, numPaths); + } + + static bool classof(const Command *c) { return c->getKind() == K; } + + void dump(raw_ostream &os) const override { + os << _name << "("; + bool first = true; + for (const Path &path : getPaths()) { + if (!first) + os << " "; + first = false; + if (path._asNeeded) + os << "AS_NEEDED("; + if (path._isDashlPrefix) + os << "-l"; + os << path._path; + if (path._asNeeded) + os << ")"; + } + os << ")\n"; + } + + llvm::ArrayRef getPaths() const { return _paths; } + +private: + StringRef _name; + llvm::ArrayRef _paths; +}; + +class Group : public PathList { +public: + template + Group(Parser &ctx, RangeT range) + : PathList(ctx, "GROUP", std::move(range)) {} +}; + +class Input : public PathList { +public: + template + Input(Parser &ctx, RangeT range) + : PathList(ctx, "INPUT", std::move(range)) {} +}; + +class Entry : public Command { +public: + Entry(Parser &ctx, StringRef entryName) + : Command(ctx, Kind::Entry), _entryName(entryName) {} + + static bool classof(const Command *c) { return c->getKind() == Kind::Entry; } + + void dump(raw_ostream &os) const override { + os << "ENTRY(" << _entryName << ")\n"; + } + + StringRef getEntryName() const { return _entryName; } + +private: + StringRef _entryName; +}; + +class SearchDir : public Command { +public: + SearchDir(Parser &ctx, StringRef searchPath) + : Command(ctx, Kind::SearchDir), _searchPath(searchPath) {} + + static bool classof(const Command *c) { + return c->getKind() == Kind::SearchDir; + } + + void dump(raw_ostream &os) const override { + os << "SEARCH_DIR(\"" << _searchPath << "\")\n"; + } + + StringRef getSearchPath() const { return _searchPath; } + +private: + StringRef _searchPath; +}; + +/// Superclass for expression nodes. Linker scripts accept C-like expressions in +/// many places, such as when defining the value of a symbol or the address of +/// an output section. +/// Example: +/// +/// SECTIONS { +/// my_symbol = 1 + 1 * 2; +/// | | ^~~~> Constant : Expression +/// | | ^~~~> Constant : Expression +/// | | ^~~~> BinOp : Expression +/// ^~~~> Constant : Expression +/// ^~~~> BinOp : Expression (the top-level Expression node) +/// } +/// +class Expression { +public: + // The symbol table does not need to own its string keys and the use of StringMap + // here is an overkill. + typedef llvm::StringMap SymbolTableTy; + + enum class Kind { Constant, Symbol, FunctionCall, Unary, BinOp, + TernaryConditional }; + Kind getKind() const { return _kind; } + inline llvm::BumpPtrAllocator &getAllocator() const; + virtual void dump(raw_ostream &os) const = 0; + virtual ErrorOr evalExpr(SymbolTableTy &symbolTable) const = 0; + virtual ~Expression() {} + +protected: + Expression(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {} + +private: + Parser &_ctx; + Kind _kind; +}; + +/// A constant value is stored as unsigned because it represents absolute +/// values. We represent negative numbers by composing the unary '-' operator +/// with a constant. +class Constant : public Expression { +public: + Constant(Parser &ctx, uint64_t num) + : Expression(ctx, Kind::Constant), _num(num) {} + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::Constant; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + uint64_t _num; +}; + +class Symbol : public Expression { +public: + Symbol(Parser &ctx, StringRef name) + : Expression(ctx, Kind::Symbol), _name(name) {} + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::Symbol; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + StringRef _name; +}; + +class FunctionCall : public Expression { +public: + FunctionCall(Parser &ctx, StringRef name, + const SmallVectorImpl &args) + : Expression(ctx, Kind::FunctionCall), _name(name) { + size_t numArgs = args.size(); + const Expression **argsStart = + getAllocator().Allocate(numArgs); + std::copy(std::begin(args), std::end(args), argsStart); + _args = llvm::makeArrayRef(argsStart, numArgs); + } + + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::FunctionCall; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + StringRef _name; + llvm::ArrayRef _args; +}; + +class Unary : public Expression { +public: + enum Operation { + Minus, + Not + }; + + Unary(Parser &ctx, Operation op, const Expression *child) + : Expression(ctx, Kind::Unary), _op(op), _child(child) {} + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::Unary; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + Operation _op; + const Expression *_child; +}; + +class BinOp : public Expression { +public: + enum Operation { + And, + CompareDifferent, + CompareEqual, + CompareGreater, + CompareGreaterEqual, + CompareLess, + CompareLessEqual, + Div, + Mul, + Or, + Shl, + Shr, + Sub, + Sum + }; + + BinOp(Parser &ctx, const Expression *lhs, Operation op, const Expression *rhs) + : Expression(ctx, Kind::BinOp), _op(op), _lhs(lhs), _rhs(rhs) {} + + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::BinOp; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + Operation _op; + const Expression *_lhs; + const Expression *_rhs; +}; + +/// Operands of the ternary operator can be any expression, similar to the other +/// operations, including another ternary operator. To disambiguate the parse +/// tree, note that ternary conditionals have precedence 13 and, different from +/// other operators, associates right-to-left. For example: +/// +/// i = i > 3 ? i < 5 ? 1 : 2 : 0; +/// +/// will have the following parse tree: +/// +/// i = ((i > 3) ? ((i < 5) ? 1 : 2) : 0); +/// +/// The '>' binds tigher because it has precedence 6. When faced with two "?" +/// ternary operators back-to-back, the parser prioritized the rightmost one. +/// +class TernaryConditional : public Expression { +public: + TernaryConditional(Parser &ctx, const Expression *conditional, + const Expression *trueExpr, const Expression *falseExpr) + : Expression(ctx, Kind::TernaryConditional), _conditional(conditional), + _trueExpr(trueExpr), _falseExpr(falseExpr) {} + + void dump(raw_ostream &os) const override; + + static bool classof(const Expression *c) { + return c->getKind() == Kind::TernaryConditional; + } + + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + +private: + const Expression *_conditional; + const Expression *_trueExpr; + const Expression *_falseExpr; +}; + +/// Symbol assignments of the form "symbolname = " may occur either +/// as sections-commands or as output-section-commands. +/// Example: +/// +/// SECTIONS { +/// mysymbol = . /* SymbolAssignment as a sections-command */ +/// .data : { +/// othersymbol = . /* SymbolAssignment as an output-section-command */ +/// } +///} +/// +class SymbolAssignment : public Command { +public: + enum AssignmentKind { Simple, Sum, Sub, Mul, Div, Shl, Shr, And, Or }; + enum AssignmentVisibility { Default, Hidden, Provide, ProvideHidden }; + + SymbolAssignment(Parser &ctx, StringRef name, const Expression *expr, + AssignmentKind kind, AssignmentVisibility visibility) + : Command(ctx, Kind::SymbolAssignment), _expression(expr), _symbol(name), + _assignmentKind(Simple), _assignmentVisibility(visibility) {} + + static bool classof(const Command *c) { + return c->getKind() == Kind::SymbolAssignment; + } + + void dump(raw_ostream &os) const override; + const Expression *expr() const { return _expression; } + StringRef symbol() const { return _symbol; } + AssignmentKind assignmentKind() const { return _assignmentKind; } + AssignmentVisibility assignmentVisibility() const { + return _assignmentVisibility; + } + +private: + const Expression *_expression; + StringRef _symbol; + AssignmentKind _assignmentKind; + AssignmentVisibility _assignmentVisibility; +}; + +/// Encodes how to sort file names or section names that are expanded from +/// wildcard operators. This typically occurs in constructs such as +/// SECTIONS { .data : SORT_BY_NAME(*)(*) }}, where the order of the expanded +/// names is important to determine which sections go first. +enum class WildcardSortMode { + NA, + ByAlignment, + ByAlignmentAndName, + ByInitPriority, + ByName, + ByNameAndAlignment, + None +}; + +/// Represents either a single input section name or a group of sorted input +/// section names. They specify which sections to map to a given output section. +/// Example: +/// +/// SECTIONS { +/// .x: { *(.text) } +/// /* ^~~~^ InputSectionName : InputSection */ +/// .y: { *(SORT(.text*)) } +/// /* ^~~~~~~~~~~^ InputSectionSortedGroup : InputSection */ +/// } +class InputSection : public Command { +public: + static bool classof(const Command *c) { + return c->getKind() == Kind::InputSectionName || + c->getKind() == Kind::SortedGroup; + } + +protected: + InputSection(Parser &ctx, Kind k) : Command(ctx, k) {} +}; + +class InputSectionName : public InputSection { +public: + InputSectionName(Parser &ctx, StringRef name, bool excludeFile) + : InputSection(ctx, Kind::InputSectionName), _name(name), + _excludeFile(excludeFile) {} + + void dump(raw_ostream &os) const override; + + static bool classof(const Command *c) { + return c->getKind() == Kind::InputSectionName; + } + bool hasExcludeFile() const { return _excludeFile; } + StringRef name() const { return _name; } + +private: + StringRef _name; + bool _excludeFile; +}; + +class InputSectionSortedGroup : public InputSection { +public: + typedef llvm::ArrayRef::const_iterator const_iterator; + + InputSectionSortedGroup(Parser &ctx, WildcardSortMode sort, + const SmallVectorImpl §ions) + : InputSection(ctx, Kind::SortedGroup), _sortMode(sort) { + size_t numSections = sections.size(); + const InputSection **sectionsStart = + getAllocator().Allocate(numSections); + std::copy(std::begin(sections), std::end(sections), sectionsStart); + _sections = llvm::makeArrayRef(sectionsStart, numSections); + } + + void dump(raw_ostream &os) const override; + WildcardSortMode sortMode() const { return _sortMode; } + + static bool classof(const Command *c) { + return c->getKind() == Kind::SortedGroup; + } + + const_iterator begin() const { return _sections.begin(); } + const_iterator end() const { return _sections.end(); } + +private: + WildcardSortMode _sortMode; + llvm::ArrayRef _sections; +}; + +/// An output-section-command that maps a series of sections inside a given +/// file-archive pair to an output section. +/// Example: +/// +/// SECTIONS { +/// .x: { *(.text) } +/// /* ^~~~~~~^ InputSectionsCmd */ +/// .y: { w:z(SORT(.text*)) } +/// /* ^~~~~~~~~~~~~~~~^ InputSectionsCmd */ +/// } +class InputSectionsCmd : public Command { +public: + typedef llvm::ArrayRef::const_iterator const_iterator; + typedef std::vector VectorTy; + + InputSectionsCmd(Parser &ctx, StringRef memberName, StringRef archiveName, + bool keep, WildcardSortMode fileSortMode, + WildcardSortMode archiveSortMode, + const SmallVectorImpl §ions) + : Command(ctx, Kind::InputSectionsCmd), _memberName(memberName), + _archiveName(archiveName), _keep(keep), _fileSortMode(fileSortMode), + _archiveSortMode(archiveSortMode) { + size_t numSections = sections.size(); + const InputSection **sectionsStart = + getAllocator().Allocate(numSections); + std::copy(std::begin(sections), std::end(sections), sectionsStart); + _sections = llvm::makeArrayRef(sectionsStart, numSections); + } + + void dump(raw_ostream &os) const override; + + static bool classof(const Command *c) { + return c->getKind() == Kind::InputSectionsCmd; + } + + StringRef memberName() const { return _memberName; } + StringRef archiveName() const { return _archiveName; } + const_iterator begin() const { return _sections.begin(); } + const_iterator end() const { return _sections.end(); } + WildcardSortMode archiveSortMode() const { return _archiveSortMode; } + WildcardSortMode fileSortMode() const { return _fileSortMode; } + +private: + StringRef _memberName; + StringRef _archiveName; + bool _keep; + WildcardSortMode _fileSortMode; + WildcardSortMode _archiveSortMode; + llvm::ArrayRef _sections; +}; + +/// A sections-command to specify which input sections and symbols compose a +/// given output section. +/// Example: +/// +/// SECTIONS { +/// .x: { *(.text) ; symbol = .; } +/// /*^~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */ +/// .y: { w:z(SORT(.text*)) } +/// /*^~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */ +/// .a 0x10000 : ONLY_IF_RW { *(.data*) ; *:libc.a(SORT(*)); } +/// /*^~~~~~~~~~~~~ OutputSectionDescription ~~~~~~~~~~~~~~~~~^ */ +/// } +class OutputSectionDescription : public Command { +public: + enum Constraint { C_None, C_OnlyIfRO, C_OnlyIfRW }; + + typedef llvm::ArrayRef::const_iterator const_iterator; + + OutputSectionDescription( + Parser &ctx, StringRef sectionName, const Expression *address, + const Expression *align, const Expression *subAlign, const Expression *at, + const Expression *fillExpr, StringRef fillStream, bool alignWithInput, + bool discard, Constraint constraint, + const SmallVectorImpl &outputSectionCommands) + : Command(ctx, Kind::OutputSectionDescription), _sectionName(sectionName), + _address(address), _align(align), _subAlign(subAlign), _at(at), + _fillExpr(fillExpr), _fillStream(fillStream), + _alignWithInput(alignWithInput), _discard(discard), + _constraint(constraint) { + size_t numCommands = outputSectionCommands.size(); + const Command **commandsStart = + getAllocator().Allocate(numCommands); + std::copy(std::begin(outputSectionCommands), + std::end(outputSectionCommands), commandsStart); + _outputSectionCommands = llvm::makeArrayRef(commandsStart, numCommands); + } + + static bool classof(const Command *c) { + return c->getKind() == Kind::OutputSectionDescription; + } + + void dump(raw_ostream &os) const override; + + const_iterator begin() const { return _outputSectionCommands.begin(); } + const_iterator end() const { return _outputSectionCommands.end(); } + StringRef name() const { return _sectionName; } + +private: + StringRef _sectionName; + const Expression *_address; + const Expression *_align; + const Expression *_subAlign; + const Expression *_at; + const Expression *_fillExpr; + StringRef _fillStream; + bool _alignWithInput; + bool _discard; + Constraint _constraint; + llvm::ArrayRef _outputSectionCommands; +}; + +/// Represents an Overlay structure as documented in +/// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description +class Overlay : public Command { +public: + Overlay(Parser &ctx) : Command(ctx, Kind::Overlay) {} + + static bool classof(const Command *c) { + return c->getKind() == Kind::Overlay; + } + + void dump(raw_ostream &os) const override { os << "Overlay description\n"; } +}; + +/// Represents all the contents of the SECTIONS {} construct. +class Sections : public Command { +public: + typedef llvm::ArrayRef::const_iterator const_iterator; + + Sections(Parser &ctx, + const SmallVectorImpl §ionsCommands) + : Command(ctx, Kind::Sections) { + size_t numCommands = sectionsCommands.size(); + const Command **commandsStart = + getAllocator().Allocate(numCommands); + std::copy(std::begin(sectionsCommands), std::end(sectionsCommands), + commandsStart); + _sectionsCommands = llvm::makeArrayRef(commandsStart, numCommands); + } + + static bool classof(const Command *c) { + return c->getKind() == Kind::Sections; + } + + void dump(raw_ostream &os) const override; + const_iterator begin() const { return _sectionsCommands.begin(); } + const_iterator end() const { return _sectionsCommands.end(); } + +private: + llvm::ArrayRef _sectionsCommands; +}; + +/// Represents a single memory block definition in a MEMORY {} command. +class MemoryBlock { +public: + MemoryBlock(StringRef name, StringRef attr, + const Expression *origin, const Expression *length) + : _name(name), _attr(attr), _origin(origin), _length(length) {} + + void dump(raw_ostream &os) const; + +private: + StringRef _name; + StringRef _attr; + const Expression *_origin; + const Expression *_length; +}; + +/// Represents all the contents of the MEMORY {} command. +class Memory : public Command { +public: + Memory(Parser &ctx, + const SmallVectorImpl &blocks) + : Command(ctx, Kind::Memory) { + size_t numBlocks = blocks.size(); + const MemoryBlock **blocksStart = + getAllocator().Allocate(numBlocks); + std::copy(std::begin(blocks), std::end(blocks), blocksStart); + _blocks = llvm::makeArrayRef(blocksStart, numBlocks); + } + + static bool classof(const Command *c) { + return c->getKind() == Kind::Memory; + } + + void dump(raw_ostream &os) const override; + +private: + llvm::ArrayRef _blocks; +}; + +/// Represents an extern command. +class Extern : public Command { +public: + typedef llvm::ArrayRef::const_iterator const_iterator; + + Extern(Parser &ctx, + const SmallVectorImpl &symbols) + : Command(ctx, Kind::Extern) { + size_t numSymbols = symbols.size(); + StringRef *symbolsStart = + getAllocator().Allocate(numSymbols); + std::copy(std::begin(symbols), std::end(symbols), symbolsStart); + _symbols = llvm::makeArrayRef(symbolsStart, numSymbols); + } + + static bool classof(const Command *c) { + return c->getKind() == Kind::Extern; + } + + void dump(raw_ostream &os) const override; + const_iterator begin() const { return _symbols.begin(); } + const_iterator end() const { return _symbols.end(); } + +private: + llvm::ArrayRef _symbols; +}; + +/// Stores the parse tree of a linker script. +class LinkerScript { +public: + void dump(raw_ostream &os) const { + for (const Command *c : _commands) { + c->dump(os); + if (isa(c)) + os << "\n"; + } + } + + std::vector _commands; +}; + +/// Recognizes syntactic constructs of a linker script using a predictive +/// parser/recursive descent implementation. +/// +/// Based on the linker script documentation available at +/// https://sourceware.org/binutils/docs/ld/Scripts.html +class Parser { +public: + explicit Parser(std::unique_ptr mb) + : _lex(std::move(mb)), _peekAvailable(false) {} + + /// Let's not allow copying of Parser class because it would be expensive + /// to update all the AST pointers to a new buffer. + Parser(const Parser &instance) = delete; + + /// Lex and parse the current memory buffer to create a linker script AST. + std::error_code parse(); + + /// Returns a reference to the top level node of the linker script AST. + LinkerScript *get() { return &_script; } + + /// Returns a reference to the underlying allocator. + llvm::BumpPtrAllocator &getAllocator() { return _alloc; } + +private: + /// Advances to the next token, either asking the Lexer to lex the next token + /// or obtaining it from the look ahead buffer. + void consumeToken() { + // First check if the look ahead buffer cached the next token + if (_peekAvailable) { + _tok = _bufferedToken; + _peekAvailable = false; + return; + } + _lex.lex(_tok); + } + + /// Returns the token that succeeds the current one without consuming the + /// current token. This operation will lex an additional token and store it in + /// a private buffer. + const Token &peek() { + if (_peekAvailable) + return _bufferedToken; + + _lex.lex(_bufferedToken); + _peekAvailable = true; + return _bufferedToken; + } + + void error(const Token &tok, Twine msg) { + _lex.getSourceMgr().PrintMessage( + llvm::SMLoc::getFromPointer(tok._range.data()), + llvm::SourceMgr::DK_Error, msg); + } + + bool expectAndConsume(Token::Kind kind, Twine msg) { + if (_tok._kind != kind) { + error(_tok, msg); + return false; + } + consumeToken(); + return true; + } + + bool isNextToken(Token::Kind kind) { return (_tok._kind == kind); } + + // Recursive descent parsing member functions + // All of these functions consumes tokens and return an AST object, + // represented by the Command superclass. However, note that not all AST + // objects derive from Command. For nodes of C-like expressions, used in + // linker scripts, the superclass is Expression. For nodes that represent + // input sections that map to an output section, the superclass is + // InputSection. + // + // Example mapping common constructs to AST nodes: + // + // SECTIONS { /* Parsed to Sections class */ + // my_symbol = 1 + 1; /* Parsed to SymbolAssignment class */ + // /* ^~~> Parsed to Expression class */ + // .data : { *(.data) } /* Parsed to OutputSectionDescription class */ + // /* ^~~> Parsed to InputSectionName class */ + // /* ^~~~~> Parsed to InputSectionsCmd class */ + // } + + // ==== Expression parsing member functions ==== + + /// Parse "identifier(param [, param]...)" + /// + /// Example: + /// + /// SECTIONS { + /// my_symbol = 0x1000 | ALIGN(other_symbol); + /// /* ^~~~> parseFunctionCall() + /// } + const Expression *parseFunctionCall(); + + /// Ensures that the current token is an expression operand. If it is not, + /// issues an error to the user and returns false. + bool expectExprOperand(); + + /// Parse operands of an expression, such as function calls, identifiers, + /// literal numbers or unary operators. + /// + /// Example: + /// + /// SECTIONS { + /// my_symbol = 0x1000 | ALIGN(other_symbol); + /// ^~~~> parseExprTerminal() + /// } + const Expression *parseExprOperand(); + + // As a reference to the precedence of C operators, consult + // http://en.cppreference.com/w/c/language/operator_precedence + + /// Parse either a single expression operand and returns or parse an entire + /// expression if its top-level node has a lower or equal precedence than the + /// indicated. + const Expression *parseExpression(unsigned precedence = 13); + + /// Parse an operator and its rhs operand, assuming that the lhs was already + /// consumed. Keep parsing subsequent operator-operand pairs that do not + /// exceed highestPrecedence. + /// * lhs points to the left-hand-side operand of this operator + /// * maxPrecedence has the maximum operator precedence level that this parse + /// function is allowed to consume. + const Expression *parseOperatorOperandLoop(const Expression *lhs, + unsigned maxPrecedence); + + /// Parse ternary conditionals such as "(condition)? true: false;". This + /// operator has precedence level 13 and associates right-to-left. + const Expression *parseTernaryCondOp(const Expression *lhs); + + // ==== High-level commands parsing ==== + + /// Parse the OUTPUT linker script command. + /// Example: + /// OUTPUT(/path/to/file) + /// ^~~~> parseOutput() + /// + Output *parseOutput(); + + /// Parse the OUTPUT_FORMAT linker script command. + /// Example: + /// + /// OUTPUT_FORMAT(elf64-x86-64,elf64-x86-64,elf64-x86-64) + /// ^~~~> parseOutputFormat() + /// + OutputFormat *parseOutputFormat(); + + /// Parse the OUTPUT_ARCH linker script command. + /// Example: + /// + /// OUTPUT_ARCH(i386:x86-64) + /// ^~~~> parseOutputArch() + /// + OutputArch *parseOutputArch(); + + /// Parse the INPUT or GROUP linker script command. + /// Example: + /// + /// GROUP ( /lib/x86_64-linux-gnu/libc.so.6 + /// /usr/lib/x86_64-linux-gnu/libc_nonshared.a + /// AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) + /// -lm -l:libgcc.a ) + /// + template T *parsePathList(); + bool parseAsNeeded(SmallVectorImpl &paths); + + /// Parse the ENTRY linker script command. + /// Example: + /// + /// ENTRY(init) + /// ^~~~> parseEntry() + /// + Entry *parseEntry(); + + /// Parse the SEARCH_DIR linker script command. + /// Example: + /// + /// SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); + /// ^~~~> parseSearchDir() + /// + SearchDir *parseSearchDir(); + + /// Parse "symbol = expression" commands that live inside the + /// SECTIONS directive. + /// Example: + /// + /// SECTIONS { + /// my_symbol = 1 + 1; + /// ^~~~> parseExpression() + /// ^~~~ parseSymbolAssignment() + /// } + /// + const SymbolAssignment *parseSymbolAssignment(); + + /// Parse "EXCLUDE_FILE" used inside the listing of input section names. + /// Example: + /// + /// SECTIONS { + /// .data : { *(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors) } + /// ^~~~> parseExcludeFile() + /// } + /// + ErrorOr parseExcludeFile(); + + /// Helper to parse SORT_BY_NAME(, SORT_BY_ALIGNMENT( and SORT_NONE(, + /// possibly nested. Returns the number of Token::r_paren tokens that need + /// to be consumed, while sortMode is updated with the parsed sort + /// criteria. + /// Example: + /// + /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*)) + /// ^~~~ parseSortDirectives() ~~^ + /// Returns 2, finishes with sortMode = WildcardSortMode::ByNameAndAlignment + /// + int parseSortDirectives(WildcardSortMode &sortMode); + + /// Parse a group of input section names that are sorted via SORT* directives. + /// Example: + /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*data *bss)) + const InputSection *parseSortedInputSections(); + + /// Parse input section description statements. + /// Example: + /// + /// SECTIONS { + /// .mysection : crt.o(.data* .bss SORT_BY_NAME(name*)) + /// ^~~~ parseInputSectionsCmd() + /// } + const InputSectionsCmd *parseInputSectionsCmd(); + + /// Parse output section description statements. + /// Example: + /// + /// SECTIONS { + /// .data : { crt.o(.data* .bss SORT_BY_NAME(name*)) } + /// ^~~~ parseOutputSectionDescription() + /// } + const OutputSectionDescription *parseOutputSectionDescription(); + + /// Stub for parsing overlay commands. Currently unimplemented. + const Overlay *parseOverlay(); + + /// Parse the SECTIONS linker script command. + /// Example: + /// + /// SECTIONS { + /// ^~~~ parseSections() + /// . = 0x100000; + /// .data : { *(.data) } + /// } + /// + Sections *parseSections(); + + /// Parse the MEMORY linker script command. + /// Example: + /// + /// MEMORY { + /// ^~~~ parseMemory() + /// ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K + /// rom (rx) : ORIGIN = 0x0, LENGTH = 256K + /// } + /// + Memory *parseMemory(); + + /// Parse the EXTERN linker script command. + /// Example: + /// + /// EXTERN(symbol symbol ...) + /// ^~~~> parseExtern() + /// + Extern *parseExtern(); + +private: + // Owns the entire linker script AST nodes + llvm::BumpPtrAllocator _alloc; + + // The top-level/entry-point linker script AST node + LinkerScript _script; + + Lexer _lex; + + // Current token being analyzed + Token _tok; + + // Annotate whether we buffered the next token to allow peeking + bool _peekAvailable; + Token _bufferedToken; +}; + +/// script::Sema traverses all parsed linker script structures and populate +/// internal data structures to be able to answer the following questions: +/// +/// * According to the linker script, which input section goes first in the +/// output file layout, input section A or input section B? +/// +/// * What is the name of the output section that input section A should be +/// mapped to? +/// +/// * Which linker script expressions should be calculated before emitting +/// a given section? +/// +/// * How to evaluate a given linker script expression? +/// +class Sema { +public: + /// From the linker script point of view, this class represents the minimum + /// set of information to uniquely identify an input section. + struct SectionKey { + StringRef archivePath; + StringRef memberPath; + StringRef sectionName; + }; + + Sema(); + + /// We can parse several linker scripts via command line whose ASTs are stored + /// here via addLinkerScript(). + void addLinkerScript(std::unique_ptr script) { + _scripts.push_back(std::move(script)); + } + + const std::vector> &getLinkerScripts() { + return _scripts; + } + + /// Prepare our data structures according to the linker scripts currently in + /// our control (control given via addLinkerScript()). Called once all linker + /// scripts have been parsed. + void perform(); + + /// Answer if we have layout commands (section mapping rules). If we don't, + /// the output file writer can assume there is no linker script special rule + /// to handle. + bool hasLayoutCommands() const { return _layoutCommands.size() > 0; } + + /// Return true if this section has a mapping rule in the linker script + bool hasMapping(const SectionKey &key) const { + return getLayoutOrder(key, true) >= 0; + } + + /// Order function - used to sort input sections in the output file according + /// to linker script custom mappings. Return true if lhs should appear before + /// rhs. + bool less(const SectionKey &lhs, const SectionKey &rhs) const; + + /// Retrieve the name of the output section that this input section is mapped + /// to, according to custom linker script mappings. + StringRef getOutputSection(const SectionKey &key) const; + + /// Retrieve all the linker script expressions that need to be evaluated + /// before the given section is emitted. This is *not* const because the + /// first section to retrieve a given set of expression is the only one to + /// receive it. This set is marked as "delivered" and no other sections can + /// retrieve this set again. If we don't do this, multiple sections may map + /// to the same set of expressions because of wildcards rules. + std::vector getExprs(const SectionKey &key); + + /// Evaluate a single linker script expression according to our current + /// context (symbol table). This function is *not* constant because it can + /// update our symbol table with new symbols calculated in this expression. + std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos); + + /// Retrieve the set of symbols defined in linker script expressions. + const llvm::StringSet<> &getScriptDefinedSymbols() const; + + /// Queries the linker script symbol table for the value of a given symbol. + /// This function must be called after linker script expressions evaluation + /// has been performed (by calling evalExpr() for all expressions). + uint64_t getLinkerScriptExprValue(StringRef name) const; + + void dump() const; + +private: + /// A custom hash operator to teach the STL how to handle our custom keys. + /// This will be used in our hash table mapping Sections to a Layout Order + /// number (caching results). + struct SectionKeyHash { + int64_t operator()(const SectionKey &k) const { + return llvm::hash_combine(k.archivePath, k.memberPath, k.sectionName); + } + }; + + /// Teach the STL when two section keys are the same. This will be used in + /// our hash table mapping Sections to a Layout Order number (caching results) + struct SectionKeyEq { + bool operator()(const SectionKey &lhs, const SectionKey &rhs) const { + return ((lhs.archivePath == rhs.archivePath) && + (lhs.memberPath == rhs.memberPath) && + (lhs.sectionName == rhs.sectionName)); + } + }; + + /// Given an order id, check if it matches the tuple + /// and returns the + /// internal id that matched, or -1 if no matches. + int matchSectionName(int id, const SectionKey &key) const; + + /// Returns a number that will determine the order of this input section + /// in the final layout. If coarse is true, we simply return the layour order + /// of the higher-level node InputSectionsCmd, used to order input sections. + /// If coarse is false, we return the layout index down to the internal + /// InputSectionsCmd arrangement, used to get the set of preceding linker + ///expressions. + int getLayoutOrder(const SectionKey &key, bool coarse) const; + + /// Compare two sections that have the same mapping rule (i.e., are matched + /// by the same InputSectionsCmd). + /// Determine if lhs < rhs by analyzing the InputSectionsCmd structure. + bool localCompare(int order, const SectionKey &lhs, + const SectionKey &rhs) const; + + + /// Our goal with all linearizeAST overloaded functions is to + /// traverse the linker script AST while putting nodes in a vector and + /// thus enforcing order among nodes (which comes first). + /// + /// The order among nodes is determined by their indexes in this vector + /// (_layoutCommands). This index allows us to solve the problem of + /// establishing the order among two different input sections: we match each + /// input sections with their respective layout command and use the indexes + /// of these commands to order these sections. + /// + /// Example: + /// + /// Given the linker script: + /// SECTIONS { + /// .text : { *(.text) } + /// .data : { *(.data) } + /// } + /// + /// The _layoutCommands vector should contain: + /// id 0 : (_sectionName = ".text") + /// id 1 : (_memberName = "*") + /// id 2 : (_name = ".text) + /// id 3 : (_sectionName = ".data") + /// id 4 : (_memberName = "*") + /// id 5 : (_name = ".data") + /// + /// If we need to sort the following input sections: + /// + /// input section A: .text from libc.a (member errno.o) + /// input section B: .data from libc.a (member write.o) + /// + /// Then we match input section A with the InputSectionsCmd of id 1, and + /// input section B with the InputSectionsCmd of id 4. Since 1 < 4, we + /// put A before B. + /// + /// The second problem handled by the linearization of the AST is the task + /// of finding all preceding expressions that need to be calculated before + /// emitting a given section. This task is easier to deal with when all nodes + /// are in a vector because otherwise we would need to traverse multiple + /// levels of the AST to find the set of expressions that preceed a layout + /// command. + /// + /// The linker script commands that are linearized ("layout commands") are: + /// + /// * OutputSectionDescription, containing an output section name + /// * InputSectionsCmd, containing an input file name + /// * InputSectionName, containing a single input section name + /// * InputSectionSortedName, a group of input section names + /// * SymbolAssignment, containing an expression that may + /// change the address where the linker is outputting data + /// + void linearizeAST(const Sections *sections); + void linearizeAST(const InputSectionsCmd *inputSections); + void linearizeAST(const InputSection *inputSection); + + void perform(const LinkerScript *ls); + + std::vector> _scripts; + std::vector _layoutCommands; + std::unordered_multimap _memberToLayoutOrder; + std::vector> _memberNameWildcards; + mutable std::unordered_map + _cacheSectionOrder, _cacheExpressionOrder; + llvm::DenseSet _deliveredExprs; + mutable llvm::StringSet<> _definedSymbols; + + Expression::SymbolTableTy _symbolTable; +}; + +llvm::BumpPtrAllocator &Command::getAllocator() const { + return _ctx.getAllocator(); +} +llvm::BumpPtrAllocator &Expression::getAllocator() const { + return _ctx.getAllocator(); +} +} // end namespace script +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h new file mode 100644 index 000000000000..8e253a1235f1 --- /dev/null +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -0,0 +1,369 @@ +//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H +#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Reader.h" +#include "lld/Core/Writer.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MachO.h" +#include + +using llvm::MachO::HeaderFileType; + +namespace lld { + +namespace mach_o { +class ArchHandler; +class MachODylibFile; +class MachOFile; +} + +class MachOLinkingContext : public LinkingContext { +public: + MachOLinkingContext(); + ~MachOLinkingContext(); + + enum Arch { + arch_unknown, + arch_ppc, + arch_x86, + arch_x86_64, + arch_armv6, + arch_armv7, + arch_armv7s, + arch_arm64, + }; + + enum class OS { + unknown, + macOSX, + iOS, + iOS_simulator + }; + + enum class ExportMode { + globals, // Default, all global symbols exported. + whiteList, // -exported_symbol[s_list], only listed symbols exported. + blackList // -unexported_symbol[s_list], no listed symbol exported. + }; + + enum class DebugInfoMode { + addDebugMap, // Default + noDebugMap // -S option + }; + + /// Initializes the context to sane default values given the specified output + /// file type, arch, os, and minimum os version. This should be called before + /// other setXXX() methods. + void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion); + + void addPasses(PassManager &pm) override; + bool validateImpl(raw_ostream &diagnostics) override; + std::string demangle(StringRef symbolName) const override; + + bool createImplicitFiles(std::vector> &) override; + + uint32_t getCPUType() const; + uint32_t getCPUSubType() const; + + bool addEntryPointLoadCommand() const; + bool addUnixThreadLoadCommand() const; + bool outputTypeHasEntry() const; + bool is64Bit() const; + + virtual uint64_t pageZeroSize() const { return _pageZeroSize; } + virtual uint64_t pageSize() const { return _pageSize; } + + mach_o::ArchHandler &archHandler() const; + + HeaderFileType outputMachOType() const { return _outputMachOType; } + + Arch arch() const { return _arch; } + StringRef archName() const { return nameFromArch(_arch); } + OS os() const { return _os; } + + ExportMode exportMode() const { return _exportMode; } + void setExportMode(ExportMode mode) { _exportMode = mode; } + void addExportSymbol(StringRef sym); + bool exportRestrictMode() const { return _exportMode != ExportMode::globals; } + bool exportSymbolNamed(StringRef sym) const; + + DebugInfoMode debugInfoMode() const { return _debugInfoMode; } + void setDebugInfoMode(DebugInfoMode mode) { + _debugInfoMode = mode; + } + + void appendOrderedSymbol(StringRef symbol, StringRef filename); + + bool keepPrivateExterns() const { return _keepPrivateExterns; } + void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; } + bool demangleSymbols() const { return _demangle; } + void setDemangleSymbols(bool d) { _demangle = d; } + /// Create file at specified path which will contain a binary encoding + /// of all input and output file paths. + std::error_code createDependencyFile(StringRef path); + void addInputFileDependency(StringRef path) const; + void addInputFileNotFound(StringRef path) const; + void addOutputFileDependency(StringRef path) const; + + bool minOS(StringRef mac, StringRef iOS) const; + void setDoNothing(bool value) { _doNothing = value; } + bool doNothing() const { return _doNothing; } + bool printAtoms() const { return _printAtoms; } + bool testingFileUsage() const { return _testingFileUsage; } + const StringRefVector &searchDirs() const { return _searchDirs; } + const StringRefVector &frameworkDirs() const { return _frameworkDirs; } + void setSysLibRoots(const StringRefVector &paths); + const StringRefVector &sysLibRoots() const { return _syslibRoots; } + bool PIE() const { return _pie; } + void setPIE(bool pie) { _pie = pie; } + + uint64_t baseAddress() const { return _baseAddress; } + void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } + + /// \brief Checks whether a given path on the filesystem exists. + /// + /// When running in -test_file_usage mode, this method consults an + /// internally maintained list of files that exist (provided by -path_exists) + /// instead of the actual filesystem. + bool pathExists(StringRef path) const; + + /// Like pathExists() but only used on files - not directories. + bool fileExists(StringRef path) const; + + /// \brief Adds any library search paths derived from the given base, possibly + /// modified by -syslibroots. + /// + /// The set of paths added consists of approximately all syslibroot-prepended + /// versions of libPath that exist, or the original libPath if there are none + /// for whatever reason. With various edge-cases for compatibility. + void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false); + + /// \brief Determine whether -lFoo can be resolve within the given path, and + /// return the filename if so. + /// + /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in + /// that order, unless Foo ends in ".o", in which case only the exact file + /// matches (e.g. -lfoo.o would only find foo.o). + ErrorOr searchDirForLibrary(StringRef path, + StringRef libName) const; + + /// \brief Iterates through all search path entries looking for libName (as + /// specified by -lFoo). + ErrorOr searchLibrary(StringRef libName) const; + + /// Add a framework search path. Internally, this method may be prepended + /// the path with syslibroot. + void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false); + + /// \brief Iterates through all framework directories looking for + /// Foo.framework/Foo (when fwName = "Foo"). + ErrorOr findPathForFramework(StringRef fwName) const; + + /// \brief The dylib's binary compatibility version, in the raw uint32 format. + /// + /// When building a dynamic library, this is the compatibility version that + /// gets embedded into the result. Other Mach-O binaries that link against + /// this library will store the compatibility version in its load command. At + /// runtime, the loader will verify that the binary is compatible with the + /// installed dynamic library. + uint32_t compatibilityVersion() const { return _compatibilityVersion; } + + /// \brief The dylib's current version, in the the raw uint32 format. + /// + /// When building a dynamic library, this is the current version that gets + /// embedded into the result. Other Mach-O binaries that link against + /// this library will store the compatibility version in its load command. + uint32_t currentVersion() const { return _currentVersion; } + + /// \brief The dylib's install name. + /// + /// Binaries that link against the dylib will embed this path into the dylib + /// load command. When loading the binaries at runtime, this is the location + /// on disk that the loader will look for the dylib. + StringRef installName() const { return _installName; } + + /// \brief Whether or not the dylib has side effects during initialization. + /// + /// Dylibs marked as being dead strippable provide the guarantee that loading + /// the dylib has no side effects, allowing the linker to strip out the dylib + /// when linking a binary that does not use any of its symbols. + bool deadStrippableDylib() const { return _deadStrippableDylib; } + + /// \brief The path to the executable that will load the bundle at runtime. + /// + /// When building a Mach-O bundle, this executable will be examined if there + /// are undefined symbols after the main link phase. It is expected that this + /// binary will be loading the bundle at runtime and will provide the symbols + /// at that point. + StringRef bundleLoader() const { return _bundleLoader; } + + void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; } + void setCurrentVersion(uint32_t vers) { _currentVersion = vers; } + void setInstallName(StringRef name) { _installName = name; } + void setDeadStrippableDylib(bool deadStrippable) { + _deadStrippableDylib = deadStrippable; + } + void setBundleLoader(StringRef loader) { _bundleLoader = loader; } + void setPrintAtoms(bool value=true) { _printAtoms = value; } + void setTestingFileUsage(bool value = true) { + _testingFileUsage = value; + } + void addExistingPathForDebug(StringRef path) { + _existingPaths.insert(path); + } + + void addRpath(StringRef rpath); + const StringRefVector &rpaths() const { return _rpaths; } + + /// Add section alignment constraint on final layout. + void addSectionAlignment(StringRef seg, StringRef sect, uint8_t align2); + + /// Returns true if specified section had alignment constraints. + bool sectionAligned(StringRef seg, StringRef sect, uint8_t &align2) const; + + StringRef dyldPath() const { return "/usr/lib/dyld"; } + + /// Stub creation Pass should be run. + bool needsStubsPass() const; + + // GOT creation Pass should be run. + bool needsGOTPass() const; + + /// Pass to transform __compact_unwind into __unwind_info should be run. + bool needsCompactUnwindPass() const; + + /// Pass to add shims switching between thumb and arm mode. + bool needsShimPass() const; + + /// Magic symbol name stubs will need to help lazy bind. + StringRef binderSymbolName() const; + + /// Used to keep track of direct and indirect dylibs. + void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const; + + // Reads a file from disk to memory. Returns only a needed chunk + // if a fat binary. + ErrorOr> getMemoryBuffer(StringRef path); + + /// Used to find indirect dylibs. Instantiates a MachODylibFile if one + /// has not already been made for the requested dylib. Uses -L and -F + /// search paths to allow indirect dylibs to be overridden. + mach_o::MachODylibFile* findIndirectDylib(StringRef path); + + uint32_t dylibCurrentVersion(StringRef installName) const; + + uint32_t dylibCompatVersion(StringRef installName) const; + + /// Creates a copy (owned by this MachOLinkingContext) of a string. + StringRef copy(StringRef str) { return str.copy(_allocator); } + + /// If the memoryBuffer is a fat file with a slice for the current arch, + /// this method will return the offset and size of that slice. + bool sliceFromFatFile(const MemoryBuffer &mb, uint32_t &offset, + uint32_t &size); + + /// Returns if a command line option specified dylib is an upward link. + bool isUpwardDylib(StringRef installName) const; + + static bool isThinObjectFile(StringRef path, Arch &arch); + static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); + static Arch archFromName(StringRef archName); + static StringRef nameFromArch(Arch arch); + static uint32_t cpuTypeFromArch(Arch arch); + static uint32_t cpuSubtypeFromArch(Arch arch); + static bool is64Bit(Arch arch); + static bool isHostEndian(Arch arch); + static bool isBigEndian(Arch arch); + + /// Construct 32-bit value from string "X.Y.Z" where + /// bits are xxxx.yy.zz. Largest number is 65535.255.255 + static bool parsePackedVersion(StringRef str, uint32_t &result); + + void finalizeInputFiles() override; + + bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, + bool &leftBeforeRight) const; + +private: + Writer &writer() const override; + mach_o::MachODylibFile* loadIndirectDylib(StringRef path); + void checkExportWhiteList(const DefinedAtom *atom) const; + void checkExportBlackList(const DefinedAtom *atom) const; + struct ArchInfo { + StringRef archName; + MachOLinkingContext::Arch arch; + bool littleEndian; + uint32_t cputype; + uint32_t cpusubtype; + }; + + struct SectionAlign { + StringRef segmentName; + StringRef sectionName; + uint8_t align2; + }; + + struct OrderFileNode { + StringRef fileFilter; + unsigned order; + }; + + static bool findOrderOrdinal(const std::vector &nodes, + const DefinedAtom *atom, unsigned &ordinal); + + static ArchInfo _s_archInfos[]; + + std::set _existingPaths; // For testing only. + StringRefVector _searchDirs; + StringRefVector _syslibRoots; + StringRefVector _frameworkDirs; + HeaderFileType _outputMachOType; // e.g MH_EXECUTE + bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog + bool _doNothing; // for -help and -v which just print info + bool _pie; + Arch _arch; + OS _os; + uint32_t _osMinVersion; + uint64_t _pageZeroSize; + uint64_t _pageSize; + uint64_t _baseAddress; + uint32_t _compatibilityVersion; + uint32_t _currentVersion; + StringRef _installName; + StringRefVector _rpaths; + bool _deadStrippableDylib; + bool _printAtoms; + bool _testingFileUsage; + bool _keepPrivateExterns; + bool _demangle; + StringRef _bundleLoader; + mutable std::unique_ptr _archHandler; + mutable std::unique_ptr _writer; + std::vector _sectAligns; + mutable llvm::StringMap _pathToDylibMap; + mutable std::set _allDylibs; + mutable std::set _upwardDylibs; + mutable std::vector> _indirectDylibs; + ExportMode _exportMode; + llvm::StringSet<> _exportedSymbols; + DebugInfoMode _debugInfoMode; + std::unique_ptr _dependencyInfo; + llvm::StringMap> _orderFiles; + unsigned _orderFileEntries; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/PECOFFLinkingContext.h b/include/lld/ReaderWriter/PECOFFLinkingContext.h new file mode 100644 index 000000000000..cccb8ac03b6e --- /dev/null +++ b/include/lld/ReaderWriter/PECOFFLinkingContext.h @@ -0,0 +1,463 @@ +//===- lld/ReaderWriter/PECOFFLinkingContext.h ----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H +#define LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Reader.h" +#include "lld/Core/Writer.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileUtilities.h" +#include +#include +#include +#include + +using llvm::COFF::MachineTypes; +using llvm::COFF::WindowsSubsystem; + +static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'}; + +namespace lld { + +class PECOFFLinkingContext : public LinkingContext { +public: + PECOFFLinkingContext() + : _mutex(), _allocMutex(), _hasEntry(true), + _baseAddress(invalidBaseAddress), _stackReserve(1024 * 1024), + _stackCommit(4096), _heapReserve(1024 * 1024), _heapCommit(4096), + _noDefaultLibAll(false), _sectionDefaultAlignment(4096), + _subsystem(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN), + _machineType(llvm::COFF::IMAGE_FILE_MACHINE_I386), _imageVersion(0, 0), + _minOSVersion(6, 0), _nxCompat(true), _largeAddressAware(false), + _allowBind(true), _allowIsolation(true), _swapRunFromCD(false), + _swapRunFromNet(false), _baseRelocationEnabled(true), + _terminalServerAware(true), _dynamicBaseEnabled(true), + _createManifest(true), _embedManifest(false), _manifestId(1), + _manifestUAC(true), _manifestLevel("'asInvoker'"), + _manifestUiAccess("'false'"), _isDll(false), _highEntropyVA(true), + _requireSEH(false), _noSEH(false), _implib(""), _debug(false), + _pdbFilePath(""), _dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)), + _parseDirectives(nullptr) { + setDeadStripping(true); + } + + struct Version { + Version(int v1, int v2) : majorVersion(v1), minorVersion(v2) {} + int majorVersion; + int minorVersion; + }; + + struct ExportDesc { + ExportDesc() + : ordinal(-1), noname(false), isData(false), isPrivate(false) {} + + bool operator<(const ExportDesc &other) const { + return getExternalName().compare(other.getExternalName()) < 0; + } + + StringRef getRealName() const { + return mangledName.empty() ? name : mangledName; + } + + StringRef getExternalName() const { + return externalName.empty() ? name : externalName; + } + + std::string name; + std::string externalName; + std::string mangledName; + int ordinal; + bool noname; + bool isData; + bool isPrivate; + }; + + typedef bool (*ParseDirectives)(int, const char **, PECOFFLinkingContext &, + raw_ostream &); + + /// \brief Casting support + static bool classof(const LinkingContext *info) { return true; } + + Writer &writer() const override; + bool validateImpl(raw_ostream &diagnostics) override; + + void addPasses(PassManager &pm) override; + + bool createImplicitFiles( + std::vector > &result) override; + + bool is64Bit() const { + return _machineType == llvm::COFF::IMAGE_FILE_MACHINE_AMD64; + } + + // Returns a set of all defined symbols in input files. + const std::set &definedSymbols(); + + /// Page size of x86 processor. Some data needs to be aligned at page boundary + /// when loaded into memory. + uint64_t getPageSize() const { + return 0x1000; + } + + void appendInputSearchPath(StringRef dirPath) { + _inputSearchPaths.push_back(dirPath); + } + + const std::vector getInputSearchPaths() { + return _inputSearchPaths; + } + + void registerTemporaryFile(StringRef path) { + std::unique_ptr fileRemover( + new llvm::FileRemover(Twine(allocate(path)))); + _tempFiles.push_back(std::move(fileRemover)); + } + + StringRef searchLibraryFile(StringRef path) const; + + StringRef decorateSymbol(StringRef name) const; + StringRef undecorateSymbol(StringRef name) const; + + void setEntrySymbolName(StringRef name) { _entry = name; } + StringRef getEntrySymbolName() const { return _entry; } + + void setHasEntry(bool val) { _hasEntry = val; } + bool hasEntry() const { return _hasEntry; } + + void setBaseAddress(uint64_t addr) { _baseAddress = addr; } + uint64_t getBaseAddress() const; + + void setStackReserve(uint64_t size) { _stackReserve = size; } + void setStackCommit(uint64_t size) { _stackCommit = size; } + uint64_t getStackReserve() const { return _stackReserve; } + uint64_t getStackCommit() const { return _stackCommit; } + + void setHeapReserve(uint64_t size) { _heapReserve = size; } + void setHeapCommit(uint64_t size) { _heapCommit = size; } + uint64_t getHeapReserve() const { return _heapReserve; } + uint64_t getHeapCommit() const { return _heapCommit; } + + void setSectionDefaultAlignment(uint32_t val) { + _sectionDefaultAlignment = val; + } + uint32_t getSectionDefaultAlignment() const { + return _sectionDefaultAlignment; + } + + void setSubsystem(WindowsSubsystem ss) { _subsystem = ss; } + WindowsSubsystem getSubsystem() const { return _subsystem; } + + void setMachineType(MachineTypes type) { _machineType = type; } + MachineTypes getMachineType() const { return _machineType; } + + void setImageVersion(const Version &version) { _imageVersion = version; } + Version getImageVersion() const { return _imageVersion; } + + void setMinOSVersion(const Version &version) { _minOSVersion = version; } + Version getMinOSVersion() const { return _minOSVersion; } + + void setNxCompat(bool nxCompat) { _nxCompat = nxCompat; } + bool isNxCompat() const { return _nxCompat; } + + void setLargeAddressAware(bool val) { _largeAddressAware = val; } + bool getLargeAddressAware() const { return _largeAddressAware; } + + void setAllowBind(bool val) { _allowBind = val; } + bool getAllowBind() const { return _allowBind; } + + void setAllowIsolation(bool val) { _allowIsolation = val; } + bool getAllowIsolation() const { return _allowIsolation; } + + void setSwapRunFromCD(bool val) { _swapRunFromCD = val; } + bool getSwapRunFromCD() const { return _swapRunFromCD; } + + void setSwapRunFromNet(bool val) { _swapRunFromNet = val; } + bool getSwapRunFromNet() const { return _swapRunFromNet; } + + void setBaseRelocationEnabled(bool val) { _baseRelocationEnabled = val; } + bool getBaseRelocationEnabled() const { return _baseRelocationEnabled; } + + void setTerminalServerAware(bool val) { _terminalServerAware = val; } + bool isTerminalServerAware() const { return _terminalServerAware; } + + void setDynamicBaseEnabled(bool val) { _dynamicBaseEnabled = val; } + bool getDynamicBaseEnabled() const { return _dynamicBaseEnabled; } + + void setCreateManifest(bool val) { _createManifest = val; } + bool getCreateManifest() const { return _createManifest; } + + void setManifestOutputPath(std::string val) { _manifestOutputPath = val; } + const std::string &getManifestOutputPath() const { + return _manifestOutputPath; + } + + void setEmbedManifest(bool val) { _embedManifest = val; } + bool getEmbedManifest() const { return _embedManifest; } + + void setManifestId(int val) { _manifestId = val; } + int getManifestId() const { return _manifestId; } + + void setManifestUAC(bool val) { _manifestUAC = val; } + bool getManifestUAC() const { return _manifestUAC; } + + void setManifestLevel(std::string val) { _manifestLevel = std::move(val); } + const std::string &getManifestLevel() const { return _manifestLevel; } + + void setManifestUiAccess(std::string val) { _manifestUiAccess = val; } + const std::string &getManifestUiAccess() const { return _manifestUiAccess; } + + void setManifestDependency(std::string val) { _manifestDependency = val; } + const std::string &getManifestDependency() const { + return _manifestDependency; + } + + void setIsDll(bool val) { _isDll = val; } + bool isDll() const { return _isDll; } + + void setSafeSEH(bool val) { + if (val) + _requireSEH = true; + else + _noSEH = true; + } + bool requireSEH() const { return _requireSEH; } + bool noSEH() const { return _noSEH; } + + void setHighEntropyVA(bool val) { _highEntropyVA = val; } + bool getHighEntropyVA() const { return _highEntropyVA; } + + void setOutputImportLibraryPath(const std::string &val) { _implib = val; } + std::string getOutputImportLibraryPath() const; + + void setDebug(bool val) { _debug = val; } + bool getDebug() { return _debug; } + + void setPDBFilePath(StringRef str) { _pdbFilePath = str; } + std::string getPDBFilePath() const; + + void addDelayLoadDLL(StringRef dll) { + _delayLoadDLLs.insert(dll.lower()); + } + bool isDelayLoadDLL(StringRef dll) const { + return _delayLoadDLLs.count(dll.lower()) == 1; + } + + StringRef getOutputSectionName(StringRef sectionName) const; + bool addSectionRenaming(raw_ostream &diagnostics, + StringRef from, StringRef to); + + const std::set &getAlternateNames(StringRef name) { + return _alternateNames[name]; + } + + void addAlternateName(StringRef weak, StringRef def) { + _alternateNames[def].insert(weak); + } + + void addNoDefaultLib(StringRef path) { + if (path.endswith_lower(".lib")) + _noDefaultLibs.insert(path.drop_back(4).lower()); + else + _noDefaultLibs.insert(path.lower()); + } + + bool hasNoDefaultLib(StringRef path) const { + if (path.endswith_lower(".lib")) + return _noDefaultLibs.count(path.drop_back(4).lower()) > 0; + return _noDefaultLibs.count(path.lower()) > 0; + } + + void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; } + bool getNoDefaultLibAll() const { return _noDefaultLibAll; } + + void setSectionSetMask(StringRef sectionName, uint32_t flags); + void setSectionClearMask(StringRef sectionName, uint32_t flags); + uint32_t getSectionAttributes(StringRef sectionName, uint32_t flags) const; + + void setDosStub(ArrayRef data) { _dosStub = data; } + ArrayRef getDosStub() const { return _dosStub; } + + void addDllExport(ExportDesc &desc); + std::vector &getDllExports() { return _dllExports; } + const std::vector &getDllExports() const { return _dllExports; } + + StringRef getDelayLoadHelperName() const { + return is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2@8"; + } + + StringRef allocate(StringRef ref) const { + _allocMutex.lock(); + char *x = _allocator.Allocate(ref.size() + 1); + _allocMutex.unlock(); + memcpy(x, ref.data(), ref.size()); + x[ref.size()] = '\0'; + return x; + } + + ArrayRef allocate(ArrayRef array) const { + size_t size = array.size(); + _allocMutex.lock(); + uint8_t *p = _allocator.Allocate(size); + _allocMutex.unlock(); + memcpy(p, array.data(), size); + return ArrayRef(p, p + array.size()); + } + + template T &allocateCopy(const T &x) const { + _allocMutex.lock(); + T *r = new (_allocator) T(x); + _allocMutex.unlock(); + return *r; + } + + void addLibraryFile(std::unique_ptr file); + + void setModuleDefinitionFile(const std::string val) { + _moduleDefinitionFile = val; + } + std::string getModuleDefinitionFile() const { + return _moduleDefinitionFile; + } + + std::recursive_mutex &getMutex() { return _mutex; } + + void setParseDirectives(ParseDirectives parseDirectives) { + _parseDirectives = parseDirectives; + } + + ParseDirectives getParseDirectives() { + return _parseDirectives; + } + +protected: + /// Method to create a internal file for the entry symbol + std::unique_ptr createEntrySymbolFile() const override; + + /// Method to create a internal file for an undefined symbol + std::unique_ptr createUndefinedSymbolFile() const override; + +private: + enum : uint64_t { + invalidBaseAddress = UINT64_MAX, + pe32DefaultBaseAddress = 0x400000U, + pe32PlusDefaultBaseAddress = 0x140000000U + }; + + std::recursive_mutex _mutex; + mutable std::mutex _allocMutex; + + std::string _entry; + + // False if /noentry option is given. + bool _hasEntry; + + // The start address for the program. The default value for the executable is + // 0x400000, but can be altered using /base command line option. + uint64_t _baseAddress; + + uint64_t _stackReserve; + uint64_t _stackCommit; + uint64_t _heapReserve; + uint64_t _heapCommit; + bool _noDefaultLibAll; + uint32_t _sectionDefaultAlignment; + WindowsSubsystem _subsystem; + MachineTypes _machineType; + Version _imageVersion; + Version _minOSVersion; + bool _nxCompat; + bool _largeAddressAware; + bool _allowBind; + bool _allowIsolation; + bool _swapRunFromCD; + bool _swapRunFromNet; + bool _baseRelocationEnabled; + bool _terminalServerAware; + bool _dynamicBaseEnabled; + bool _createManifest; + std::string _manifestOutputPath; + bool _embedManifest; + int _manifestId; + bool _manifestUAC; + std::string _manifestLevel; + std::string _manifestUiAccess; + std::string _manifestDependency; + bool _isDll; + bool _highEntropyVA; + + // True if /SAFESEH option is specified. Valid only for x86. If true, LLD will + // produce an image with SEH table. If any modules were not compatible with + // SEH, LLD will exit with an error. + bool _requireSEH; + + // True if /SAFESEH:no option is specified. Valid only for x86. If true, LLD + // will not produce an image with SEH table even if all input object files are + // compatible with SEH. + bool _noSEH; + + // /IMPLIB command line option. + std::string _implib; + + // True if /DEBUG is given. + bool _debug; + + // PDB file output path. NB: this is dummy -- LLD just creates the empty file. + std::string _pdbFilePath; + + // /DELAYLOAD option. + std::set _delayLoadDLLs; + + // The set to store /nodefaultlib arguments. + std::set _noDefaultLibs; + + std::vector _inputSearchPaths; + std::unique_ptr _writer; + + // A map for weak aliases. + std::map> _alternateNames; + + // A map for section renaming. For example, if there is an entry in the map + // whose value is .rdata -> .text, the section contens of .rdata will be + // merged to .text in the resulting executable. + std::map _renamedSections; + + // Section attributes specified by /section option. + std::map _sectionSetMask; + std::map _sectionClearMask; + + // DLLExport'ed symbols. + std::vector _dllExports; + + // List of files that will be removed on destruction. + std::vector > _tempFiles; + + // DOS Stub. DOS stub is data located at the beginning of PE/COFF file. + // Windows loader do not really care about DOS stub contents, but it's usually + // a small DOS program that prints out a message "This program requires + // Microsoft Windows." This feature was somewhat useful before Windows 95. + ArrayRef _dosStub; + + // Name of the temporary file for lib.exe subcommand. For debugging + // only. + std::string _moduleDefinitionFile; + + std::set _definedSyms; + std::set _seen; + + ParseDirectives _parseDirectives; +}; + +} // end namespace lld + +#endif diff --git a/include/lld/ReaderWriter/RelocationHelperFunctions.h b/include/lld/ReaderWriter/RelocationHelperFunctions.h new file mode 100644 index 000000000000..8738e91ebabc --- /dev/null +++ b/include/lld/ReaderWriter/RelocationHelperFunctions.h @@ -0,0 +1,57 @@ +//===- lld/ReaderWriter/RelocationHelperFunctions.h------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H +#define LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H + +namespace lld { + +/// Gather val's bits as specified by the mask. Example: +/// +/// Val: 0bABCDEFGHIJKLMN +/// Mask: 0b10111100001011 +/// Output: 0b000000ACDEFKMN +template T gatherBits(T val, T mask) { + T result = 0; + size_t off = 0; + + for (size_t bit = 0; bit < sizeof(T) * 8; ++bit) { + bool maskBit = (mask >> bit) & 1; + if (maskBit) { + bool valBit = (val >> bit) & 1; + result |= static_cast(valBit) << off; + ++off; + } + } + return result; +} + +/// Scatter val's bits as specified by the mask. Example: +/// +/// Val: 0bABCDEFG +/// Mask: 0b10111100001011 +/// Output: 0b00ABCD0000E0FG +template T scatterBits(T val, T mask) { + T result = 0; + size_t off = 0; + + for (size_t bit = 0; bit < sizeof(T) * 8; ++bit) { + bool maskBit = (mask >> bit) & 1; + if (maskBit) { + bool valBit = (val >> off) & 1; + result |= static_cast(valBit) << bit; + ++off; + } + } + return result; +} + +} // namespace lld + +#endif // LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h new file mode 100644 index 000000000000..a15a398ec636 --- /dev/null +++ b/include/lld/ReaderWriter/YamlContext.h @@ -0,0 +1,46 @@ +//===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_YAML_CONTEXT_H +#define LLD_READER_WRITER_YAML_CONTEXT_H + +#include "lld/Core/LLVM.h" +#include +#include +#include + +namespace lld { +class File; +class LinkingContext; +namespace mach_o { +namespace normalized { +struct NormalizedFile; +} +} + +using lld::mach_o::normalized::NormalizedFile; + +/// When YAML I/O is used in lld, the yaml context always holds a YamlContext +/// object. We need to support hetergenous yaml documents which each require +/// different context info. This struct supports all clients. +struct YamlContext { + YamlContext() + : _linkingContext(nullptr), _registry(nullptr), _file(nullptr), + _normalizeMachOFile(nullptr) {} + + const LinkingContext *_linkingContext; + const Registry *_registry; + File *_file; + NormalizedFile *_normalizeMachOFile; + StringRef _path; +}; + +} // end namespace lld + +#endif // LLD_READER_WRITER_YAML_CONTEXT_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 000000000000..699f5e93f8af --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(Config) +add_subdirectory(Core) +add_subdirectory(Driver) +add_subdirectory(ReaderWriter) diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt new file mode 100644 index 000000000000..f7ea0423b2c9 --- /dev/null +++ b/lib/Config/CMakeLists.txt @@ -0,0 +1,5 @@ +add_llvm_library(lldConfig + Version.cpp + LINK_LIBS + LLVMSupport + ) diff --git a/lib/Config/Makefile b/lib/Config/Makefile new file mode 100644 index 000000000000..b3c57f81418f --- /dev/null +++ b/lib/Config/Makefile @@ -0,0 +1,13 @@ +##===- lib/Config/Makefile ---------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLD_LEVEL := ../.. +LIBRARYNAME := lldConfig + +include $(LLD_LEVEL)/Makefile diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp new file mode 100644 index 000000000000..b64ccef12c7b --- /dev/null +++ b/lib/Config/Version.cpp @@ -0,0 +1,66 @@ +//===- lib/Config/Version.cpp - LLD Version Number ---------------*- C++-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines several version-related utility functions for LLD. +// +//===----------------------------------------------------------------------===// + +#include "lld/Config/Version.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +using namespace llvm; + +namespace lld { + +StringRef getLLDRepositoryPath() { +#ifdef LLD_REPOSITORY_STRING + return LLD_REPOSITORY_STRING; +#else + return ""; +#endif +} + +StringRef getLLDRevision() { +#ifdef LLD_REVISION_STRING + return LLD_REVISION_STRING; +#else + return ""; +#endif +} + +std::string getLLDRepositoryVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); + std::string Path = getLLDRepositoryPath(); + std::string Revision = getLLDRevision(); + if (!Path.empty() || !Revision.empty()) { + OS << '('; + if (!Path.empty()) + OS << Path; + if (!Revision.empty()) { + if (!Path.empty()) + OS << ' '; + OS << Revision; + } + OS << ')'; + } + return OS.str(); +} + +StringRef getLLDVersion() { +#ifdef LLD_VERSION_STRING + return LLD_VERSION_STRING; +#else + return ""; +#endif +} + +} // end namespace lld diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt new file mode 100644 index 000000000000..009b50a38335 --- /dev/null +++ b/lib/Core/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library(lldCore + DefinedAtom.cpp + Error.cpp + File.cpp + LinkingContext.cpp + Reader.cpp + Resolver.cpp + SymbolTable.cpp + Writer.cpp + LINK_LIBS + LLVMSupport + ) diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp new file mode 100644 index 000000000000..b3f81ca65a91 --- /dev/null +++ b/lib/Core/DefinedAtom.cpp @@ -0,0 +1,96 @@ +//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ErrorHandling.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" + +namespace lld { + +DefinedAtom::ContentPermissions DefinedAtom::permissions() const { + // By default base permissions on content type. + return permissions(this->contentType()); +} + +// Utility function for deriving permissions from content type +DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { + switch (type) { + case typeCode: + case typeResolver: + case typeBranchIsland: + case typeBranchShim: + case typeStub: + case typeStubHelper: + case typeMachHeader: + return permR_X; + + case typeConstant: + case typeCString: + case typeUTF16String: + case typeCFI: + case typeLSDA: + case typeLiteral4: + case typeLiteral8: + case typeLiteral16: + case typeDTraceDOF: + case typeCompactUnwindInfo: + case typeProcessedUnwindInfo: + case typeRONote: + case typeNoAlloc: + return permR__; + + case typeData: + case typeDataFast: + case typeZeroFill: + case typeZeroFillFast: + case typeObjC1Class: + case typeLazyPointer: + case typeLazyDylibPointer: + case typeThunkTLV: + case typeRWNote: + return permRW_; + + case typeGOT: + case typeConstData: + case typeCFString: + case typeInitializerPtr: + case typeTerminatorPtr: + case typeCStringPtr: + case typeObjCClassPtr: + case typeObjC2CategoryList: + case typeInterposingTuples: + case typeTLVInitialData: + case typeTLVInitialZeroFill: + case typeTLVInitializerPtr: + case typeThreadData: + case typeThreadZeroFill: + return permRW_L; + + case typeGroupComdat: + case typeGnuLinkOnce: + case typeUnknown: + case typeTempLTO: + return permUnknown; + } + llvm_unreachable("unknown content type"); +} + +bool DefinedAtom::compareByPosition(const DefinedAtom *lhs, + const DefinedAtom *rhs) { + if (lhs == rhs) + return false; + const File *lhsFile = &lhs->file(); + const File *rhsFile = &rhs->file(); + if (lhsFile->ordinal() != rhsFile->ordinal()) + return lhsFile->ordinal() < rhsFile->ordinal(); + assert(lhs->ordinal() != rhs->ordinal()); + return lhs->ordinal() < rhs->ordinal(); +} + +} // namespace diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp new file mode 100644 index 000000000000..24809c3869e5 --- /dev/null +++ b/lib/Core/Error.cpp @@ -0,0 +1,151 @@ +//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include + +using namespace lld; + +class _NativeReaderErrorCategory : public std::error_category { +public: + const char* name() const LLVM_NOEXCEPT override { + return "lld.native.reader"; + } + + std::string message(int ev) const override { + switch (static_cast(ev)) { + case NativeReaderError::success: + return "Success"; + case NativeReaderError::unknown_file_format: + return "Unknown file format"; + case NativeReaderError::file_too_short: + return "file truncated"; + case NativeReaderError::file_malformed: + return "file malformed"; + case NativeReaderError::memory_error: + return "out of memory"; + case NativeReaderError::unknown_chunk_type: + return "unknown chunk type"; + case NativeReaderError::conflicting_target_machine: + return "conflicting target machine"; + } + llvm_unreachable("An enumerator of NativeReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::native_reader_category() { + static _NativeReaderErrorCategory o; + return o; +} + +class _YamlReaderErrorCategory : public std::error_category { +public: + const char* name() const LLVM_NOEXCEPT override { + return "lld.yaml.reader"; + } + + std::string message(int ev) const override { + switch (static_cast(ev)) { + case YamlReaderError::success: + return "Success"; + case YamlReaderError::unknown_keyword: + return "Unknown keyword found in yaml file"; + case YamlReaderError::illegal_value: + return "Bad value found in yaml file"; + } + llvm_unreachable("An enumerator of YamlReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::YamlReaderCategory() { + static _YamlReaderErrorCategory o; + return o; +} + +class _LinkerScriptReaderErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { + return "lld.linker-script.reader"; + } + + std::string message(int ev) const override { + switch (static_cast(ev)) { + case LinkerScriptReaderError::success: + return "Success"; + case LinkerScriptReaderError::parse_error: + return "Error parsing linker script"; + case LinkerScriptReaderError::unknown_symbol_in_expr: + return "Unknown symbol found when evaluating linker script expression"; + case LinkerScriptReaderError::unrecognized_function_in_expr: + return "Unrecognized function call when evaluating linker script " + "expression"; + } + llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::LinkerScriptReaderCategory() { + static _LinkerScriptReaderErrorCategory o; + return o; +} + + +namespace lld { + +/// Temporary class to enable make_dynamic_error_code() until +/// llvm::ErrorOr<> is updated to work with error encapsulations +/// other than error_code. +class dynamic_error_category : public std::error_category { +public: + ~dynamic_error_category() LLVM_NOEXCEPT {} + + const char *name() const LLVM_NOEXCEPT override { + return "lld.dynamic_error"; + } + + std::string message(int ev) const override { + assert(ev >= 0); + assert(ev < (int)_messages.size()); + // The value is an index into the string vector. + return _messages[ev]; + } + + int add(std::string msg) { + std::lock_guard lock(_mutex); + // Value zero is always the successs value. + if (_messages.empty()) + _messages.push_back("Success"); + _messages.push_back(msg); + // Return the index of the string just appended. + return _messages.size() - 1; + } + +private: + std::vector _messages; + std::recursive_mutex _mutex; +}; + +static dynamic_error_category categorySingleton; + +std::error_code make_dynamic_error_code(StringRef msg) { + return std::error_code(categorySingleton.add(msg), categorySingleton); +} + +std::error_code make_dynamic_error_code(const Twine &msg) { + return std::error_code(categorySingleton.add(msg.str()), categorySingleton); +} + +} diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp new file mode 100644 index 000000000000..dbac86b368aa --- /dev/null +++ b/lib/Core/File.cpp @@ -0,0 +1,30 @@ +//===- Core/File.cpp - A Container of Atoms -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include + +namespace lld { + +File::~File() {} + +File::atom_collection_empty File::_noDefinedAtoms; +File::atom_collection_empty File::_noUndefinedAtoms; +File::atom_collection_empty File::_noSharedLibraryAtoms; +File::atom_collection_empty File::_noAbsoluteAtoms; + +std::error_code File::parse() { + std::lock_guard lock(_parseMutex); + if (!_lastError.hasValue()) + _lastError = doParse(); + return _lastError.getValue(); +} + +} // namespace lld diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp new file mode 100644 index 000000000000..c6656b935916 --- /dev/null +++ b/lib/Core/LinkingContext.cpp @@ -0,0 +1,104 @@ +//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Alias.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/Simple.h" +#include "lld/Core/Writer.h" +#include "llvm/ADT/Triple.h" + +namespace lld { + +LinkingContext::LinkingContext() + : _deadStrip(false), _allowDuplicates(false), + _globalsAreDeadStripRoots(false), + _searchArchivesToOverrideTentativeDefinitions(false), + _searchSharedLibrariesToOverrideTentativeDefinitions(false), + _warnIfCoalesableAtomsHaveDifferentCanBeNull(false), + _warnIfCoalesableAtomsHaveDifferentLoadName(false), + _printRemainingUndefines(true), _allowRemainingUndefines(false), + _logInputFiles(false), _allowShlibUndefines(false), + _outputFileType(OutputFileType::Default), _nextOrdinal(0) {} + +LinkingContext::~LinkingContext() {} + +bool LinkingContext::validate(raw_ostream &diagnostics) { + return validateImpl(diagnostics); +} + +std::error_code LinkingContext::writeFile(const File &linkedFile) const { + return this->writer().writeFile(linkedFile, _outputPath); +} + +bool LinkingContext::createImplicitFiles( + std::vector > &result) { + return this->writer().createImplicitFiles(result); +} + +std::unique_ptr LinkingContext::createEntrySymbolFile() const { + return createEntrySymbolFile(""); +} + +std::unique_ptr +LinkingContext::createEntrySymbolFile(StringRef filename) const { + if (entrySymbolName().empty()) + return nullptr; + std::unique_ptr entryFile(new SimpleFile(filename)); + entryFile->addAtom( + *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); + return std::move(entryFile); +} + +std::unique_ptr LinkingContext::createUndefinedSymbolFile() const { + return createUndefinedSymbolFile(""); +} + +std::unique_ptr +LinkingContext::createUndefinedSymbolFile(StringRef filename) const { + if (_initialUndefinedSymbols.empty()) + return nullptr; + std::unique_ptr undefinedSymFile(new SimpleFile(filename)); + for (StringRef undefSym : _initialUndefinedSymbols) + undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( + *undefinedSymFile, undefSym))); + return std::move(undefinedSymFile); +} + +std::unique_ptr LinkingContext::createAliasSymbolFile() const { + if (getAliases().empty()) + return nullptr; + std::unique_ptr file(new SimpleFile("")); + for (const auto &i : getAliases()) { + StringRef from = i.first; + StringRef to = i.second; + SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from); + UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to); + fromAtom->addReference(Reference::KindNamespace::all, + Reference::KindArch::all, Reference::kindLayoutAfter, + 0, toAtom, 0); + file->addAtom(*fromAtom); + file->addAtom(*toAtom); + } + return std::move(file); +} + +void LinkingContext::createInternalFiles( + std::vector > &result) const { + if (std::unique_ptr file = createEntrySymbolFile()) + result.push_back(std::move(file)); + if (std::unique_ptr file = createUndefinedSymbolFile()) + result.push_back(std::move(file)); + if (std::unique_ptr file = createAliasSymbolFile()) + result.push_back(std::move(file)); +} + +void LinkingContext::addPasses(PassManager &pm) {} + +} // end namespace lld diff --git a/lib/Core/Makefile b/lib/Core/Makefile new file mode 100644 index 000000000000..042d01a1e1b3 --- /dev/null +++ b/lib/Core/Makefile @@ -0,0 +1,13 @@ +##===- lld/lib/Core/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLD_LEVEL := ../.. +LIBRARYNAME := lldCore + +include $(LLD_LEVEL)/Makefile diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp new file mode 100644 index 000000000000..6f8b8cbd1bf8 --- /dev/null +++ b/lib/Core/Reader.cpp @@ -0,0 +1,117 @@ +//===- lib/Core/Reader.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/Reader.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include +#include + +namespace lld { + +YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {} + +void Registry::add(std::unique_ptr reader) { + _readers.push_back(std::move(reader)); +} + +void Registry::add(std::unique_ptr handler) { + _yamlHandlers.push_back(std::move(handler)); +} + +std::error_code +Registry::loadFile(std::unique_ptr mb, + std::vector> &result) const { + // Get file type. + StringRef content(mb->getBufferStart(), mb->getBufferSize()); + llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content); + // Get file extension. + StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier()); + + // Ask each registered reader if it can handle this file type or extension. + for (const std::unique_ptr &reader : _readers) { + if (!reader->canParse(fileType, extension, *mb)) + continue; + if (std::error_code ec = reader->loadFile(std::move(mb), *this, result)) + return ec; + return std::error_code(); + } + + // No Reader could parse this file. + return make_error_code(llvm::errc::executable_format_error); +} + +static const Registry::KindStrings kindStrings[] = { + {Reference::kindLayoutAfter, "layout-after"}, + {Reference::kindGroupChild, "group-child"}, + {Reference::kindAssociate, "associate"}, + LLD_KIND_STRING_END}; + +Registry::Registry() { + addKindTable(Reference::KindNamespace::all, Reference::KindArch::all, + kindStrings); +} + +bool Registry::handleTaggedDoc(llvm::yaml::IO &io, + const lld::File *&file) const { + for (const std::unique_ptr &h : _yamlHandlers) + if (h->handledDocTag(io, file)) + return true; + return false; +} + + +void Registry::addKindTable(Reference::KindNamespace ns, + Reference::KindArch arch, + const KindStrings array[]) { + KindEntry entry = { ns, arch, array }; + _kindEntries.push_back(entry); +} + +bool Registry::referenceKindFromString(StringRef inputStr, + Reference::KindNamespace &ns, + Reference::KindArch &arch, + Reference::KindValue &value) const { + for (const KindEntry &entry : _kindEntries) { + for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { + if (!inputStr.equals(pair->name)) + continue; + ns = entry.ns; + arch = entry.arch; + value = pair->value; + return true; + } + } + return false; +} + +bool Registry::referenceKindToString(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue value, + StringRef &str) const { + for (const KindEntry &entry : _kindEntries) { + if (entry.ns != ns) + continue; + if (entry.arch != arch) + continue; + for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { + if (pair->value != value) + continue; + str = pair->name; + return true; + } + } + return false; +} + +} // end namespace lld diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp new file mode 100644 index 000000000000..393a7ef2bfc8 --- /dev/null +++ b/lib/Core/Resolver.cpp @@ -0,0 +1,516 @@ +//===- Core/Resolver.cpp - Resolves Atom References -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Atom.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/SymbolTable.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +namespace lld { + +bool Resolver::handleFile(File &file) { + bool undefAdded = false; + for (const DefinedAtom *atom : file.defined()) + doDefinedAtom(*atom); + for (const UndefinedAtom *atom : file.undefined()) { + if (doUndefinedAtom(*atom)) { + undefAdded = true; + maybePreloadArchiveMember(atom->name()); + } + } + for (const SharedLibraryAtom *atom : file.sharedLibrary()) + doSharedLibraryAtom(*atom); + for (const AbsoluteAtom *atom : file.absolute()) + doAbsoluteAtom(*atom); + return undefAdded; +} + +void Resolver::forEachUndefines(File &file, bool searchForOverrides, + UndefCallback callback) { + size_t i = _undefineIndex[&file]; + do { + for (; i < _undefines.size(); ++i) { + StringRef undefName = _undefines[i]; + if (undefName.empty()) + continue; + const Atom *atom = _symbolTable.findByName(undefName); + if (!isa(atom) || _symbolTable.isCoalescedAway(atom)) { + // The symbol was resolved by some other file. Cache the result. + _undefines[i] = ""; + continue; + } + callback(undefName, false); + } + if (!searchForOverrides) + continue; + for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) { + // Load for previous tentative may also have loaded + // something that overrode this tentative, so always check. + const Atom *curAtom = _symbolTable.findByName(tentDefName); + assert(curAtom != nullptr); + if (const DefinedAtom *curDefAtom = dyn_cast(curAtom)) + if (curDefAtom->merge() == DefinedAtom::mergeAsTentative) + callback(tentDefName, true); + } + } while (i < _undefines.size()); + _undefineIndex[&file] = i; +} + +bool Resolver::handleArchiveFile(File &file) { + ArchiveLibraryFile *archiveFile = cast(&file); + bool searchForOverrides = + _ctx.searchArchivesToOverrideTentativeDefinitions(); + bool undefAdded = false; + forEachUndefines(file, searchForOverrides, + [&](StringRef undefName, bool dataSymbolOnly) { + if (File *member = archiveFile->find(undefName, dataSymbolOnly)) { + member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + member->beforeLink(); + updatePreloadArchiveMap(); + undefAdded = handleFile(*member) || undefAdded; + } + }); + return undefAdded; +} + +void Resolver::handleSharedLibrary(File &file) { + // Add all the atoms from the shared library + SharedLibraryFile *sharedLibrary = cast(&file); + handleFile(*sharedLibrary); + bool searchForOverrides = + _ctx.searchSharedLibrariesToOverrideTentativeDefinitions(); + forEachUndefines(file, searchForOverrides, + [&](StringRef undefName, bool dataSymbolOnly) { + if (const SharedLibraryAtom *atom = + sharedLibrary->exports(undefName, dataSymbolOnly)) + doSharedLibraryAtom(*atom); + }); +} + +bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " UndefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" << atom.name() << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + bool newUndefAdded = _symbolTable.add(atom); + if (newUndefAdded) + _undefines.push_back(atom.name()); + + // If the undefined symbol has an alternative name, try to resolve the + // symbol with the name to give it a second chance. This feature is used + // for COFF "weak external" symbol. + if (newUndefAdded || !_symbolTable.isDefined(atom.name())) { + if (const UndefinedAtom *fallbackAtom = atom.fallback()) { + doUndefinedAtom(*fallbackAtom); + _symbolTable.addReplacement(&atom, fallbackAtom); + } + } + return newUndefAdded; +} + +/// \brief Add the section group and the group-child reference members. +void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) { + // First time adding a group? + bool isFirstTime = _symbolTable.addGroup(atom); + + if (!isFirstTime) { + // If duplicate symbols are allowed, select the first group. + if (_ctx.getAllowDuplicates()) + return; + auto *prevGroup = dyn_cast(_symbolTable.findGroup(atom.name())); + assert(prevGroup && + "Internal Error: The group atom could only be a defined atom"); + // The atoms should be of the same content type, reject invalid group + // resolution behaviors. + if (atom.contentType() == prevGroup->contentType()) + return; + llvm::errs() << "SymbolTable: error while merging " << atom.name() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + return; + } + + for (const Reference *r : atom) { + if (r->kindNamespace() == lld::Reference::KindNamespace::all && + r->kindValue() == lld::Reference::kindGroupChild) { + const DefinedAtom *target = dyn_cast(r->target()); + assert(target && "Internal Error: kindGroupChild references need to " + "be associated with Defined Atoms only"); + _atoms.push_back(target); + _symbolTable.add(*target); + } + } +} + +// Called on each atom when a file is added. Returns true if a given +// atom is added to the symbol table. +void Resolver::doDefinedAtom(const DefinedAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " DefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", file=#" + << atom.file().ordinal() + << ", atom=#" + << atom.ordinal() + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + if (atom.isGroupParent()) { + maybeAddSectionGroupOrGnuLinkOnce(atom); + } else { + _symbolTable.add(atom); + } + + // An atom that should never be dead-stripped is a dead-strip root. + if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(&atom); + } +} + +void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " SharedLibraryAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + _symbolTable.add(atom); +} + +void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " AbsoluteAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + if (atom.scope() != Atom::scopeTranslationUnit) + _symbolTable.add(atom); +} + +// utility to add a vector of atoms +void Resolver::addAtoms(const std::vector &newAtoms) { + for (const DefinedAtom *newAtom : newAtoms) + doDefinedAtom(*newAtom); +} + +// Instantiate an archive file member if there's a file containing a +// defined symbol for a given symbol name. Instantiation is done in a +// different worker thread and has no visible side effect. +void Resolver::maybePreloadArchiveMember(StringRef sym) { + auto it = _archiveMap.find(sym); + if (it == _archiveMap.end()) + return; + ArchiveLibraryFile *archive = it->second; + archive->preload(_ctx.getTaskGroup(), sym); +} + +// Returns true if at least one of N previous files has created an +// undefined symbol. +bool Resolver::undefinesAdded(int begin, int end) { + std::vector> &inputs = _ctx.getNodes(); + for (int i = begin; i < end; ++i) + if (FileNode *node = dyn_cast(inputs[i].get())) + if (_newUndefinesAdded[node->getFile()]) + return true; + return false; +} + +File *Resolver::getFile(int &index) { + std::vector> &inputs = _ctx.getNodes(); + if ((size_t)index >= inputs.size()) + return nullptr; + if (GroupEnd *group = dyn_cast(inputs[index].get())) { + // We are at the end of the current group. If one or more new + // undefined atom has been added in the last groupSize files, we + // reiterate over the files. + int size = group->getSize(); + if (undefinesAdded(index - size, index)) { + index -= size; + return getFile(index); + } + ++index; + return getFile(index); + } + return cast(inputs[index++].get())->getFile(); +} + +// Update a map of Symbol -> ArchiveFile. The map is used for speculative +// file loading. +void Resolver::updatePreloadArchiveMap() { + std::vector> &nodes = _ctx.getNodes(); + for (int i = nodes.size() - 1; i >= 0; --i) { + auto *fnode = dyn_cast(nodes[i].get()); + if (!fnode) + continue; + auto *archive = dyn_cast(fnode->getFile()); + if (!archive || _archiveSeen.count(archive)) + continue; + _archiveSeen.insert(archive); + for (StringRef sym : archive->getDefinedSymbols()) + _archiveMap[sym] = archive; + } +} + +// Keep adding atoms until _ctx.getNextFile() returns an error. This +// function is where undefined atoms are resolved. +bool Resolver::resolveUndefines() { + ScopedTask task(getDefaultDomain(), "resolveUndefines"); + int index = 0; + std::set seen; + for (;;) { + bool undefAdded = false; + File *file = getFile(index); + if (!file) + return true; + if (std::error_code ec = file->parse()) { + llvm::errs() << "Cannot open " + file->path() + << ": " << ec.message() << "\n"; + return false; + } + file->beforeLink(); + updatePreloadArchiveMap(); + switch (file->kind()) { + case File::kindObject: + // The same file may be visited more than once if the file is + // in --start-group and --end-group. Only library files should + // be processed more than once. + if (seen.count(file)) + break; + seen.insert(file); + assert(!file->hasOrdinal()); + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + undefAdded = handleFile(*file); + break; + case File::kindArchiveLibrary: + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + undefAdded = handleArchiveFile(*file); + break; + case File::kindSharedLibrary: + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + handleSharedLibrary(*file); + break; + } + _newUndefinesAdded[file] = undefAdded; + } +} + +// switch all references to undefined or coalesced away atoms +// to the new defined atom +void Resolver::updateReferences() { + ScopedTask task(getDefaultDomain(), "updateReferences"); + for (const Atom *atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom)) { + for (const Reference *ref : *defAtom) { + // A reference of type kindAssociate should't be updated. + // Instead, an atom having such reference will be removed + // if the target atom is coalesced away, so that they will + // go away as a group. + if (ref->kindNamespace() == lld::Reference::KindNamespace::all && + ref->kindValue() == lld::Reference::kindAssociate) { + if (_symbolTable.isCoalescedAway(atom)) + _deadAtoms.insert(ref->target()); + continue; + } + const Atom *newTarget = _symbolTable.replacement(ref->target()); + const_cast(ref)->setTarget(newTarget); + } + } + } +} + +// For dead code stripping, recursively mark atoms "live" +void Resolver::markLive(const Atom *atom) { + // Mark the atom is live. If it's already marked live, then stop recursion. + auto exists = _liveAtoms.insert(atom); + if (!exists.second) + return; + + // Mark all atoms it references as live + if (const DefinedAtom *defAtom = dyn_cast(atom)) { + for (const Reference *ref : *defAtom) + markLive(ref->target()); + for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) { + const Atom *target = p.second; + markLive(target); + } + } +} + +static bool isBackref(const Reference *ref) { + if (ref->kindNamespace() != lld::Reference::KindNamespace::all) + return false; + return (ref->kindValue() == lld::Reference::kindLayoutAfter || + ref->kindValue() == lld::Reference::kindGroupChild); +} + +// remove all atoms not actually used +void Resolver::deadStripOptimize() { + ScopedTask task(getDefaultDomain(), "deadStripOptimize"); + // only do this optimization with -dead_strip + if (!_ctx.deadStrip()) + return; + + // Some type of references prevent referring atoms to be dead-striped. + // Make a reverse map of such references before traversing the graph. + // While traversing the list of atoms, mark AbsoluteAtoms as live + // in order to avoid reclaim. + for (const Atom *atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom)) + for (const Reference *ref : *defAtom) + if (isBackref(ref)) + _reverseRef.insert(std::make_pair(ref->target(), atom)); + if (const AbsoluteAtom *absAtom = dyn_cast(atom)) + markLive(absAtom); + } + + // By default, shared libraries are built with all globals as dead strip roots + if (_ctx.globalsAreDeadStripRoots()) + for (const Atom *atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast(atom)) + if (defAtom->scope() == DefinedAtom::scopeGlobal) + _deadStripRoots.insert(defAtom); + + // Or, use list of names that are dead strip roots. + for (const StringRef &name : _ctx.deadStripRoots()) { + const Atom *symAtom = _symbolTable.findByName(name); + assert(symAtom); + _deadStripRoots.insert(symAtom); + } + + // mark all roots as live, and recursively all atoms they reference + for (const Atom *dsrAtom : _deadStripRoots) + markLive(dsrAtom); + + // now remove all non-live atoms from _atoms + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { + return _liveAtoms.count(a) == 0; + }), + _atoms.end()); +} + +// error out if some undefines remain +bool Resolver::checkUndefines() { + // build vector of remaining undefined symbols + std::vector undefinedAtoms = _symbolTable.undefines(); + if (_ctx.deadStrip()) { + // When dead code stripping, we don't care if dead atoms are undefined. + undefinedAtoms.erase( + std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(), + [&](const Atom *a) { return _liveAtoms.count(a) == 0; }), + undefinedAtoms.end()); + } + + if (undefinedAtoms.empty()) + return false; + + // Warn about unresolved symbols. + bool foundUndefines = false; + for (const UndefinedAtom *undef : undefinedAtoms) { + // Skip over a weak symbol. + if (undef->canBeNull() != UndefinedAtom::canBeNullNever) + continue; + + // If this is a library and undefined symbols are allowed on the + // target platform, skip over it. + if (isa(undef->file()) && _ctx.allowShlibUndefines()) + continue; + + // If the undefine is coalesced away, skip over it. + if (_symbolTable.isCoalescedAway(undef)) + continue; + + // Seems like this symbol is undefined. Warn that. + foundUndefines = true; + if (_ctx.printRemainingUndefines()) { + llvm::errs() << "Undefined symbol: " << undef->file().path() + << ": " << _ctx.demangle(undef->name()) + << "\n"; + } + } + if (!foundUndefines) + return false; + if (_ctx.printRemainingUndefines()) + llvm::errs() << "symbol(s) not found\n"; + return true; +} + +// remove from _atoms all coaleseced away atoms +void Resolver::removeCoalescedAwayAtoms() { + ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { + return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); + }), + _atoms.end()); +} + +bool Resolver::resolve() { + updatePreloadArchiveMap(); + if (!resolveUndefines()) + return false; + updateReferences(); + deadStripOptimize(); + if (checkUndefines()) + if (!_ctx.allowRemainingUndefines()) + return false; + removeCoalescedAwayAtoms(); + _result->addAtoms(_atoms); + return true; +} + +void Resolver::MergedFile::addAtoms(std::vector &all) { + ScopedTask task(getDefaultDomain(), "addAtoms"); + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); + for (const Atom *atom : all) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << llvm::format(" 0x%09lX", atom) + << ", name=" + << atom->name() + << "\n"); + addAtom(*atom); + } +} + +} // namespace lld diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp new file mode 100644 index 000000000000..f3f2da9262e0 --- /dev/null +++ b/lib/Core/SymbolTable.cpp @@ -0,0 +1,390 @@ +//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/SymbolTable.h" +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/Atom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +namespace lld { +SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {} + +bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const DefinedAtom &atom) { + if (!atom.name().empty() && + atom.scope() != DefinedAtom::scopeTranslationUnit) { + // Named atoms cannot be merged by content. + assert(atom.merge() != DefinedAtom::mergeByContent); + // Track named atoms that are not scoped to file (static). + return addByName(atom); + } + if (atom.merge() == DefinedAtom::mergeByContent) { + // Named atoms cannot be merged by content. + assert(atom.name().empty()); + // Currently only read-only constants can be merged. + if (atom.permissions() == DefinedAtom::permR__) + return addByContent(atom); + // TODO: support mergeByContent of data atoms by comparing content & fixups. + } + return false; +} + +const Atom *SymbolTable::findGroup(StringRef sym) { + NameToAtom::iterator pos = _groupTable.find(sym); + if (pos == _groupTable.end()) + return nullptr; + return pos->second; +} + +bool SymbolTable::addGroup(const DefinedAtom &da) { + StringRef name = da.name(); + assert(!name.empty()); + const Atom *existing = findGroup(name); + if (existing == nullptr) { + _groupTable[name] = &da; + return true; + } + _replacedAtoms[&da] = existing; + return false; +} + +enum NameCollisionResolution { + NCR_First, + NCR_Second, + NCR_DupDef, + NCR_DupUndef, + NCR_DupShLib, + NCR_Error +}; + +static NameCollisionResolution cases[4][4] = { + //regular absolute undef sharedLib + { + // first is regular + NCR_DupDef, NCR_Error, NCR_First, NCR_First + }, + { + // first is absolute + NCR_Error, NCR_Error, NCR_First, NCR_First + }, + { + // first is undef + NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second + }, + { + // first is sharedLib + NCR_Second, NCR_Second, NCR_First, NCR_DupShLib + } +}; + +static NameCollisionResolution collide(Atom::Definition first, + Atom::Definition second) { + return cases[first][second]; +} + +enum MergeResolution { + MCR_First, + MCR_Second, + MCR_Largest, + MCR_SameSize, + MCR_Error +}; + +static MergeResolution mergeCases[][6] = { + // no tentative weak weakAddress sameNameAndSize largest + {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no + {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative + {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak + {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress + {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize + {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest +}; + +static MergeResolution mergeSelect(DefinedAtom::Merge first, + DefinedAtom::Merge second) { + assert(first != DefinedAtom::mergeByContent); + assert(second != DefinedAtom::mergeByContent); + return mergeCases[first][second]; +} + +bool SymbolTable::addByName(const Atom &newAtom) { + StringRef name = newAtom.name(); + assert(!name.empty()); + const Atom *existing = findByName(name); + if (existing == nullptr) { + // Name is not in symbol table yet, add it associate with this atom. + _nameTable[name] = &newAtom; + return true; + } + + // Do nothing if the same object is added more than once. + if (existing == &newAtom) + return false; + + // Name is already in symbol table and associated with another atom. + bool useNew = true; + switch (collide(existing->definition(), newAtom.definition())) { + case NCR_First: + useNew = false; + break; + case NCR_Second: + useNew = true; + break; + case NCR_DupDef: { + const auto *existingDef = cast(existing); + const auto *newDef = cast(&newAtom); + switch (mergeSelect(existingDef->merge(), newDef->merge())) { + case MCR_First: + useNew = false; + break; + case MCR_Second: + useNew = true; + break; + case MCR_Largest: { + uint64_t existingSize = existingDef->sectionSize(); + uint64_t newSize = newDef->sectionSize(); + useNew = (newSize >= existingSize); + break; + } + case MCR_SameSize: { + uint64_t existingSize = existingDef->sectionSize(); + uint64_t newSize = newDef->sectionSize(); + if (existingSize == newSize) { + useNew = true; + break; + } + llvm::errs() << "Size mismatch: " + << existing->name() << " (" << existingSize << ") " + << newAtom.name() << " (" << newSize << ")\n"; + // fallthrough + } + case MCR_Error: + if (!_context.getAllowDuplicates()) { + llvm::errs() << "Duplicate symbols: " + << existing->name() + << ":" + << existing->file().path() + << " and " + << newAtom.name() + << ":" + << newAtom.file().path() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + } + useNew = false; + break; + } + break; + } + case NCR_DupUndef: { + const UndefinedAtom* existingUndef = cast(existing); + const UndefinedAtom* newUndef = cast(&newAtom); + + bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); + if (!sameCanBeNull && + _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { + llvm::errs() << "lld warning: undefined symbol " + << existingUndef->name() + << " has different weakness in " + << existingUndef->file().path() + << " and in " << newUndef->file().path() << "\n"; + } + + const UndefinedAtom *existingFallback = existingUndef->fallback(); + const UndefinedAtom *newFallback = newUndef->fallback(); + bool hasDifferentFallback = + (existingFallback && newFallback && + existingFallback->name() != newFallback->name()); + if (hasDifferentFallback) { + llvm::errs() << "lld warning: undefined symbol " + << existingUndef->name() << " has different fallback: " + << existingFallback->name() << " in " + << existingUndef->file().path() << " and " + << newFallback->name() << " in " + << newUndef->file().path() << "\n"; + } + + bool hasNewFallback = newUndef->fallback(); + if (sameCanBeNull) + useNew = hasNewFallback; + else + useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); + break; + } + case NCR_DupShLib: { + const SharedLibraryAtom *curShLib = cast(existing); + const SharedLibraryAtom *newShLib = cast(&newAtom); + bool sameNullness = + (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime()); + bool sameName = curShLib->loadName().equals(newShLib->loadName()); + if (sameName && !sameNullness && + _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { + // FIXME: need diagonstics interface for writing warning messages + llvm::errs() << "lld warning: shared library symbol " + << curShLib->name() << " has different weakness in " + << curShLib->file().path() << " and in " + << newShLib->file().path(); + } + if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) { + // FIXME: need diagonstics interface for writing warning messages + llvm::errs() << "lld warning: shared library symbol " + << curShLib->name() << " has different load path in " + << curShLib->file().path() << " and in " + << newShLib->file().path(); + } + useNew = false; + break; + } + case NCR_Error: + llvm::errs() << "SymbolTable: error while merging " << name << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + break; + } + + // Give context a chance to change which is kept. + _context.notifySymbolTableCoalesce(existing, &newAtom, useNew); + + if (useNew) { + // Update name table to use new atom. + _nameTable[name] = &newAtom; + // Add existing atom to replacement table. + _replacedAtoms[existing] = &newAtom; + } else { + // New atom is not being used. Add it to replacement table. + _replacedAtoms[&newAtom] = existing; + } + return false; +} + +unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) { + auto content = atom->rawContent(); + return llvm::hash_combine(atom->size(), + atom->contentType(), + llvm::hash_combine_range(content.begin(), + content.end())); +} + +bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, + const DefinedAtom * const r) { + if (l == r) + return true; + if (l == getEmptyKey()) + return false; + if (r == getEmptyKey()) + return false; + if (l == getTombstoneKey()) + return false; + if (r == getTombstoneKey()) + return false; + if (l->contentType() != r->contentType()) + return false; + if (l->size() != r->size()) + return false; + if (l->sectionChoice() != r->sectionChoice()) + return false; + if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) { + if (!l->customSectionName().equals(r->customSectionName())) + return false; + } + ArrayRef lc = l->rawContent(); + ArrayRef rc = r->rawContent(); + return memcmp(lc.data(), rc.data(), lc.size()) == 0; +} + +bool SymbolTable::addByContent(const DefinedAtom &newAtom) { + AtomContentSet::iterator pos = _contentTable.find(&newAtom); + if (pos == _contentTable.end()) { + _contentTable.insert(&newAtom); + return true; + } + const Atom* existing = *pos; + // New atom is not being used. Add it to replacement table. + _replacedAtoms[&newAtom] = existing; + return false; +} + +const Atom *SymbolTable::findByName(StringRef sym) { + NameToAtom::iterator pos = _nameTable.find(sym); + if (pos == _nameTable.end()) + return nullptr; + return pos->second; +} + +bool SymbolTable::isDefined(StringRef sym) { + if (const Atom *atom = findByName(sym)) + return !isa(atom); + return false; +} + +void SymbolTable::addReplacement(const Atom *replaced, + const Atom *replacement) { + _replacedAtoms[replaced] = replacement; +} + +const Atom *SymbolTable::replacement(const Atom *atom) { + // Find the replacement for a given atom. Atoms in _replacedAtoms + // may be chained, so find the last one. + for (;;) { + AtomToAtom::iterator pos = _replacedAtoms.find(atom); + if (pos == _replacedAtoms.end()) + return atom; + atom = pos->second; + } +} + +bool SymbolTable::isCoalescedAway(const Atom *atom) { + return _replacedAtoms.count(atom) > 0; +} + +std::vector SymbolTable::undefines() { + std::vector ret; + for (auto it : _nameTable) { + const Atom *atom = it.second; + assert(atom != nullptr); + if (const auto *undef = dyn_cast(atom)) + if (_replacedAtoms.count(undef) == 0) + ret.push_back(undef); + } + return ret; +} + +std::vector SymbolTable::tentativeDefinitions() { + std::vector ret; + for (auto entry : _nameTable) { + const Atom *atom = entry.second; + StringRef name = entry.first; + assert(atom != nullptr); + if (const DefinedAtom *defAtom = dyn_cast(atom)) + if (defAtom->merge() == DefinedAtom::mergeAsTentative) + ret.push_back(name); + } + return ret; +} + +} // namespace lld diff --git a/lib/Core/TODO.txt b/lib/Core/TODO.txt new file mode 100644 index 000000000000..196a3e02c2fc --- /dev/null +++ b/lib/Core/TODO.txt @@ -0,0 +1,18 @@ +lib/Core +~~~~~~~~ + +* Add endianness support to the native reader and writer. + +* The NativeReader has lots of similar code for converting arrays of ivar + data in mapped memory into arrays of objects. The commonality can be + factored out, maybe templatized. + +* The NativeFileFormat.h is old school C structs and constants. We scope + things better by defining constants used with a struct inside the struct + declaration. + +* The native reader and writer currently just blast in memory enumeration + values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support + future changes to the enumerations, there should be a translation layer + to map disk values to in-memory values. + diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp new file mode 100644 index 000000000000..39bcc9e68523 --- /dev/null +++ b/lib/Core/Writer.cpp @@ -0,0 +1,23 @@ +//===- lib/Core/Writer.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/Writer.h" + +namespace lld { +Writer::Writer() { +} + +Writer::~Writer() { +} + +bool Writer::createImplicitFiles(std::vector > &) { + return true; +} +} // end namespace lld diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt new file mode 100644 index 000000000000..5a410e7eed7e --- /dev/null +++ b/lib/Driver/CMakeLists.txt @@ -0,0 +1,43 @@ +set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td) +tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs) +set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td) +tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs) +set(LLVM_TARGET_DEFINITIONS CoreOptions.td) +tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs) +set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td) +tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs) +set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td) +tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs) +add_public_tablegen_target(DriverOptionsTableGen) + +add_llvm_library(lldDriver + CoreDriver.cpp + DarwinLdDriver.cpp + Driver.cpp + GnuLdDriver.cpp + UniversalDriver.cpp + WinLinkDriver.cpp + WinLinkModuleDef.cpp + LINK_LIBS + lldConfig + lldMachO + lldPECOFF + lldELF + lldAArch64ELFTarget + lldARMELFTarget + lldHexagonELFTarget + lldMipsELFTarget + lldX86ELFTarget + lldExampleSubTarget + lldX86_64ELFTarget + lldCore + lldNative + lldReaderWriter + lldYAML + LLVMObject + LLVMOption + LLVMSupport + ) + +add_dependencies(lldDriver DriverOptionsTableGen) + diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp new file mode 100644 index 000000000000..b8adee55746f --- /dev/null +++ b/lib/Driver/CoreDriver.cpp @@ -0,0 +1,172 @@ +//===- lib/Driver/CoreDriver.cpp ------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Reader.h" +#include "lld/Driver/Driver.h" +#include "lld/ReaderWriter/CoreLinkingContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lld; + +namespace { + +// Create enum with OPT_xxx values for each option in CoreOptions.td +enum { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELP, META) \ + OPT_##ID, +#include "CoreOptions.inc" +#undef OPTION +}; + +// Create prefix string literals used in CoreOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "CoreOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in CoreOptions.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#include "CoreOptions.inc" +#undef OPTION +}; + +// Create OptTable class for parsing actual command line arguments +class CoreOptTable : public llvm::opt::OptTable { +public: + CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} +}; + +} // namespace anonymous + + +namespace lld { + +static const Registry::KindStrings coreKindStrings[] = { + { CoreLinkingContext::TEST_RELOC_CALL32, "call32" }, + { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" }, + { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" }, + { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" }, + { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" }, + LLD_KIND_STRING_END +}; + +bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) { + CoreLinkingContext ctx; + + // Register possible input file parsers. + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + ctx.registry().addKindTable(Reference::KindNamespace::testing, + Reference::KindArch::all, coreKindStrings); + + if (!parse(argc, argv, ctx)) + return false; + return Driver::link(ctx); +} + +bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx, + raw_ostream &diagnostics) { + // Parse command line options using CoreOptions.td + std::unique_ptr parsedArgs; + CoreOptTable table; + unsigned missingIndex; + unsigned missingCount; + parsedArgs.reset( + table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); + if (missingCount) { + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; + return false; + } + + // Set default options + ctx.setOutputPath("-"); + ctx.setDeadStripping(false); + ctx.setGlobalsAreDeadStripRoots(false); + ctx.setPrintRemainingUndefines(false); + ctx.setAllowRemainingUndefines(true); + ctx.setSearchArchivesToOverrideTentativeDefinitions(false); + + // Process all the arguments and create input files. + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx.appendLLVMOption(inputArg->getValue()); + break; + + case OPT_entry: + ctx.setEntrySymbolName(inputArg->getValue()); + break; + + case OPT_output: + ctx.setOutputPath(inputArg->getValue()); + break; + + case OPT_dead_strip: + ctx.setDeadStripping(true); + break; + + case OPT_keep_globals: + ctx.setGlobalsAreDeadStripRoots(true); + break; + + case OPT_undefines_are_errors: + ctx.setPrintRemainingUndefines(true); + ctx.setAllowRemainingUndefines(false); + break; + + case OPT_commons_search_archives: + ctx.setSearchArchivesToOverrideTentativeDefinitions(true); + break; + + case OPT_add_pass: + ctx.addPassNamed(inputArg->getValue()); + break; + + case OPT_INPUT: { + std::vector> files + = loadFile(ctx, inputArg->getValue(), false); + for (std::unique_ptr &file : files) + ctx.getNodes().push_back(llvm::make_unique(std::move(file))); + break; + } + + default: + break; + } + } + + if (ctx.getNodes().empty()) { + diagnostics << "No input files\n"; + return false; + } + + // Validate the combination of options used. + return ctx.validate(diagnostics); +} + +} // namespace lld diff --git a/lib/Driver/CoreOptions.td b/lib/Driver/CoreOptions.td new file mode 100644 index 000000000000..df7cb41737d2 --- /dev/null +++ b/lib/Driver/CoreOptions.td @@ -0,0 +1,15 @@ +include "llvm/Option/OptParser.td" + +def output : Separate<["-"], "o">; +def entry : Separate<["-"], "e">; + +def dead_strip : Flag<["--"], "dead-strip">; +def undefines_are_errors : Flag<["--"], "undefines-are-errors">; +def keep_globals : Flag<["--"], "keep-globals">; +def commons_search_archives : Flag<["--"], "commons-search-archives">; + +def add_pass : Separate<["--"], "add-pass">; + +def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; +def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; + diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp new file mode 100644 index 000000000000..2c64aeee38a5 --- /dev/null +++ b/lib/Driver/DarwinLdDriver.cpp @@ -0,0 +1,832 @@ +//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Concrete instance of the Driver for darwin's ld. +/// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Driver/Driver.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MachO.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace lld; + +namespace { + +// Create enum with OPT_xxx values for each option in DarwinLdOptions.td +enum { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELP, META) \ + OPT_##ID, +#include "DarwinLdOptions.inc" +#undef OPTION +}; + +// Create prefix string literals used in DarwinLdOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "DarwinLdOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in DarwinLdOptions.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#include "DarwinLdOptions.inc" +#undef OPTION +}; + +// Create OptTable class for parsing actual command line arguments +class DarwinLdOptTable : public llvm::opt::OptTable { +public: + DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} +}; + +std::vector> +loadFile(MachOLinkingContext &ctx, StringRef path, + raw_ostream &diag, bool wholeArchive, bool upwardDylib) { + if (ctx.logInputFiles()) + diag << path << "\n"; + + ErrorOr> mbOrErr = ctx.getMemoryBuffer(path); + if (std::error_code ec = mbOrErr.getError()) + return makeErrorFile(path, ec); + std::vector> files; + if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), files)) + return makeErrorFile(path, ec); + for (std::unique_ptr &pf : files) { + // If file is a dylib, inform LinkingContext about it. + if (SharedLibraryFile *shl = dyn_cast(pf.get())) { + if (std::error_code ec = shl->parse()) + return makeErrorFile(path, ec); + ctx.registerDylib(reinterpret_cast(shl), + upwardDylib); + } + } + if (wholeArchive) + return parseMemberFiles(files); + return files; +} + +} // anonymous namespace + +// Test may be running on Windows. Canonicalize the path +// separator to '/' to get consistent outputs for tests. +static std::string canonicalizePath(StringRef path) { + char sep = llvm::sys::path::get_separator().front(); + if (sep != '/') { + std::string fixedPath = path; + std::replace(fixedPath.begin(), fixedPath.end(), sep, '/'); + return fixedPath; + } else { + return path; + } +} + +static void addFile(StringRef path, MachOLinkingContext &ctx, + bool loadWholeArchive, + bool upwardDylib, raw_ostream &diag) { + std::vector> files = + loadFile(ctx, path, diag, loadWholeArchive, upwardDylib); + for (std::unique_ptr &file : files) + ctx.getNodes().push_back(llvm::make_unique(std::move(file))); +} + +// Export lists are one symbol per line. Blank lines are ignored. +// Trailing comments start with #. +static std::error_code parseExportsList(StringRef exportFilePath, + MachOLinkingContext &ctx, + raw_ostream &diagnostics) { + // Map in export list file. + ErrorOr> mb = + MemoryBuffer::getFileOrSTDIN(exportFilePath); + if (std::error_code ec = mb.getError()) + return ec; + ctx.addInputFileDependency(exportFilePath); + StringRef buffer = mb->get()->getBuffer(); + while (!buffer.empty()) { + // Split off each line in the file. + std::pair lineAndRest = buffer.split('\n'); + StringRef line = lineAndRest.first; + // Ignore trailing # comments. + std::pair symAndComment = line.split('#'); + StringRef sym = symAndComment.first.trim(); + if (!sym.empty()) + ctx.addExportSymbol(sym); + buffer = lineAndRest.second; + } + return std::error_code(); +} + + + +/// Order files are one symbol per line. Blank lines are ignored. +/// Trailing comments start with #. Symbol names can be prefixed with an +/// architecture name and/or .o leaf name. Examples: +/// _foo +/// bar.o:_bar +/// libfrob.a(bar.o):_bar +/// x86_64:_foo64 +static std::error_code parseOrderFile(StringRef orderFilePath, + MachOLinkingContext &ctx, + raw_ostream &diagnostics) { + // Map in order file. + ErrorOr> mb = + MemoryBuffer::getFileOrSTDIN(orderFilePath); + if (std::error_code ec = mb.getError()) + return ec; + ctx.addInputFileDependency(orderFilePath); + StringRef buffer = mb->get()->getBuffer(); + while (!buffer.empty()) { + // Split off each line in the file. + std::pair lineAndRest = buffer.split('\n'); + StringRef line = lineAndRest.first; + buffer = lineAndRest.second; + // Ignore trailing # comments. + std::pair symAndComment = line.split('#'); + if (symAndComment.first.empty()) + continue; + StringRef sym = symAndComment.first.trim(); + if (sym.empty()) + continue; + // Check for prefix. + StringRef prefix; + std::pair prefixAndSym = sym.split(':'); + if (!prefixAndSym.second.empty()) { + sym = prefixAndSym.second; + prefix = prefixAndSym.first; + if (!prefix.endswith(".o") && !prefix.endswith(".o)")) { + // If arch name prefix does not match arch being linked, ignore symbol. + if (!ctx.archName().equals(prefix)) + continue; + prefix = ""; + } + } else + sym = prefixAndSym.first; + if (!sym.empty()) { + ctx.appendOrderedSymbol(sym, prefix); + //llvm::errs() << sym << ", prefix=" << prefix << "\n"; + } + } + return std::error_code(); +} + +// +// There are two variants of the -filelist option: +// +// -filelist +// In this variant, the path is to a text file which contains one file path +// per line. There are no comments or trimming of whitespace. +// +// -fileList , +// In this variant, the path is to a text file which contains a partial path +// per line. The prefix is prepended to each partial path. +// +static std::error_code loadFileList(StringRef fileListPath, + MachOLinkingContext &ctx, bool forceLoad, + raw_ostream &diagnostics) { + // If there is a comma, split off . + std::pair opt = fileListPath.split(','); + StringRef filePath = opt.first; + StringRef dirName = opt.second; + ctx.addInputFileDependency(filePath); + // Map in file list file. + ErrorOr> mb = + MemoryBuffer::getFileOrSTDIN(filePath); + if (std::error_code ec = mb.getError()) + return ec; + StringRef buffer = mb->get()->getBuffer(); + while (!buffer.empty()) { + // Split off each line in the file. + std::pair lineAndRest = buffer.split('\n'); + StringRef line = lineAndRest.first; + StringRef path; + if (!dirName.empty()) { + // If there is a then prepend dir to each line. + SmallString<256> fullPath; + fullPath.assign(dirName); + llvm::sys::path::append(fullPath, Twine(line)); + path = ctx.copy(fullPath.str()); + } else { + // No use whole line as input file path. + path = ctx.copy(line); + } + if (!ctx.pathExists(path)) { + return make_dynamic_error_code(Twine("File not found '") + + path + + "'"); + } + if (ctx.testingFileUsage()) { + diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; + } + addFile(path, ctx, forceLoad, false, diagnostics); + buffer = lineAndRest.second; + } + return std::error_code(); +} + +/// Parse number assuming it is base 16, but allow 0x prefix. +static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { + if (numStr.startswith_lower("0x")) + numStr = numStr.drop_front(2); + return numStr.getAsInteger(16, baseAddress); +} + +namespace lld { + +bool DarwinLdDriver::linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (!parse(argc, argv, ctx, diagnostics)) + return false; + if (ctx.doNothing()) + return true; + return link(ctx, diagnostics); +} + +bool DarwinLdDriver::parse(int argc, const char *argv[], + MachOLinkingContext &ctx, raw_ostream &diagnostics) { + // Parse command line options using DarwinLdOptions.td + std::unique_ptr parsedArgs; + DarwinLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + bool globalWholeArchive = false; + parsedArgs.reset( + table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); + if (missingCount) { + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; + return false; + } + + for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) { + diagnostics << "warning: ignoring unknown argument: " + << unknownArg->getAsString(*parsedArgs) << "\n"; + } + + // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) + llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; + if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable, + OPT_bundle, OPT_static, OPT_preload)) { + switch (kind->getOption().getID()) { + case OPT_dylib: + fileType = llvm::MachO::MH_DYLIB; + break; + case OPT_relocatable: + fileType = llvm::MachO::MH_OBJECT; + break; + case OPT_bundle: + fileType = llvm::MachO::MH_BUNDLE; + break; + case OPT_static: + fileType = llvm::MachO::MH_EXECUTE; + break; + case OPT_preload: + fileType = llvm::MachO::MH_PRELOAD; + break; + } + } + + // Handle -arch xxx + MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown; + if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { + arch = MachOLinkingContext::archFromName(archStr->getValue()); + if (arch == MachOLinkingContext::arch_unknown) { + diagnostics << "error: unknown arch named '" << archStr->getValue() + << "'\n"; + return false; + } + } + // If no -arch specified, scan input files to find first non-fat .o file. + if (arch == MachOLinkingContext::arch_unknown) { + for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) { + // This is expensive because it opens and maps the file. But that is + // ok because no -arch is rare. + if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) + break; + } + if (arch == MachOLinkingContext::arch_unknown + && !parsedArgs->getLastArg(OPT_test_file_usage)) { + // If no -arch and no options at all, print usage message. + if (parsedArgs->size() == 0) + table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); + else + diagnostics << "error: -arch not specified and could not be inferred\n"; + return false; + } + } + + // Handle -macosx_version_min or -ios_version_min + MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX; + uint32_t minOSVersion = 0; + if (llvm::opt::Arg *minOS = + parsedArgs->getLastArg(OPT_macosx_version_min, OPT_ios_version_min, + OPT_ios_simulator_version_min)) { + switch (minOS->getOption().getID()) { + case OPT_macosx_version_min: + os = MachOLinkingContext::OS::macOSX; + if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), + minOSVersion)) { + diagnostics << "error: malformed macosx_version_min value\n"; + return false; + } + break; + case OPT_ios_version_min: + os = MachOLinkingContext::OS::iOS; + if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), + minOSVersion)) { + diagnostics << "error: malformed ios_version_min value\n"; + return false; + } + break; + case OPT_ios_simulator_version_min: + os = MachOLinkingContext::OS::iOS_simulator; + if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), + minOSVersion)) { + diagnostics << "error: malformed ios_simulator_version_min value\n"; + return false; + } + break; + } + } else { + // No min-os version on command line, check environment variables + } + + // Now that there's enough information parsed in, let the linking context + // set up default values. + ctx.configure(fileType, arch, os, minOSVersion); + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) + ctx.setEntrySymbolName(entry->getValue()); + + // Handle -o xxx + if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) + ctx.setOutputPath(outpath->getValue()); + else + ctx.setOutputPath("a.out"); + + // Handle -image_base XXX and -seg1addr XXXX + if (llvm::opt::Arg *imageBase = parsedArgs->getLastArg(OPT_image_base)) { + uint64_t baseAddress; + if (parseNumberBase16(imageBase->getValue(), baseAddress)) { + diagnostics << "error: image_base expects a hex number\n"; + return false; + } else if (baseAddress < ctx.pageZeroSize()) { + diagnostics << "error: image_base overlaps with __PAGEZERO\n"; + return false; + } else if (baseAddress % ctx.pageSize()) { + diagnostics << "error: image_base must be a multiple of page size (" + << llvm::format("0x%" PRIx64, ctx.pageSize()) << ")\n"; + return false; + } + + ctx.setBaseAddress(baseAddress); + } + + // Handle -dead_strip + if (parsedArgs->getLastArg(OPT_dead_strip)) + ctx.setDeadStripping(true); + + // Handle -all_load + if (parsedArgs->getLastArg(OPT_all_load)) + globalWholeArchive = true; + + // Handle -install_name + if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name)) + ctx.setInstallName(installName->getValue()); + else + ctx.setInstallName(ctx.outputPath()); + + // Handle -mark_dead_strippable_dylib + if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib)) + ctx.setDeadStrippableDylib(true); + + // Handle -compatibility_version and -current_version + if (llvm::opt::Arg *vers = + parsedArgs->getLastArg(OPT_compatibility_version)) { + if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { + diagnostics + << "error: -compatibility_version can only be used with -dylib\n"; + return false; + } + uint32_t parsedVers; + if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { + diagnostics << "error: -compatibility_version value is malformed\n"; + return false; + } + ctx.setCompatibilityVersion(parsedVers); + } + + if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) { + if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { + diagnostics << "-current_version can only be used with -dylib\n"; + return false; + } + uint32_t parsedVers; + if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { + diagnostics << "error: -current_version value is malformed\n"; + return false; + } + ctx.setCurrentVersion(parsedVers); + } + + // Handle -bundle_loader + if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader)) + ctx.setBundleLoader(loader->getValue()); + + // Handle -sectalign segname sectname align + for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) { + const char* segName = alignArg->getValue(0); + const char* sectName = alignArg->getValue(1); + const char* alignStr = alignArg->getValue(2); + if ((alignStr[0] == '0') && (alignStr[1] == 'x')) + alignStr += 2; + unsigned long long alignValue; + if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) { + diagnostics << "error: -sectalign alignment value '" + << alignStr << "' not a valid number\n"; + return false; + } + uint8_t align2 = llvm::countTrailingZeros(alignValue); + if ( (unsigned long)(1 << align2) != alignValue ) { + diagnostics << "warning: alignment for '-sectalign " + << segName << " " << sectName + << llvm::format(" 0x%llX", alignValue) + << "' is not a power of two, using " + << llvm::format("0x%08X", (1 << align2)) << "\n"; + } + ctx.addSectionAlignment(segName, sectName, align2); + } + + // Handle -mllvm + for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) { + ctx.appendLLVMOption(llvmArg->getValue()); + } + + // Handle -print_atoms + if (parsedArgs->getLastArg(OPT_print_atoms)) + ctx.setPrintAtoms(); + + // Handle -t (trace) option. + if (parsedArgs->getLastArg(OPT_t)) + ctx.setLogInputFiles(true); + + // Handle -demangle option. + if (parsedArgs->getLastArg(OPT_demangle)) + ctx.setDemangleSymbols(true); + + // Handle -keep_private_externs + if (parsedArgs->getLastArg(OPT_keep_private_externs)) { + ctx.setKeepPrivateExterns(true); + if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) + diagnostics << "warning: -keep_private_externs only used in -r mode\n"; + } + + // Handle -dependency_info used by Xcode. + if (llvm::opt::Arg *depInfo = parsedArgs->getLastArg(OPT_dependency_info)) { + if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) { + diagnostics << "warning: " << ec.message() + << ", processing '-dependency_info " + << depInfo->getValue() + << "'\n"; + } + } + + // In -test_file_usage mode, we'll be given an explicit list of paths that + // exist. We'll also be expected to print out information about how we located + // libraries and so on that the user specified, but not to actually do any + // linking. + if (parsedArgs->getLastArg(OPT_test_file_usage)) { + ctx.setTestingFileUsage(); + + // With paths existing by fiat, linking is not going to end well. + ctx.setDoNothing(true); + + // Only bother looking for an existence override if we're going to use it. + for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) { + ctx.addExistingPathForDebug(existingPath->getValue()); + } + } + + // Register possible input file parsers. + if (!ctx.doNothing()) { + ctx.registry().addSupportMachOObjects(ctx); + ctx.registry().addSupportArchives(ctx.logInputFiles()); + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + } + + // Now construct the set of library search directories, following ld64's + // baroque set of accumulated hacks. Mostly, the algorithm constructs + // { syslibroots } x { libpaths } + // + // Unfortunately, there are numerous exceptions: + // 1. Only absolute paths get modified by syslibroot options. + // 2. If there is just 1 -syslibroot, system paths not found in it are + // skipped. + // 3. If the last -syslibroot is "/", all of them are ignored entirely. + // 4. If { syslibroots } x path == {}, the original path is kept. + std::vector sysLibRoots; + for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) { + sysLibRoots.push_back(syslibRoot->getValue()); + } + if (!sysLibRoots.empty()) { + // Ignore all if last -syslibroot is "/". + if (sysLibRoots.back() != "/") + ctx.setSysLibRoots(sysLibRoots); + } + + // Paths specified with -L come first, and are not considered system paths for + // the case where there is precisely 1 -syslibroot. + for (auto libPath : parsedArgs->filtered(OPT_L)) { + ctx.addModifiedSearchDir(libPath->getValue()); + } + + // Process -F directories (where to look for frameworks). + for (auto fwPath : parsedArgs->filtered(OPT_F)) { + ctx.addFrameworkSearchDir(fwPath->getValue()); + } + + // -Z suppresses the standard search paths. + if (!parsedArgs->hasArg(OPT_Z)) { + ctx.addModifiedSearchDir("/usr/lib", true); + ctx.addModifiedSearchDir("/usr/local/lib", true); + ctx.addFrameworkSearchDir("/Library/Frameworks", true); + ctx.addFrameworkSearchDir("/System/Library/Frameworks", true); + } + + // Now that we've constructed the final set of search paths, print out those + // search paths in verbose mode. + if (parsedArgs->getLastArg(OPT_v)) { + diagnostics << "Library search paths:\n"; + for (auto path : ctx.searchDirs()) { + diagnostics << " " << path << '\n'; + } + diagnostics << "Framework search paths:\n"; + for (auto path : ctx.frameworkDirs()) { + diagnostics << " " << path << '\n'; + } + } + + // Handle -exported_symbols_list + for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) { + if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { + diagnostics << "error: -exported_symbols_list cannot be combined " + << "with -unexported_symbol[s_list]\n"; + return false; + } + ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); + if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, + diagnostics)) { + diagnostics << "error: " << ec.message() + << ", processing '-exported_symbols_list " + << expFile->getValue() + << "'\n"; + return false; + } + } + + // Handle -exported_symbol + for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) { + if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { + diagnostics << "error: -exported_symbol cannot be combined " + << "with -unexported_symbol[s_list]\n"; + return false; + } + ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); + ctx.addExportSymbol(symbol->getValue()); + } + + // Handle -unexported_symbols_list + for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) { + if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { + diagnostics << "error: -unexported_symbols_list cannot be combined " + << "with -exported_symbol[s_list]\n"; + return false; + } + ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); + if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, + diagnostics)) { + diagnostics << "error: " << ec.message() + << ", processing '-unexported_symbols_list " + << expFile->getValue() + << "'\n"; + return false; + } + } + + // Handle -unexported_symbol + for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) { + if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { + diagnostics << "error: -unexported_symbol cannot be combined " + << "with -exported_symbol[s_list]\n"; + return false; + } + ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); + ctx.addExportSymbol(symbol->getValue()); + } + + // Handle obosolete -multi_module and -single_module + if (llvm::opt::Arg *mod = parsedArgs->getLastArg(OPT_multi_module, + OPT_single_module)) { + if (mod->getOption().getID() == OPT_multi_module) { + diagnostics << "warning: -multi_module is obsolete and being ignored\n"; + } + else { + if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { + diagnostics << "warning: -single_module being ignored. " + "It is only for use when producing a dylib\n"; + } + } + } + + // Handle -pie or -no_pie + if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) { + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_EXECUTE: + switch (ctx.os()) { + case MachOLinkingContext::OS::macOSX: + if ((minOSVersion < 0x000A0500) && + (pie->getOption().getID() == OPT_pie)) { + diagnostics << "-pie can only be used when targeting " + "Mac OS X 10.5 or later\n"; + return false; + } + break; + case MachOLinkingContext::OS::iOS: + if ((minOSVersion < 0x00040200) && + (pie->getOption().getID() == OPT_pie)) { + diagnostics << "-pie can only be used when targeting " + "iOS 4.2 or later\n"; + return false; + } + break; + case MachOLinkingContext::OS::iOS_simulator: + if (pie->getOption().getID() == OPT_no_pie) + diagnostics << "iOS simulator programs must be built PIE\n"; + return false; + break; + case MachOLinkingContext::OS::unknown: + break; + } + ctx.setPIE(pie->getOption().getID() == OPT_pie); + break; + case llvm::MachO::MH_PRELOAD: + break; + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + diagnostics << "warning: " << pie->getSpelling() << " being ignored. " + << "It is only used when linking main executables\n"; + break; + default: + diagnostics << pie->getSpelling() + << " can only used when linking main executables\n"; + return false; + break; + } + } + + // Handle debug info handling options: -S + if (parsedArgs->hasArg(OPT_S)) + ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap); + + // Handle -order_file + for (auto orderFile : parsedArgs->filtered(OPT_order_file)) { + if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx, + diagnostics)) { + diagnostics << "error: " << ec.message() + << ", processing '-order_file " + << orderFile->getValue() + << "'\n"; + return false; + } + } + + // Handle -rpath + if (parsedArgs->hasArg(OPT_rpath)) { + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_EXECUTE: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!ctx.minOS("10.5", "2.0")) { + if (ctx.os() == MachOLinkingContext::OS::macOSX) { + diagnostics << "error: -rpath can only be used when targeting " + "OS X 10.5 or later\n"; + } else { + diagnostics << "error: -rpath can only be used when targeting " + "iOS 2.0 or later\n"; + } + return false; + } + break; + default: + diagnostics << "error: -rpath can only be used when creating " + "a dynamic final linked image\n"; + return false; + } + + for (auto rPath : parsedArgs->filtered(OPT_rpath)) { + ctx.addRpath(rPath->getValue()); + } + } + + // Handle input files + for (auto &arg : *parsedArgs) { + bool upward; + ErrorOr resolvedPath = StringRef(); + switch (arg->getOption().getID()) { + default: + continue; + case OPT_INPUT: + addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics); + break; + case OPT_upward_library: + addFile(arg->getValue(), ctx, false, true, diagnostics); + break; + case OPT_force_load: + addFile(arg->getValue(), ctx, true, false, diagnostics); + break; + case OPT_l: + case OPT_upward_l: + upward = (arg->getOption().getID() == OPT_upward_l); + resolvedPath = ctx.searchLibrary(arg->getValue()); + if (!resolvedPath) { + diagnostics << "Unable to find library for " << arg->getSpelling() + << arg->getValue() << "\n"; + return false; + } else if (ctx.testingFileUsage()) { + diagnostics << "Found " << (upward ? "upward " : " ") << "library " + << canonicalizePath(resolvedPath.get()) << '\n'; + } + addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + break; + case OPT_framework: + case OPT_upward_framework: + upward = (arg->getOption().getID() == OPT_upward_framework); + resolvedPath = ctx.findPathForFramework(arg->getValue()); + if (!resolvedPath) { + diagnostics << "Unable to find framework for " + << arg->getSpelling() << " " << arg->getValue() << "\n"; + return false; + } else if (ctx.testingFileUsage()) { + diagnostics << "Found " << (upward ? "upward " : " ") << "framework " + << canonicalizePath(resolvedPath.get()) << '\n'; + } + addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + break; + case OPT_filelist: + if (std::error_code ec = loadFileList(arg->getValue(), + ctx, globalWholeArchive, + diagnostics)) { + diagnostics << "error: " << ec.message() + << ", processing '-filelist " << arg->getValue() + << "'\n"; + return false; + } + break; + } + } + + if (ctx.getNodes().empty()) { + diagnostics << "No input files\n"; + return false; + } + + // Validate the combination of options used. + return ctx.validate(diagnostics); +} + + +} // namespace lld diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td new file mode 100644 index 000000000000..81dcc0a1d925 --- /dev/null +++ b/lib/Driver/DarwinLdOptions.td @@ -0,0 +1,187 @@ +include "llvm/Option/OptParser.td" + + +// output kinds +def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">; +def relocatable : Flag<["-"], "r">, + HelpText<"Create relocatable object file">, Group; +def static : Flag<["-"], "static">, + HelpText<"Create static executable">, Group; +def dynamic : Flag<["-"], "dynamic">, + HelpText<"Create dynamic executable (default)">,Group; +def dylib : Flag<["-"], "dylib">, + HelpText<"Create dynamic library">, Group; +def bundle : Flag<["-"], "bundle">, + HelpText<"Create dynamic bundle">, Group; +def execute : Flag<["-"], "execute">, + HelpText<"Create main executable (default)">, Group; +def preload : Flag<["-"], "preload">, + HelpText<"Create binary for use with embedded systems">, Group; + +// optimizations +def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">; +def dead_strip : Flag<["-"], "dead_strip">, + HelpText<"Remove unreference code and data">, Group; +def macosx_version_min : Separate<["-"], "macosx_version_min">, + MetaVarName<"">, + HelpText<"Minimum Mac OS X version">, Group; +def ios_version_min : Separate<["-"], "ios_version_min">, + MetaVarName<"">, + HelpText<"Minimum iOS version">, Group; +def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">, + Alias; +def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, + MetaVarName<"">, + HelpText<"Minimum iOS simulator version">, Group; +def mllvm : Separate<["-"], "mllvm">, + MetaVarName<"