From 3f7e1b62eb7eae412e146b5d430d246b05d89474 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 9 Dec 2017 18:56:52 +0000 Subject: [PATCH] Import llvm-toolchain-5.0_5.0.1.orig-lld.tar.bz2 [dgit import orig llvm-toolchain-5.0_5.0.1.orig-lld.tar.bz2] --- .arcconfig | 4 + .clang-format | 1 + .gitignore | 24 + CMakeLists.txt | 224 ++ CODE_OWNERS.TXT | 19 + COFF/CMakeLists.txt | 50 + COFF/Chunks.cpp | 500 ++++ COFF/Chunks.h | 375 +++ COFF/Config.h | 174 ++ COFF/DLL.cpp | 548 ++++ COFF/DLL.h | 84 + COFF/Driver.cpp | 1181 ++++++++ COFF/Driver.h | 188 ++ COFF/DriverUtils.cpp | 730 +++++ COFF/Error.cpp | 114 + COFF/Error.h | 62 + COFF/ICF.cpp | 258 ++ COFF/InputFiles.cpp | 411 +++ COFF/InputFiles.h | 223 ++ COFF/LTO.cpp | 140 + COFF/LTO.h | 56 + COFF/MapFile.cpp | 125 + COFF/MapFile.h | 22 + COFF/MarkLive.cpp | 75 + COFF/Memory.h | 52 + COFF/Options.td | 139 + COFF/PDB.cpp | 672 +++++ COFF/PDB.h | 31 + COFF/README.md | 1 + COFF/Strings.cpp | 35 + COFF/Strings.h | 23 + COFF/SymbolTable.cpp | 375 +++ COFF/SymbolTable.h | 124 + COFF/Symbols.cpp | 90 + COFF/Symbols.h | 443 +++ COFF/Writer.cpp | 900 ++++++ COFF/Writer.h | 75 + ELF/Arch/AArch64.cpp | 376 +++ ELF/Arch/AMDGPU.cpp | 84 + ELF/Arch/ARM.cpp | 480 ++++ ELF/Arch/AVR.cpp | 80 + ELF/Arch/Mips.cpp | 423 +++ ELF/Arch/MipsArchTree.cpp | 369 +++ ELF/Arch/PPC.cpp | 65 + ELF/Arch/PPC64.cpp | 217 ++ ELF/Arch/SPARCV9.cpp | 149 + ELF/Arch/X86.cpp | 364 +++ ELF/Arch/X86_64.cpp | 473 ++++ ELF/CMakeLists.txt | 75 + ELF/Config.h | 238 ++ ELF/Driver.cpp | 1061 +++++++ ELF/Driver.h | 75 + ELF/DriverUtils.cpp | 208 ++ ELF/EhFrame.cpp | 212 ++ ELF/EhFrame.h | 25 + ELF/Error.cpp | 116 + ELF/Error.h | 78 + ELF/Filesystem.cpp | 77 + ELF/Filesystem.h | 22 + ELF/GdbIndex.cpp | 49 + ELF/GdbIndex.h | 82 + ELF/ICF.cpp | 435 +++ ELF/ICF.h | 19 + ELF/InputFiles.cpp | 1109 ++++++++ ELF/InputFiles.h | 346 +++ ELF/InputSection.cpp | 1040 +++++++ ELF/InputSection.h | 339 +++ ELF/LTO.cpp | 191 ++ ELF/LTO.h | 57 + ELF/LinkerScript.cpp | 1255 +++++++++ ELF/LinkerScript.h | 306 +++ ELF/MapFile.cpp | 150 + ELF/MapFile.h | 23 + ELF/MarkLive.cpp | 268 ++ ELF/Memory.h | 67 + ELF/Options.td | 414 +++ ELF/OutputSections.cpp | 277 ++ ELF/OutputSections.h | 153 ++ ELF/README.md | 1 + ELF/Relocations.cpp | 1144 ++++++++ ELF/Relocations.h | 185 ++ ELF/ScriptLexer.cpp | 285 ++ ELF/ScriptLexer.h | 56 + ELF/ScriptParser.cpp | 1247 +++++++++ ELF/ScriptParser.h | 31 + ELF/Strings.cpp | 85 + ELF/Strings.h | 79 + ELF/SymbolTable.cpp | 782 ++++++ ELF/SymbolTable.h | 147 + ELF/Symbols.cpp | 399 +++ ELF/Symbols.h | 414 +++ ELF/SyntheticSections.cpp | 2437 +++++++++++++++++ ELF/SyntheticSections.h | 806 ++++++ ELF/Target.cpp | 167 ++ ELF/Target.h | 162 ++ ELF/Threads.h | 88 + ELF/Thunks.cpp | 273 ++ ELF/Thunks.h | 63 + ELF/Writer.cpp | 1913 +++++++++++++ ELF/Writer.h | 61 + LICENSE.TXT | 62 + README.md | 11 + cmake/modules/AddLLD.cmake | 77 + cmake/modules/FindVTune.cmake | 31 + docs/AtomLLD.rst | 62 + docs/CMakeLists.txt | 8 + docs/Driver.rst | 82 + docs/NewLLD.rst | 314 +++ docs/README.txt | 12 + docs/Readers.rst | 174 ++ docs/ReleaseNotes.rst | 172 ++ docs/_static/favicon.ico | Bin 0 -> 1150 bytes docs/_templates/indexsidebar.html | 4 + docs/_templates/layout.html | 12 + docs/conf.py | 255 ++ docs/design.rst | 421 +++ docs/development.rst | 45 + docs/getting_started.rst | 106 + docs/hello.png | Bin 0 -> 27616 bytes docs/index.rst | 179 ++ 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 | 11 + docs/sphinx_intro.rst | 147 + docs/windows_support.rst | 91 + include/lld/Config/Version.h | 25 + include/lld/Config/Version.inc.in | 6 + include/lld/Core/AbsoluteAtom.h | 43 + include/lld/Core/ArchiveLibraryFile.h | 47 + include/lld/Core/Atom.h | 131 + include/lld/Core/DefinedAtom.h | 374 +++ include/lld/Core/Error.h | 68 + include/lld/Core/File.h | 278 ++ include/lld/Core/Instrumentation.h | 132 + include/lld/Core/LLVM.h | 83 + include/lld/Core/LinkingContext.h | 258 ++ include/lld/Core/Node.h | 75 + include/lld/Core/Pass.h | 43 + include/lld/Core/PassManager.h | 48 + include/lld/Core/Reader.h | 155 ++ include/lld/Core/Reference.h | 119 + include/lld/Core/Reproduce.h | 39 + include/lld/Core/Resolver.h | 106 + include/lld/Core/SharedLibraryAtom.h | 53 + include/lld/Core/SharedLibraryFile.h | 70 + include/lld/Core/Simple.h | 271 ++ include/lld/Core/SymbolTable.h | 96 + include/lld/Core/TODO.txt | 17 + include/lld/Core/TargetOptionsCommandFlags.h | 20 + include/lld/Core/UndefinedAtom.h | 68 + include/lld/Core/Writer.h | 47 + include/lld/Driver/Driver.h | 33 + .../lld/ReaderWriter/MachOLinkingContext.h | 508 ++++ include/lld/ReaderWriter/YamlContext.h | 42 + lib/CMakeLists.txt | 4 + lib/Config/CMakeLists.txt | 9 + lib/Config/Version.cpp | 43 + lib/Core/CMakeLists.txt | 30 + lib/Core/DefinedAtom.cpp | 82 + lib/Core/Error.cpp | 93 + lib/Core/File.cpp | 29 + lib/Core/LinkingContext.cpp | 70 + lib/Core/Reader.cpp | 114 + lib/Core/Reproduce.cpp | 66 + lib/Core/Resolver.cpp | 505 ++++ lib/Core/SymbolTable.cpp | 291 ++ lib/Core/TargetOptionsCommandFlags.cpp | 32 + lib/Core/Writer.cpp | 18 + lib/Driver/CMakeLists.txt | 24 + lib/Driver/DarwinLdDriver.cpp | 1239 +++++++++ lib/Driver/DarwinLdOptions.td | 242 ++ lib/ReaderWriter/CMakeLists.txt | 21 + lib/ReaderWriter/FileArchive.cpp | 228 ++ lib/ReaderWriter/MachO/ArchHandler.cpp | 172 ++ lib/ReaderWriter/MachO/ArchHandler.h | 323 +++ lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 1523 ++++++++++ lib/ReaderWriter/MachO/ArchHandler_arm64.cpp | 898 ++++++ lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 644 +++++ lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 865 ++++++ lib/ReaderWriter/MachO/Atoms.h | 181 ++ lib/ReaderWriter/MachO/CMakeLists.txt | 34 + lib/ReaderWriter/MachO/CompactUnwindPass.cpp | 582 ++++ lib/ReaderWriter/MachO/DebugInfo.h | 106 + lib/ReaderWriter/MachO/ExecutableAtoms.h | 155 ++ lib/ReaderWriter/MachO/File.h | 400 +++ lib/ReaderWriter/MachO/FlatNamespaceFile.h | 61 + lib/ReaderWriter/MachO/GOTPass.cpp | 184 ++ lib/ReaderWriter/MachO/LayoutPass.cpp | 489 ++++ lib/ReaderWriter/MachO/LayoutPass.h | 119 + .../MachO/MachOLinkingContext.cpp | 1102 ++++++++ lib/ReaderWriter/MachO/MachONormalizedFile.h | 345 +++ .../MachO/MachONormalizedFileBinaryReader.cpp | 591 ++++ .../MachO/MachONormalizedFileBinaryUtils.h | 215 ++ .../MachO/MachONormalizedFileBinaryWriter.cpp | 1551 +++++++++++ .../MachO/MachONormalizedFileFromAtoms.cpp | 1657 +++++++++++ .../MachO/MachONormalizedFileToAtoms.cpp | 1635 +++++++++++ .../MachO/MachONormalizedFileYAML.cpp | 843 ++++++ lib/ReaderWriter/MachO/MachOPasses.h | 30 + lib/ReaderWriter/MachO/ObjCPass.cpp | 132 + lib/ReaderWriter/MachO/SectCreateFile.h | 102 + lib/ReaderWriter/MachO/ShimPass.cpp | 129 + lib/ReaderWriter/MachO/StubsPass.cpp | 379 +++ lib/ReaderWriter/MachO/TLVPass.cpp | 141 + lib/ReaderWriter/MachO/WriterMachO.cpp | 71 + lib/ReaderWriter/YAML/CMakeLists.txt | 9 + lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 1404 ++++++++++ test/CMakeLists.txt | 56 + test/COFF/Inputs/armnt-executable.obj.yaml | 29 + test/COFF/Inputs/armnt-executable.s | 13 + test/COFF/Inputs/associative-comdat-2.s | 13 + test/COFF/Inputs/bar.ll | 6 + test/COFF/Inputs/cl-gl.obj | Bin 0 -> 3734 bytes test/COFF/Inputs/combined-resources-2.rc | 36 + test/COFF/Inputs/combined-resources-2.res | Bin 0 -> 452 bytes .../COFF/Inputs/combined-resources-cursor.bmp | Bin 0 -> 822 bytes test/COFF/Inputs/combined-resources-okay.bmp | Bin 0 -> 822 bytes test/COFF/Inputs/combined-resources.rc | 50 + test/COFF/Inputs/combined-resources.res | Bin 0 -> 2332 bytes test/COFF/Inputs/conflict.ll | 6 + test/COFF/Inputs/constant-export.ll | 7 + test/COFF/Inputs/constant-import.s | 21 + test/COFF/Inputs/default.def | 2 + test/COFF/Inputs/delayimports-error.yaml | 29 + test/COFF/Inputs/entry-mangled.ll | 6 + test/COFF/Inputs/export.ll | 18 + test/COFF/Inputs/export.yaml | 57 + test/COFF/Inputs/export2.yaml | 29 + test/COFF/Inputs/extension.def | 3 + test/COFF/Inputs/far-arm-thumb-abs.s | 2 + test/COFF/Inputs/hello32.yaml | 82 + test/COFF/Inputs/hello64.asm | 24 + test/COFF/Inputs/hello64.obj | Bin 0 -> 682 bytes test/COFF/Inputs/import.yaml | 48 + test/COFF/Inputs/imports-mangle.lib | Bin 0 -> 2114 bytes test/COFF/Inputs/include1a.yaml | 33 + test/COFF/Inputs/include1b.yaml | 33 + test/COFF/Inputs/include1c.yaml | 29 + test/COFF/Inputs/library-arm64.lib | Bin 0 -> 2000 bytes test/COFF/Inputs/library.def | 5 + test/COFF/Inputs/library.lib | Bin 0 -> 1694 bytes test/COFF/Inputs/lto-chkstk-chkstk.s | 3 + test/COFF/Inputs/lto-chkstk-foo.s | 3 + test/COFF/Inputs/lto-comdat1.ll | 13 + test/COFF/Inputs/lto-comdat2.ll | 13 + test/COFF/Inputs/lto-dep.ll | 10 + test/COFF/Inputs/lto-lazy-reference-dummy.ll | 6 + .../Inputs/lto-lazy-reference-quadruple.ll | 16 + test/COFF/Inputs/machine-x64.yaml | 29 + test/COFF/Inputs/machine-x86.yaml | 29 + test/COFF/Inputs/manifestinput.test | 13 + test/COFF/Inputs/msvclto-order-a.ll | 7 + test/COFF/Inputs/msvclto-order-b.ll | 10 + test/COFF/Inputs/msvclto.s | 3 + test/COFF/Inputs/named.def | 3 + test/COFF/Inputs/object.s | 13 + test/COFF/Inputs/oldname.yaml | 26 + test/COFF/Inputs/pdb-diff-cl.pdb | Bin 0 -> 102400 bytes test/COFF/Inputs/pdb-diff.cpp | 10 + test/COFF/Inputs/pdb-diff.obj | Bin 0 -> 8602 bytes test/COFF/Inputs/pdb-global-gc.s | 4 + test/COFF/Inputs/pdb-import-gc.lib | Bin 0 -> 1614 bytes test/COFF/Inputs/pdb-scopes-a.yaml | 425 +++ test/COFF/Inputs/pdb-scopes-b.yaml | 365 +++ .../COFF/Inputs/pdb-type-server-simple-a.yaml | 255 ++ .../COFF/Inputs/pdb-type-server-simple-b.yaml | 173 ++ .../Inputs/pdb-type-server-simple-ts.yaml | 147 + test/COFF/Inputs/pdb1.yaml | 302 ++ test/COFF/Inputs/pdb2.yaml | 217 ++ test/COFF/Inputs/pdb_comdat_bar.yaml | 440 +++ test/COFF/Inputs/pdb_comdat_main.yaml | 446 +++ test/COFF/Inputs/pdb_lines_1.yaml | 480 ++++ test/COFF/Inputs/pdb_lines_2.yaml | 209 ++ test/COFF/Inputs/resource.res | Bin 0 -> 108 bytes test/COFF/Inputs/ret42.lib | Bin 0 -> 550 bytes test/COFF/Inputs/ret42.obj | Bin 0 -> 408 bytes test/COFF/Inputs/ret42.yaml | 45 + test/COFF/Inputs/std32.lib | Bin 0 -> 1898 bytes test/COFF/Inputs/std64.lib | Bin 0 -> 2068 bytes test/COFF/Inputs/thinlto-mangled-qux.ll | 28 + test/COFF/Inputs/weak-external.ll | 6 + test/COFF/Inputs/weak-external2.ll | 6 + test/COFF/Inputs/weak-external3.ll | 8 + test/COFF/alternatename.test | 61 + test/COFF/ar-comdat.test | 38 + test/COFF/arm-thumb-branch-error.s | 10 + test/COFF/arm64-magic.yaml | 46 + test/COFF/arm64-relocs-imports.test | 136 + test/COFF/armnt-blx23t.test | 66 + test/COFF/armnt-branch24t.test | 59 + test/COFF/armnt-entry-point.test | 5 + test/COFF/armnt-imports.test | 51 + test/COFF/armnt-mov32t-exec.test | 60 + test/COFF/armnt-movt32t.test | 72 + test/COFF/associative-comdat.s | 46 + test/COFF/base.test | 57 + test/COFF/baserel.test | 215 ++ test/COFF/cl-gl.test | 4 + test/COFF/combined-resources.test | 213 ++ test/COFF/common.test | 103 + test/COFF/conflict-mangled.test | 37 + test/COFF/conflict.test | 42 + test/COFF/constant-export.test | 92 + test/COFF/constant.test | 6 + test/COFF/debug.test | 38 + test/COFF/def-export-stdcall.s | 27 + test/COFF/def-name.test | 26 + test/COFF/defparser.test | 13 + test/COFF/delayimports-error.test | 46 + test/COFF/delayimports.test | 41 + test/COFF/delayimports32.test | 87 + test/COFF/dll.test | 50 + test/COFF/dllimport-gc.test | 56 + test/COFF/driver-windows.test | 3 + test/COFF/driver.test | 3 + test/COFF/entry-inference.test | 50 + test/COFF/entry-inference2.test | 39 + test/COFF/entry-inference32.test | 35 + test/COFF/entry-mangled.test | 36 + test/COFF/entrylib.ll | 12 + test/COFF/error-limit.test | 29 + test/COFF/export-exe.test | 10 + test/COFF/export.test | 95 + test/COFF/export32.test | 142 + test/COFF/failifmismatch.test | 11 + test/COFF/filetype.test | 4 + test/COFF/force.test | 43 + test/COFF/guardcf.test | 74 + test/COFF/heap.test | 25 + test/COFF/hello32.test | 132 + test/COFF/help.test | 3 + test/COFF/icf-associative.test | 104 + test/COFF/icf-circular.test | 81 + test/COFF/icf-circular2.test | 69 + test/COFF/icf-data.test | 61 + test/COFF/icf-different-align.test | 61 + test/COFF/icf-local.test | 66 + test/COFF/icf-simple.test | 71 + test/COFF/implib-name.test | 71 + test/COFF/imports-mangle.test | 66 + test/COFF/imports.test | 36 + test/COFF/include-lto.ll | 22 + test/COFF/include.test | 83 + test/COFF/include2.test | 14 + test/COFF/internal.test | 42 + test/COFF/invalid-debug-type.test | 5 + test/COFF/invalid-obj.test | 14 + test/COFF/largeaddressaware.test | 21 + test/COFF/lib.test | 11 + test/COFF/libpath.test | 18 + test/COFF/linkenv.test | 4 + test/COFF/linkrepro.test | 37 + test/COFF/lldmap.test | 10 + test/COFF/loadcfg.ll | 15 + test/COFF/loadcfg.test | 75 + test/COFF/loadcfg32.test | 58 + test/COFF/locally-imported.test | 61 + test/COFF/locally-imported32.test | 50 + test/COFF/long-section-name.test | 58 + test/COFF/lto-chkstk.ll | 17 + test/COFF/lto-comdat.ll | 108 + test/COFF/lto-debug-pass-arguments.ll | 16 + test/COFF/lto-lazy-reference.ll | 21 + test/COFF/lto-linker-opts.ll | 8 + test/COFF/lto-new-symbol.ll | 16 + test/COFF/lto-opt-level.ll | 21 + test/COFF/lto-parallel.ll | 20 + test/COFF/lto.ll | 130 + test/COFF/machine.test | 30 + test/COFF/manifest.test | 66 + test/COFF/manifestinput.test | 26 + test/COFF/merge.test | 53 + test/COFF/msvclto-archive.ll | 40 + test/COFF/msvclto-order.ll | 25 + test/COFF/msvclto.ll | 20 + test/COFF/nodefaultlib.test | 30 + test/COFF/noentry.test | 8 + test/COFF/nopdb.test | 14 + test/COFF/opt.test | 69 + test/COFF/options.test | 45 + test/COFF/order.test | 15 + test/COFF/out.test | 17 + test/COFF/pdb-comdat.test | 99 + test/COFF/pdb-diff.test | 212 ++ test/COFF/pdb-global-gc.yaml | 116 + test/COFF/pdb-import-gc.yaml | 114 + test/COFF/pdb-invalid-func-type.yaml | 146 + test/COFF/pdb-lib.s | 36 + test/COFF/pdb-linker-module.test | 18 + test/COFF/pdb-none.test | 14 + test/COFF/pdb-options.test | 21 + test/COFF/pdb-safeseh.yaml | 85 + test/COFF/pdb-scopes.test | 75 + test/COFF/pdb-secrel-absolute.yaml | 84 + test/COFF/pdb-source-lines.test | 124 + test/COFF/pdb-symbol-types.yaml | 344 +++ test/COFF/pdb-type-server-missing.yaml | 132 + test/COFF/pdb-type-server-simple.test | 91 + test/COFF/pdb.test | 202 ++ test/COFF/reloc-arm.test | 84 + test/COFF/reloc-discarded-dwarf.s | 15 + test/COFF/reloc-discarded.s | 30 + test/COFF/reloc-oob.yaml | 62 + test/COFF/reloc-x64.test | 102 + test/COFF/reloc-x86.test | 82 + test/COFF/resource.test | 44 + test/COFF/responsefile.test | 7 + test/COFF/rsds.test | 94 + test/COFF/safeseh-diag-feat.test | 51 + test/COFF/safeseh.s | 60 + test/COFF/savetemps.ll | 29 + test/COFF/secidx-absolute.s | 33 + test/COFF/secrel-absolute.s | 14 + test/COFF/secrel-common.s | 41 + test/COFF/section.test | 62 + test/COFF/seh.test | 70 + test/COFF/sort-debug.test | 335 +++ test/COFF/stack.test | 25 + test/COFF/subsystem-inference.test | 74 + test/COFF/subsystem.test | 19 + test/COFF/symtab.test | 236 ++ test/COFF/thinlto-archives.ll | 23 + test/COFF/thinlto-mangled.ll | 17 + test/COFF/thinlto.ll | 19 + test/COFF/tls.test | 43 + test/COFF/tls32.test | 43 + test/COFF/unwind.test | 198 ++ test/COFF/version.test | 19 + test/COFF/weak-external.test | 35 + test/COFF/weak-external2.test | 30 + test/COFF/weak-external3.test | 30 + test/Driver/Inputs/libtest.a | 1 + test/Driver/Inputs/usr/lib/i386/libtest.a | 1 + test/Driver/Inputs/usr/lib/libtest.a | 1 + test/ELF/Inputs/aarch64-condb-reloc.s | 17 + test/ELF/Inputs/aarch64-copy2.s | 5 + test/ELF/Inputs/aarch64-tls-gdie.s | 4 + test/ELF/Inputs/aarch64-tls-ie.s | 19 + test/ELF/Inputs/aarch64-tstbr14-reloc.s | 12 + test/ELF/Inputs/abs-hidden.s | 3 + test/ELF/Inputs/abs.s | 4 + test/ELF/Inputs/abs255.s | 2 + test/ELF/Inputs/abs256.s | 2 + test/ELF/Inputs/abs257.s | 2 + test/ELF/Inputs/allow-multiple-definition.s | 4 + test/ELF/Inputs/allow-shlib-undefined.s | 3 + test/ELF/Inputs/archive.s | 5 + test/ELF/Inputs/archive2.s | 2 + test/ELF/Inputs/archive3.s | 2 + test/ELF/Inputs/archive4.s | 1 + test/ELF/Inputs/arm-attributes1.s | 29 + test/ELF/Inputs/arm-exidx-cantunwind.s | 40 + test/ELF/Inputs/arm-plt-reloc.s | 14 + test/ELF/Inputs/arm-shared.s | 8 + test/ELF/Inputs/arm-thumb-blx-targets.s | 36 + test/ELF/Inputs/arm-thumb-narrow-branch.o | Bin 0 -> 868 bytes test/ELF/Inputs/arm-thumb-narrow-branch.s | 18 + test/ELF/Inputs/arm-tls-get-addr.s | 13 + test/ELF/Inputs/bad-archive.a | 2 + test/ELF/Inputs/comdat.s | 3 + test/ELF/Inputs/comment-gc.s | 1 + test/ELF/Inputs/common.s | 3 + test/ELF/Inputs/conflict-debug.s | 5 + test/ELF/Inputs/conflict.s | 7 + test/ELF/Inputs/copy-in-shared.s | 4 + test/ELF/Inputs/copy-rel-corrupted.s | 4 + test/ELF/Inputs/copy-rel-pie.s | 11 + test/ELF/Inputs/ctors_dtors_priority1.s | 5 + test/ELF/Inputs/ctors_dtors_priority2.s | 5 + test/ELF/Inputs/ctors_dtors_priority3.s | 5 + test/ELF/Inputs/discard-merge-unnamed.o | Bin 0 -> 584 bytes test/ELF/Inputs/dso-undef-size.s | 4 + test/ELF/Inputs/dtrace-r.o | Bin 0 -> 624 bytes test/ELF/Inputs/duplicated-plt-entry.s | 3 + test/ELF/Inputs/dynamic-reloc-weak.s | 11 + test/ELF/Inputs/dynamic-reloc.s | 2 + test/ELF/Inputs/eh-frame-end.s | 2 + test/ELF/Inputs/ehframe-relocation.s | 2 + test/ELF/Inputs/empty-ver.ver | 2 + test/ELF/Inputs/exclude-libs.s | 3 + test/ELF/Inputs/far-arm-abs.s | 13 + test/ELF/Inputs/far-arm-thumb-abs.s | 24 + test/ELF/Inputs/gc-sections-weak.s | 8 + test/ELF/Inputs/gdb-index.s | 73 + test/ELF/Inputs/gnu-ifunc-dso.s | 3 + test/ELF/Inputs/gnu-ifunc-gotpcrel.s | 4 + test/ELF/Inputs/gotpc-relax-und-dso.s | 4 + test/ELF/Inputs/i386-got32x-baseless.elf | Bin 0 -> 628 bytes test/ELF/Inputs/i386-reloc-16-error.s | 3 + test/ELF/Inputs/i386-reloc-16.s | 3 + test/ELF/Inputs/i386-reloc-8-error.s | 3 + test/ELF/Inputs/i386-reloc-8.s | 3 + test/ELF/Inputs/i386-tls-got.s | 5 + test/ELF/Inputs/icf-absolute.s | 3 + test/ELF/Inputs/icf-merge-sec.s | 9 + test/ELF/Inputs/icf-merge.s | 10 + test/ELF/Inputs/icf-merge2.s | 10 + test/ELF/Inputs/icf-merge3.s | 10 + test/ELF/Inputs/icf-non-mergeable.s | 8 + test/ELF/Inputs/icf2.s | 5 + test/ELF/Inputs/libsearch-dyn.s | 3 + test/ELF/Inputs/libsearch-st.s | 3 + test/ELF/Inputs/llvm33-rela-outside-group.o | Bin 0 -> 1072 bytes test/ELF/Inputs/map-file2.s | 8 + test/ELF/Inputs/map-file3.s | 2 + test/ELF/Inputs/map-file4.s | 3 + test/ELF/Inputs/merge.s | 6 + test/ELF/Inputs/mips-align-err.s | 2 + test/ELF/Inputs/mips-concatenated-abiflags.o | Bin 0 -> 1084 bytes test/ELF/Inputs/mips-dynamic.s | 28 + test/ELF/Inputs/mips-fnpic.s | 6 + test/ELF/Inputs/mips-fpic.s | 6 + test/ELF/Inputs/mips-gp-disp.so | Bin 0 -> 131828 bytes test/ELF/Inputs/mips-gp0-non-zero.o | Bin 0 -> 848 bytes test/ELF/Inputs/mips-n32-rels.o | Bin 0 -> 1092 bytes test/ELF/Inputs/mips-nonalloc.s | 2 + test/ELF/Inputs/mips-options.o | Bin 0 -> 1160 bytes test/ELF/Inputs/mips-pic.s | 19 + test/ELF/Inputs/mips-tls.s | 5 + test/ELF/Inputs/no-symtab.o | Bin 0 -> 416 bytes test/ELF/Inputs/plt-aarch64.s | 5 + test/ELF/Inputs/ppc64-addr16-error.s | 3 + test/ELF/Inputs/progname-ver.s | 3 + test/ELF/Inputs/protected-shared.s | 10 + test/ELF/Inputs/relocatable-comdat-multiple.s | 2 + test/ELF/Inputs/relocatable-ehframe.s | 14 + test/ELF/Inputs/relocatable-non-alloc.s | 6 + test/ELF/Inputs/relocatable-tls.s | 1 + test/ELF/Inputs/relocatable.s | 22 + test/ELF/Inputs/relocatable2.s | 22 + test/ELF/Inputs/relocation-copy-alias.s | 25 + .../ELF/Inputs/relocation-copy-align-common.s | 7 + test/ELF/Inputs/relocation-copy-align.s | 9 + test/ELF/Inputs/relocation-copy-arm.s | 22 + test/ELF/Inputs/relocation-copy-relro.s | 13 + test/ELF/Inputs/relocation-copy.s | 22 + .../ELF/Inputs/relocation-relative-absolute.s | 2 + test/ELF/Inputs/relocation-size-shared.s | 6 + test/ELF/Inputs/resolution-end.s | 3 + test/ELF/Inputs/resolution-shared.s | 2 + test/ELF/Inputs/resolution.s | 107 + test/ELF/Inputs/rodynamic.s | 4 + test/ELF/Inputs/shared-ppc64.s | 9 + test/ELF/Inputs/shared.s | 10 + test/ELF/Inputs/shared2-x86-64.s | 9 + test/ELF/Inputs/shared2.s | 6 + test/ELF/Inputs/shared3.s | 3 + test/ELF/Inputs/shf-info-link.test | 21 + test/ELF/Inputs/sht-group-gold-r.elf | Bin 0 -> 880 bytes test/ELF/Inputs/sht-group-gold-r.s | 14 + test/ELF/Inputs/start-lib-comdat.s | 5 + test/ELF/Inputs/start-lib1.s | 3 + test/ELF/Inputs/start-lib2.s | 2 + test/ELF/Inputs/startstop-shared2.s | 2 + test/ELF/Inputs/symbol-override.s | 16 + test/ELF/Inputs/symver-archive1.s | 6 + test/ELF/Inputs/symver-archive2.s | 1 + test/ELF/Inputs/tls-got-entry.s | 13 + test/ELF/Inputs/tls-got.s | 14 + test/ELF/Inputs/tls-in-archive.s | 3 + test/ELF/Inputs/tls-mismatch.s | 4 + test/ELF/Inputs/tls-opt-gdie.s | 20 + test/ELF/Inputs/tls-opt-gdiele-i686.s | 20 + test/ELF/Inputs/tls-opt-iele-i686-nopic.s | 15 + test/ELF/Inputs/trace-ar1.s | 2 + test/ELF/Inputs/trace-ar2.s | 2 + test/ELF/Inputs/trace-symbols-foo-strong.s | 14 + test/ELF/Inputs/trace-symbols-foo-weak.s | 12 + test/ELF/Inputs/uabs_label.s | 4 + test/ELF/Inputs/undef-debug.s | 11 + test/ELF/Inputs/undef-with-plt-addr.s | 7 + test/ELF/Inputs/undef.s | 3 + test/ELF/Inputs/unknown-reloc.s | 2 + test/ELF/Inputs/unresolved-symbols.s | 3 + test/ELF/Inputs/use-bar.s | 2 + test/ELF/Inputs/verdef-defaultver.s | 22 + test/ELF/Inputs/verdef.s | 6 + test/ELF/Inputs/verneed.so.sh | 58 + test/ELF/Inputs/verneed1.so | Bin 0 -> 2632 bytes test/ELF/Inputs/verneed2.so | Bin 0 -> 2200 bytes test/ELF/Inputs/version-script-err.script | 4 + test/ELF/Inputs/version-script-no-warn2.s | 1 + test/ELF/Inputs/version-script-weak.s | 4 + test/ELF/Inputs/version-undef-sym.so | Bin 0 -> 2312 bytes test/ELF/Inputs/version-use.script | 6 + test/ELF/Inputs/version-use.so | Bin 0 -> 2720 bytes test/ELF/Inputs/visibility.s | 14 + test/ELF/Inputs/warn-common.s | 2 + test/ELF/Inputs/warn-common2.s | 8 + test/ELF/Inputs/weak-and-strong-undef.s | 1 + test/ELF/Inputs/whole-archive.s | 2 + test/ELF/Inputs/wrap-dynamic-undef.s | 2 + test/ELF/Inputs/wrap.s | 4 + test/ELF/Inputs/x86-64-relax-offset.s | 7 + test/ELF/Inputs/x86-64-reloc-16-error.s | 3 + test/ELF/Inputs/x86-64-reloc-16.s | 3 + test/ELF/Inputs/x86-64-reloc-8-error.s | 3 + test/ELF/Inputs/x86-64-reloc-8.s | 3 + test/ELF/Inputs/x86-64-reloc-error.s | 7 + test/ELF/Inputs/x86-64-tls-gd-got.s | 6 + test/ELF/Inputs/ztext-text-notext.s | 10 + test/ELF/aarch64-abs16.s | 27 + test/ELF/aarch64-abs32.s | 27 + test/ELF/aarch64-abs64-dyn.s | 27 + test/ELF/aarch64-call26-error.s | 11 + test/ELF/aarch64-condb-reloc.s | 99 + test/ELF/aarch64-copy.s | 93 + test/ELF/aarch64-copy2.s | 27 + test/ELF/aarch64-data-relocs.s | 23 + test/ELF/aarch64-fpic-abs16.s | 9 + test/ELF/aarch64-fpic-add_abs_lo12_nc.s | 12 + test/ELF/aarch64-fpic-adr_prel_lo21.s | 12 + test/ELF/aarch64-fpic-adr_prel_pg_hi21.s | 12 + test/ELF/aarch64-fpic-got.s | 18 + test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s | 12 + test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s | 12 + test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s | 12 + test/ELF/aarch64-fpic-prel16.s | 9 + test/ELF/aarch64-fpic-prel32.s | 9 + test/ELF/aarch64-fpic-prel64.s | 9 + test/ELF/aarch64-gnu-ifunc-nosym.s | 27 + test/ELF/aarch64-gnu-ifunc-plt.s | 85 + test/ELF/aarch64-gnu-ifunc.s | 139 + test/ELF/aarch64-got-reloc.s | 30 + test/ELF/aarch64-got-relocations.s | 21 + test/ELF/aarch64-got.s | 18 + test/ELF/aarch64-hi21-error.s | 10 + test/ELF/aarch64-jump26-error.s | 11 + test/ELF/aarch64-lo21-error.s | 10 + test/ELF/aarch64-prel16.s | 31 + test/ELF/aarch64-prel32.s | 31 + test/ELF/aarch64-relative.s | 26 + test/ELF/aarch64-relocs.s | 174 ++ test/ELF/aarch64-relro.s | 14 + test/ELF/aarch64-tls-gdie.s | 34 + test/ELF/aarch64-tls-gdle.s | 26 + test/ELF/aarch64-tls-ie.s | 50 + test/ELF/aarch64-tls-iele.s | 33 + test/ELF/aarch64-tls-le.s | 31 + test/ELF/aarch64-tls-pie.s | 28 + test/ELF/aarch64-tls-static.s | 37 + test/ELF/aarch64-tlsdesc.s | 72 + test/ELF/aarch64-tstbr14-reloc.s | 96 + test/ELF/aarch64-undefined-weak.s | 45 + test/ELF/abs-conflict.s | 18 + test/ELF/abs-hidden.s | 46 + test/ELF/allow-multiple-definition.s | 29 + test/ELF/allow-shlib-undefined.s | 26 + test/ELF/amdgpu-globals.s | 64 + test/ELF/amdgpu-kernels.s | 59 + test/ELF/amdgpu-relocs.s | 93 + test/ELF/archive.s | 40 + test/ELF/arm-abs32-dyn.s | 32 + test/ELF/arm-attributes.s | 183 ++ test/ELF/arm-blx.s | 114 + test/ELF/arm-branch-error.s | 19 + test/ELF/arm-branch.s | 60 + test/ELF/arm-copy.s | 81 + test/ELF/arm-data-prel.s | 63 + test/ELF/arm-data-relocs.s | 20 + test/ELF/arm-eabi-version.s | 14 + test/ELF/arm-exidx-canunwind.s | 99 + test/ELF/arm-exidx-gc.s | 124 + test/ELF/arm-exidx-link.s | 25 + test/ELF/arm-exidx-order.s | 169 ++ test/ELF/arm-exidx-output.s | 44 + test/ELF/arm-exidx-relocatable.s | 132 + test/ELF/arm-exidx-sentinel-norelocatable.s | 17 + test/ELF/arm-exidx-sentinel-orphan.s | 23 + test/ELF/arm-exidx-shared.s | 45 + test/ELF/arm-fpic-got.s | 63 + test/ELF/arm-gnu-ifunc-nosym.s | 27 + test/ELF/arm-gnu-ifunc-plt.s | 101 + test/ELF/arm-gnu-ifunc.s | 140 + test/ELF/arm-got-relative.s | 53 + test/ELF/arm-gotoff.s | 74 + test/ELF/arm-icf-exidx.s | 33 + test/ELF/arm-mov-relocs.s | 89 + test/ELF/arm-pie-relative.s | 25 + test/ELF/arm-plt-reloc.s | 98 + test/ELF/arm-sbrel32.s | 39 + test/ELF/arm-static-defines.s | 44 + test/ELF/arm-target1.s | 36 + test/ELF/arm-target2.s | 60 + test/ELF/arm-thumb-blx.s | 85 + test/ELF/arm-thumb-branch-error.s | 19 + test/ELF/arm-thumb-branch.s | 60 + test/ELF/arm-thumb-interwork-shared.s | 52 + test/ELF/arm-thumb-interwork-thunk-range.s | 15 + test/ELF/arm-thumb-interwork-thunk.s | 378 +++ test/ELF/arm-thumb-narrow-branch-check.s | 73 + test/ELF/arm-thumb-no-undefined-thunk.s | 24 + test/ELF/arm-thumb-plt-reloc.s | 108 + test/ELF/arm-thumb-thunk-symbols.s | 42 + test/ELF/arm-thumb-undefined-weak.s | 38 + test/ELF/arm-tls-gd-nonpreemptible.s | 72 + test/ELF/arm-tls-gd32.s | 106 + test/ELF/arm-tls-ie32.s | 96 + test/ELF/arm-tls-ldm32.s | 73 + test/ELF/arm-tls-le32.s | 77 + test/ELF/arm-tls-norelax-gd-ie.s | 30 + test/ELF/arm-tls-norelax-gd-le.s | 37 + test/ELF/arm-tls-norelax-ie-le.s | 41 + test/ELF/arm-tls-norelax-ld-le.s | 35 + test/ELF/arm-undefined-weak.s | 39 + test/ELF/arm-use-r-output.s | 13 + test/ELF/as-needed-no-reloc.s | 23 + test/ELF/as-needed.s | 45 + test/ELF/auxiliary.s | 13 + test/ELF/avoid-empty-program-headers.s | 78 + test/ELF/bad-archive.s | 11 + test/ELF/basic-aarch64.s | 209 ++ test/ELF/basic-avr.s | 14 + test/ELF/basic-freebsd.s | 25 + test/ELF/basic-mips.s | 307 +++ test/ELF/basic-ppc.s | 317 +++ test/ELF/basic-sparcv9.s | 200 ++ test/ELF/basic.s | 252 ++ test/ELF/basic32.s | 179 ++ test/ELF/basic64be.s | 309 +++ test/ELF/bss-start-common.s | 15 + test/ELF/bss.s | 37 + test/ELF/bsymbolic-undef.s | 26 + test/ELF/bsymbolic.s | 34 + test/ELF/build-id.s | 68 + test/ELF/color-diagnostics.test | 18 + test/ELF/combrelocs.s | 92 + test/ELF/comdat-linkonce.s | 9 + test/ELF/comdat.s | 92 + test/ELF/comment-gc.s | 15 + test/ELF/common.s | 59 + test/ELF/compatible-section-types.s | 20 + test/ELF/compress-debug-sections.s | 32 + test/ELF/compressed-debug-input.s | 82 + test/ELF/conflict.s | 50 + test/ELF/copy-errors.s | 15 + test/ELF/copy-in-shared.s | 11 + test/ELF/copy-rel-corrupted.s | 10 + test/ELF/copy-rel-pie-error.s | 17 + test/ELF/copy-rel-pie.s | 44 + test/ELF/ctors_dtors_priority.s | 48 + test/ELF/debug-gc.s | 30 + test/ELF/debug-gnu-pubnames.s | 18 + test/ELF/default-fill.s | 38 + test/ELF/default-output.s | 16 + test/ELF/defined-tls_get_addr.s | 10 + test/ELF/defsym.s | 47 + test/ELF/discard-locals.s | 50 + test/ELF/discard-merge-locals.s | 35 + test/ELF/discard-merge-unnamed.s | 27 + test/ELF/discard-none.s | 54 + test/ELF/dont-export-hidden.s | 39 + test/ELF/driver-access.test | 15 + test/ELF/driver.test | 60 + test/ELF/dso-undef-size.s | 32 + test/ELF/dso_handle.s | 19 + test/ELF/dt_flags.s | 21 + test/ELF/dt_tags.s | 18 + test/ELF/dtrace-r.test | 8 + test/ELF/duplicated-plt-entry.s | 17 + test/ELF/duplicated-synthetic-sym.s | 10 + test/ELF/dynamic-got-rela.s | 34 + test/ELF/dynamic-got.s | 39 + test/ELF/dynamic-list-extern.s | 15 + test/ELF/dynamic-list.s | 171 ++ test/ELF/dynamic-reloc-in-ro.s | 10 + test/ELF/dynamic-reloc-index.s | 21 + test/ELF/dynamic-reloc-weak.s | 37 + test/ELF/dynamic-reloc.s | 65 + test/ELF/dynamic.s | 44 + test/ELF/dynsym-pie.s | 36 + test/ELF/early-exit-for-bad-paths.s | 35 + test/ELF/edata-etext.s | 40 + test/ELF/eh-align-cie.s | 57 + test/ELF/eh-frame-begin-end.s | 17 + test/ELF/eh-frame-dyn-rel.s | 12 + test/ELF/eh-frame-gc.s | 20 + test/ELF/eh-frame-gc2.s | 15 + test/ELF/eh-frame-hdr-abs-fde.s | 33 + test/ELF/eh-frame-hdr-augmentation.s | 38 + test/ELF/eh-frame-hdr-icf.s | 27 + test/ELF/eh-frame-hdr-no-out2.s | 19 + test/ELF/eh-frame-hdr.s | 126 + test/ELF/eh-frame-marker.s | 19 + test/ELF/eh-frame-merge.s | 58 + test/ELF/eh-frame-multilpe-cie.s | 12 + test/ELF/eh-frame-padding-no-rosegment.s | 64 + test/ELF/eh-frame-plt.s | 16 + test/ELF/eh-frame-rel.s | 7 + test/ELF/eh-frame-type.test | 17 + test/ELF/ehdr_start.s | 41 + test/ELF/ehframe-relocation.s | 31 + test/ELF/emit-relocs-merge.s | 20 + test/ELF/emit-relocs-shared.s | 16 + test/ELF/emit-relocs.s | 106 + test/ELF/empty-archive.s | 3 + test/ELF/empty-pt-load.s | 11 + test/ELF/empty-ver.s | 43 + test/ELF/emulation.s | 360 +++ test/ELF/end-abs.s | 11 + test/ELF/end-preserve.s | 16 + test/ELF/end-update.s | 29 + test/ELF/end.s | 37 + test/ELF/entry.s | 53 + test/ELF/error-limit.test | 26 + test/ELF/exclude-libs.s | 30 + test/ELF/exclude.s | 19 + test/ELF/fatal-warnings.s | 16 + test/ELF/file-sym.s | 12 + test/ELF/filter.s | 15 + test/ELF/format-binary.test | 57 + test/ELF/gc-absolute.s | 7 + test/ELF/gc-debuginfo-tls.s | 23 + test/ELF/gc-merge-local-sym.s | 34 + test/ELF/gc-sections-alloc.s | 31 + test/ELF/gc-sections-eh.s | 32 + test/ELF/gc-sections-implicit-addend.s | 26 + test/ELF/gc-sections-keep-shared-start.s | 30 + test/ELF/gc-sections-local-sym.s | 57 + test/ELF/gc-sections-lsda.s | 21 + test/ELF/gc-sections-merge-addend.s | 39 + test/ELF/gc-sections-merge-implicit-addend.s | 39 + test/ELF/gc-sections-merge.s | 61 + test/ELF/gc-sections-metadata-startstop.s | 33 + test/ELF/gc-sections-metadata.s | 38 + test/ELF/gc-sections-metadata2.s | 19 + test/ELF/gc-sections-non-alloc-to-merge.s | 27 + test/ELF/gc-sections-print.s | 23 + test/ELF/gc-sections-protected.s | 18 + test/ELF/gc-sections-shared.s | 59 + test/ELF/gc-sections-synthetic.s | 16 + test/ELF/gc-sections-weak.s | 24 + test/ELF/gc-sections.s | 108 + test/ELF/gdb-index-dup-types.s | 60 + test/ELF/gdb-index-empty.s | 81 + test/ELF/gdb-index-gc-sections.s | 158 ++ test/ELF/gdb-index-ranges.s | 66 + test/ELF/gdb-index.s | 112 + .../global-offset-table-position-aarch64.s | 30 + test/ELF/global-offset-table-position-arm.s | 35 + test/ELF/global-offset-table-position-i386.s | 31 + test/ELF/global-offset-table-position-mips.s | 33 + test/ELF/global-offset-table-position.s | 31 + test/ELF/global_offset_table.s | 5 + test/ELF/global_offset_table_shared.s | 14 + test/ELF/gnu-hash-table.s | 195 ++ test/ELF/gnu-ifunc-dso.s | 13 + test/ELF/gnu-ifunc-gotpcrel.s | 14 + test/ELF/gnu-ifunc-i386.s | 126 + test/ELF/gnu-ifunc-nosym-i386.s | 27 + test/ELF/gnu-ifunc-nosym.s | 27 + test/ELF/gnu-ifunc-plt-i386.s | 76 + test/ELF/gnu-ifunc-plt.s | 74 + test/ELF/gnu-ifunc-relative.s | 23 + test/ELF/gnu-ifunc-shared.s | 66 + test/ELF/gnu-ifunc.s | 127 + test/ELF/gnu-unique.s | 37 + test/ELF/gnustack.s | 34 + test/ELF/got-aarch64.s | 40 + test/ELF/got-i386.s | 56 + test/ELF/got-plt-header.s | 30 + test/ELF/got.s | 45 + test/ELF/got32-i386.s | 23 + test/ELF/got32x-i386.s | 47 + test/ELF/gotpc-relax-nopic.s | 87 + test/ELF/gotpc-relax-und-dso.s | 72 + test/ELF/gotpc-relax.s | 98 + test/ELF/gotpcrelx.s | 30 + test/ELF/hidden-vis-shared.s | 18 + test/ELF/i386-got-and-copy.s | 25 + test/ELF/i386-gotoff-shared.s | 23 + test/ELF/i386-gotpc-dynamic.s | 32 + test/ELF/i386-gotpc.s | 20 + test/ELF/i386-merge.s | 50 + test/ELF/i386-pc16.test | 40 + test/ELF/i386-pc8-pc16-addend.s | 17 + test/ELF/i386-pc8.s | 15 + test/ELF/i386-relative.s | 14 + test/ELF/i386-relax-reloc.s | 12 + test/ELF/i386-reloc-16.s | 14 + test/ELF/i386-reloc-8.s | 14 + test/ELF/i386-reloc-large-addend.s | 16 + test/ELF/i386-reloc-range.s | 23 + test/ELF/i386-reloc8-reloc16-addend.s | 17 + test/ELF/i386-tls-got.s | 7 + test/ELF/i386-tls-ie-shared.s | 111 + test/ELF/icf-absolute.s | 20 + test/ELF/icf-comdat.s | 23 + test/ELF/icf-i386.s | 25 + test/ELF/icf-merge-sec.s | 18 + test/ELF/icf-merge.s | 27 + test/ELF/icf-non-mergeable.s | 28 + test/ELF/icf-none.s | 22 + test/ELF/icf1.s | 23 + test/ELF/icf2.s | 17 + test/ELF/icf3.s | 19 + test/ELF/icf4.s | 19 + test/ELF/icf5.s | 19 + test/ELF/icf6.s | 23 + test/ELF/icf7.s | 29 + test/ELF/icf8.s | 14 + test/ELF/icf9.s | 20 + test/ELF/image-base.s | 64 + test/ELF/incompatible-ar-first.s | 11 + test/ELF/incompatible-section-flags.s | 23 + test/ELF/incompatible-section-types2.s | 9 + test/ELF/incompatible.s | 59 + test/ELF/init-fini-progbits.s | 19 + test/ELF/init-fini.s | 54 + test/ELF/init_fini_priority.s | 37 + test/ELF/invalid-cie-length.s | 10 + test/ELF/invalid-cie-length2.s | 10 + test/ELF/invalid-cie-length3.s | 11 + test/ELF/invalid-cie-length4.s | 11 + test/ELF/invalid-cie-length5.s | 10 + test/ELF/invalid-cie-reference.s | 32 + test/ELF/invalid-dynamic-list.test | 37 + test/ELF/invalid-fde-rel.s | 36 + test/ELF/invalid-linkerscript.test | 54 + test/ELF/invalid-relocations.test | 23 + test/ELF/invalid-z.s | 9 + test/ELF/invalid/Inputs/binding.elf | Bin 0 -> 536 bytes .../invalid/Inputs/broken-relaxation-x64.elf | Bin 0 -> 688 bytes test/ELF/invalid/Inputs/cie-version2.elf | Bin 0 -> 1128 bytes .../Inputs/common-symbol-alignment.elf | Bin 0 -> 456 bytes .../Inputs/common-symbol-alignment2.elf | Bin 0 -> 456 bytes test/ELF/invalid/Inputs/data-encoding.a | Bin 0 -> 156 bytes .../Inputs/dynamic-section-sh_size.elf | Bin 0 -> 482 bytes test/ELF/invalid/Inputs/file-class.a | Bin 0 -> 156 bytes test/ELF/invalid/Inputs/invalid-e_shnum.elf | Bin 0 -> 64 bytes .../mips-invalid-options-descriptor.elf | Bin 0 -> 480 bytes .../ELF/invalid/Inputs/multiple-eh-relocs.elf | Bin 0 -> 784 bytes .../Inputs/section-alignment-notpow2.elf | Bin 0 -> 960 bytes test/ELF/invalid/Inputs/section-index.elf | Bin 0 -> 544 bytes test/ELF/invalid/Inputs/section-index2.elf | Bin 0 -> 474 bytes test/ELF/invalid/Inputs/shentsize-zero.elf | Bin 0 -> 512 bytes test/ELF/invalid/Inputs/sht-group.elf | Bin 0 -> 480 bytes test/ELF/invalid/Inputs/symbol-index.elf | Bin 0 -> 480 bytes .../ELF/invalid/Inputs/symbol-name-offset.elf | Bin 0 -> 480 bytes test/ELF/invalid/Inputs/symtab-sh_info.elf | Bin 0 -> 512 bytes test/ELF/invalid/Inputs/symtab-sh_info2.elf | Bin 0 -> 470 bytes test/ELF/invalid/Inputs/symtab-sh_info3.elf | Bin 0 -> 470 bytes test/ELF/invalid/Inputs/tls-symbol.elf | Bin 0 -> 456 bytes test/ELF/invalid/Inputs/too-short.elf | Bin 0 -> 44 bytes test/ELF/invalid/broken-relaxation-x64.test | 46 + test/ELF/invalid/common-symbol-alignment.s | 12 + test/ELF/invalid/dynamic-section-size.s | 4 + test/ELF/invalid/eh-frame-hdr-no-out.s | 6 + .../invalid/invalid-debug-relocations.test | 41 + test/ELF/invalid/invalid-e_shnum.s | 3 + test/ELF/invalid/invalid-elf.test | 31 + test/ELF/invalid/invalid-relocation-x64.test | 27 + test/ELF/invalid/merge-invalid-size.s | 10 + .../invalid/mips-invalid-options-descriptor.s | 5 + test/ELF/invalid/section-alignment.test | 19 + test/ELF/invalid/section-alignment2.s | 5 + test/ELF/invalid/sht-group.s | 3 + test/ELF/invalid/symbol-index.s | 10 + test/ELF/invalid/symbol-name.s | 7 + test/ELF/invalid/symtab-sh-info.s | 9 + test/ELF/invalid/symtab-symbols.test | 25 + test/ELF/invalid/tls-symbol.s | 5 + test/ELF/invalid/too-short.s | 5 + test/ELF/invalid/verdef-no-symtab.test | 26 + test/ELF/libsearch.s | 101 + test/ELF/linkerscript/Inputs/comdat-gc.s | 5 + .../Inputs/compress-debug-sections.s | 3 + .../linkerscript/Inputs/exclude-multiple1.s | 8 + .../linkerscript/Inputs/exclude-multiple2.s | 8 + test/ELF/linkerscript/Inputs/filename-spec.s | 2 + .../Inputs/implicit-program-header.script | 12 + test/ELF/linkerscript/Inputs/include.s | 5 + test/ELF/linkerscript/Inputs/keep.s | 2 + test/ELF/linkerscript/Inputs/lazy-symbols.s | 2 + test/ELF/linkerscript/Inputs/libsearch-dyn.s | 3 + test/ELF/linkerscript/Inputs/libsearch-st.s | 3 + .../Inputs/merge-sections-reloc.s | 3 + test/ELF/linkerscript/Inputs/notinclude.s | 4 + .../linkerscript/Inputs/segment-start.script | 7 + test/ELF/linkerscript/Inputs/shared.s | 10 + test/ELF/linkerscript/Inputs/sort-nested.s | 7 + test/ELF/linkerscript/Inputs/sort.s | 19 + test/ELF/linkerscript/absolute-expr.s | 82 + test/ELF/linkerscript/absolute.s | 35 + test/ELF/linkerscript/addr-zero.s | 18 + test/ELF/linkerscript/addr.s | 32 + test/ELF/linkerscript/align-empty.s | 18 + test/ELF/linkerscript/align.s | 80 + test/ELF/linkerscript/alignof.s | 41 + test/ELF/linkerscript/alternate-sections.s | 36 + test/ELF/linkerscript/arm-exidx-phdrs.s | 16 + test/ELF/linkerscript/arm-lscript.s | 9 + test/ELF/linkerscript/assert.s | 39 + test/ELF/linkerscript/at-addr.s | 39 + test/ELF/linkerscript/at.s | 124 + test/ELF/linkerscript/bss-fill.s | 7 + test/ELF/linkerscript/comdat-gc.s | 14 + test/ELF/linkerscript/common-assign.s | 48 + test/ELF/linkerscript/common.s | 49 + .../linkerscript/compress-debug-sections.s | 36 + test/ELF/linkerscript/constructor.s | 13 + test/ELF/linkerscript/data-commands-gc.s | 17 + test/ELF/linkerscript/data-commands.s | 81 + test/ELF/linkerscript/data-segment-relro.s | 70 + test/ELF/linkerscript/define.s | 25 + test/ELF/linkerscript/diagnostic.s | 106 + test/ELF/linkerscript/discard-interp.s | 12 + test/ELF/linkerscript/discard-print-gc.s | 19 + test/ELF/linkerscript/discard-section-err.s | 23 + .../linkerscript/discard-section-metadata.s | 32 + test/ELF/linkerscript/discard-section.s | 14 + test/ELF/linkerscript/dot-is-not-abs.s | 53 + test/ELF/linkerscript/double-bss.s | 21 + test/ELF/linkerscript/dynamic-sym.s | 17 + test/ELF/linkerscript/dynamic.s | 28 + test/ELF/linkerscript/early-assign-symbol.s | 14 + test/ELF/linkerscript/edata-etext.s | 23 + test/ELF/linkerscript/eh-frame-hdr.s | 20 + .../eh-frame-reloc-out-of-range.s | 27 + test/ELF/linkerscript/eh-frame.s | 19 + test/ELF/linkerscript/ehdr_start.s | 20 + test/ELF/linkerscript/emit-reloc.s | 17 + test/ELF/linkerscript/emit-relocs-discard.s | 14 + .../emit-relocs-ehframe-discard.s | 11 + test/ELF/linkerscript/emit-relocs-multiple.s | 20 + test/ELF/linkerscript/empty-load.s | 21 + test/ELF/linkerscript/empty-tls.s | 14 + test/ELF/linkerscript/entry.s | 42 + test/ELF/linkerscript/exclude-multiple.s | 37 + test/ELF/linkerscript/excludefile.s | 49 + test/ELF/linkerscript/exidx-crash.s | 7 + test/ELF/linkerscript/expr-invalid-sec.s | 6 + test/ELF/linkerscript/expr-sections.s | 22 + test/ELF/linkerscript/extend-pt-load.s | 69 + test/ELF/linkerscript/filename-spec.s | 59 + test/ELF/linkerscript/fill-exec-sections.s | 40 + test/ELF/linkerscript/fill.s | 31 + test/ELF/linkerscript/got-write-offset.s | 23 + test/ELF/linkerscript/group.s | 56 + test/ELF/linkerscript/header-addr.s | 47 + test/ELF/linkerscript/huge-temporary-file.s | 12 + .../linkerscript/implicit-program-header.s | 13 + test/ELF/linkerscript/input-order.s | 38 + test/ELF/linkerscript/input-sec-dup.s | 18 + test/ELF/linkerscript/lazy-symbols.s | 13 + test/ELF/linkerscript/linkerscript.s | 54 + test/ELF/linkerscript/loadaddr.s | 42 + test/ELF/linkerscript/locationcountererr.s | 11 + test/ELF/linkerscript/locationcountererr2.s | 11 + test/ELF/linkerscript/memory.s | 114 + test/ELF/linkerscript/merge-sections-reloc.s | 16 + test/ELF/linkerscript/merge-sections-syms.s | 49 + test/ELF/linkerscript/merge-sections.s | 62 + .../linkerscript/multi-sections-constraint.s | 34 + test/ELF/linkerscript/multiple-tbss.s | 45 + test/ELF/linkerscript/no-pt-load.s | 5 + test/ELF/linkerscript/no-space.s | 24 + test/ELF/linkerscript/noload.s | 46 + test/ELF/linkerscript/non-absolute.s | 30 + test/ELF/linkerscript/non-absolute2.s | 12 + test/ELF/linkerscript/non-alloc-segment.s | 44 + test/ELF/linkerscript/non-alloc.s | 23 + test/ELF/linkerscript/numbers.s | 80 + test/ELF/linkerscript/obj-symbol-value.s | 19 + test/ELF/linkerscript/openbsd-bootdata.s | 7 + test/ELF/linkerscript/openbsd-randomize.s | 23 + test/ELF/linkerscript/openbsd-wxneeded.s | 17 + test/ELF/linkerscript/operators.s | 93 + test/ELF/linkerscript/orphan-align.s | 28 + test/ELF/linkerscript/orphan-first-cmd.s | 20 + test/ELF/linkerscript/orphan.s | 36 + test/ELF/linkerscript/orphans.s | 31 + test/ELF/linkerscript/ouputformat.s | 9 + test/ELF/linkerscript/out-of-order.s | 19 + test/ELF/linkerscript/output-too-large.s | 9 + test/ELF/linkerscript/outputarch.s | 4 + test/ELF/linkerscript/outsections-addr.s | 110 + test/ELF/linkerscript/page-size-align.s | 22 + test/ELF/linkerscript/page-size.s | 66 + test/ELF/linkerscript/phdr-check.s | 15 + test/ELF/linkerscript/phdrs-flags.s | 58 + test/ELF/linkerscript/phdrs.s | 143 + test/ELF/linkerscript/pt_gnu_eh_frame.s | 13 + test/ELF/linkerscript/repsection-symbol.s | 28 + test/ELF/linkerscript/repsection-va.s | 24 + test/ELF/linkerscript/rosegment.s | 24 + test/ELF/linkerscript/searchdir.s | 12 + test/ELF/linkerscript/section-align.s | 62 + test/ELF/linkerscript/section-metadata.s | 33 + test/ELF/linkerscript/sections-constraint.s | 46 + test/ELF/linkerscript/sections-constraint2.s | 14 + test/ELF/linkerscript/sections-constraint3.s | 11 + test/ELF/linkerscript/sections-constraint4.s | 20 + test/ELF/linkerscript/sections-constraint5.s | 32 + test/ELF/linkerscript/sections-gc.s | 19 + test/ELF/linkerscript/sections-gc2.s | 31 + test/ELF/linkerscript/sections-keep.s | 95 + test/ELF/linkerscript/sections-padding.s | 54 + test/ELF/linkerscript/sections-sort.s | 27 + test/ELF/linkerscript/sections.s | 108 + test/ELF/linkerscript/segment-none.s | 39 + test/ELF/linkerscript/segment-start.s | 27 + test/ELF/linkerscript/sizeof.s | 53 + test/ELF/linkerscript/sizeofheaders.s | 18 + test/ELF/linkerscript/sort-constructors.s | 5 + test/ELF/linkerscript/sort-init.s | 24 + test/ELF/linkerscript/sort-nested.s | 50 + test/ELF/linkerscript/sort-non-script.s | 16 + test/ELF/linkerscript/sort.s | 120 + test/ELF/linkerscript/sort2.s | 39 + test/ELF/linkerscript/start-end.s | 16 + test/ELF/linkerscript/subalign.s | 43 + test/ELF/linkerscript/symbol-assignexpr.s | 59 + test/ELF/linkerscript/symbol-conflict.s | 11 + test/ELF/linkerscript/symbol-memoryexpr.s | 33 + test/ELF/linkerscript/symbol-only.s | 21 + test/ELF/linkerscript/symbol-reserved.s | 22 + test/ELF/linkerscript/symbolreferenced.s | 22 + test/ELF/linkerscript/symbols-non-alloc.s | 19 + test/ELF/linkerscript/symbols-synthetic.s | 98 + test/ELF/linkerscript/symbols.s | 84 + test/ELF/linkerscript/tbss.s | 42 + test/ELF/linkerscript/ttext-script.s | 11 + test/ELF/linkerscript/undef.s | 11 + test/ELF/linkerscript/unused-synthetic.s | 18 + test/ELF/linkerscript/va.s | 24 + test/ELF/linkerscript/visibility.s | 22 + test/ELF/linkerscript/wildcards.s | 83 + test/ELF/linkerscript/wildcards2.s | 25 + test/ELF/lit.local.cfg | 2 + test/ELF/llvm33-rela-outside-group.s | 11 + test/ELF/local-dynamic.s | 94 + test/ELF/local-got-pie.s | 37 + test/ELF/local-got-shared.s | 36 + test/ELF/local-got.s | 48 + test/ELF/local-undefined-symbol.s | 13 + test/ELF/local.s | 92 + test/ELF/lto/Inputs/archive-2.ll | 6 + test/ELF/lto/Inputs/archive-3.ll | 5 + test/ELF/lto/Inputs/archive.ll | 6 + test/ELF/lto/Inputs/available-externally.ll | 6 + test/ELF/lto/Inputs/cache.ll | 10 + test/ELF/lto/Inputs/comdat.s | 5 + test/ELF/lto/Inputs/common.s | 1 + test/ELF/lto/Inputs/common3.ll | 3 + test/ELF/lto/Inputs/defsym-bar.ll | 21 + test/ELF/lto/Inputs/drop-debug-info.bc | Bin 0 -> 1152 bytes test/ELF/lto/Inputs/drop-linkage.ll | 12 + test/ELF/lto/Inputs/duplicated-name.ll | 6 + test/ELF/lto/Inputs/dynsym.s | 3 + test/ELF/lto/Inputs/internalize-exportdyn.ll | 6 + test/ELF/lto/Inputs/internalize-undef.ll | 6 + test/ELF/lto/Inputs/irmover-error.ll | 6 + test/ELF/lto/Inputs/linkonce-odr.ll | 6 + test/ELF/lto/Inputs/linkonce.ll | 6 + test/ELF/lto/Inputs/relocation-model-pic.ll | 11 + test/ELF/lto/Inputs/resolution.s | 4 + test/ELF/lto/Inputs/save-temps.ll | 6 + test/ELF/lto/Inputs/shared.s | 7 + test/ELF/lto/Inputs/start-lib1.ll | 8 + test/ELF/lto/Inputs/start-lib2.ll | 6 + test/ELF/lto/Inputs/thin1.ll | 12 + test/ELF/lto/Inputs/thin2.ll | 11 + test/ELF/lto/Inputs/thinlto.ll | 7 + test/ELF/lto/Inputs/tls-mixed.s | 4 + test/ELF/lto/Inputs/type-merge.ll | 8 + test/ELF/lto/Inputs/type-merge2.ll | 8 + test/ELF/lto/Inputs/undef-mixed.s | 3 + test/ELF/lto/Inputs/unnamed-addr-drop.ll | 4 + test/ELF/lto/Inputs/unnamed-addr-lib.s | 6 + test/ELF/lto/Inputs/visibility.s | 8 + test/ELF/lto/Inputs/wrap-bar.ll | 14 + test/ELF/lto/archive-2.ll | 28 + test/ELF/lto/archive-3.ll | 19 + test/ELF/lto/archive-no-index.ll | 25 + test/ELF/lto/archive.ll | 36 + test/ELF/lto/asmundef.ll | 24 + test/ELF/lto/available-externally.ll | 23 + test/ELF/lto/bitcode-nodatalayout.ll | 13 + test/ELF/lto/cache.ll | 32 + test/ELF/lto/codemodel.ll | 20 + test/ELF/lto/combined-lto-object-name.ll | 16 + test/ELF/lto/comdat.ll | 21 + test/ELF/lto/comdat2.ll | 41 + test/ELF/lto/common.ll | 31 + test/ELF/lto/common2.ll | 28 + test/ELF/lto/common3.ll | 15 + test/ELF/lto/ctors.ll | 18 + test/ELF/lto/defsym.ll | 42 + test/ELF/lto/discard-value-names.ll | 24 + test/ELF/lto/drop-debug-info.ll | 9 + test/ELF/lto/drop-linkage.ll | 14 + test/ELF/lto/duplicated-name.ll | 15 + test/ELF/lto/duplicated.ll | 14 + test/ELF/lto/dynamic-list.ll | 25 + test/ELF/lto/dynsym.ll | 30 + test/ELF/lto/inline-asm.ll | 11 + test/ELF/lto/internalize-basic.ll | 21 + test/ELF/lto/internalize-exportdyn.ll | 47 + test/ELF/lto/internalize-llvmused.ll | 20 + test/ELF/lto/internalize-undef.ll | 16 + test/ELF/lto/internalize-version-script.ll | 22 + test/ELF/lto/irmover-error.ll | 12 + test/ELF/lto/linkage.ll | 20 + test/ELF/lto/linkonce-odr.ll | 17 + test/ELF/lto/linkonce.ll | 17 + test/ELF/lto/lto-start.ll | 23 + test/ELF/lto/ltopasses-basic.ll | 17 + test/ELF/lto/ltopasses-custom.ll | 37 + test/ELF/lto/metadata.ll | 15 + test/ELF/lto/mix-platforms.ll | 10 + test/ELF/lto/module-asm.ll | 19 + test/ELF/lto/opt-level.ll | 30 + test/ELF/lto/opt-remarks.ll | 69 + test/ELF/lto/parallel-internalize.ll | 59 + test/ELF/lto/parallel.ll | 25 + test/ELF/lto/pic.ll | 20 + test/ELF/lto/relax-relocs.ll | 16 + test/ELF/lto/relocation-model.ll | 46 + test/ELF/lto/resolution.ll | 27 + test/ELF/lto/save-temps.ll | 20 + test/ELF/lto/shlib-undefined.ll | 27 + test/ELF/lto/start-lib.ll | 27 + test/ELF/lto/thin-archivecollision.ll | 37 + test/ELF/lto/thinlto.ll | 37 + test/ELF/lto/timepasses.ll | 15 + test/ELF/lto/tls-mixed.ll | 10 + test/ELF/lto/tls-preserve.ll | 25 + test/ELF/lto/type-merge.ll | 26 + test/ELF/lto/type-merge2.ll | 28 + test/ELF/lto/undef-mixed.ll | 22 + test/ELF/lto/undef-weak.ll | 29 + test/ELF/lto/undef.ll | 20 + test/ELF/lto/undefined-puts.ll | 28 + test/ELF/lto/unnamed-addr-comdat.ll | 12 + test/ELF/lto/unnamed-addr-drop.ll | 13 + test/ELF/lto/unnamed-addr-lib.ll | 21 + test/ELF/lto/unnamed-addr.ll | 15 + test/ELF/lto/verify-invalid.ll | 17 + test/ELF/lto/version-script.ll | 50 + test/ELF/lto/visibility.ll | 35 + test/ELF/lto/weak.ll | 16 + test/ELF/lto/wrap-1.ll | 42 + test/ELF/lto/wrap-2.ll | 50 + test/ELF/many-alloc-sections.s | 107 + test/ELF/many-sections.s | 124 + test/ELF/map-file.s | 59 + test/ELF/map-gc-sections.s | 9 + test/ELF/merge-reloc.s | 92 + test/ELF/merge-section-types.s | 20 + test/ELF/merge-shared-str.s | 28 + test/ELF/merge-shared.s | 26 + test/ELF/merge-string-align.s | 56 + test/ELF/merge-string-empty.s | 12 + test/ELF/merge-string-error.s | 11 + test/ELF/merge-string-no-null.s | 8 + test/ELF/merge-string.s | 105 + test/ELF/merge-sym.s | 21 + test/ELF/merge.s | 111 + test/ELF/mips-26-mask.s | 16 + test/ELF/mips-26.s | 95 + test/ELF/mips-32.s | 79 + test/ELF/mips-64-disp.s | 88 + test/ELF/mips-64-got.s | 91 + test/ELF/mips-64-gprel-so.s | 23 + test/ELF/mips-64-rels.s | 46 + test/ELF/mips-64.s | 63 + test/ELF/mips-align-err.s | 12 + test/ELF/mips-call-hilo.s | 62 + test/ELF/mips-call16.s | 40 + test/ELF/mips-dynamic.s | 98 + test/ELF/mips-dynsym-sort.s | 43 + test/ELF/mips-elf-flags-err.s | 86 + test/ELF/mips-elf-flags.s | 172 ++ test/ELF/mips-gnu-hash.s | 15 + test/ELF/mips-got-and-copy.s | 57 + test/ELF/mips-got-extsym.s | 59 + test/ELF/mips-got-hilo.s | 64 + test/ELF/mips-got-page.s | 40 + test/ELF/mips-got-redundant.s | 64 + test/ELF/mips-got-relocs.s | 100 + test/ELF/mips-got-string.s | 28 + test/ELF/mips-got-weak.s | 172 ++ test/ELF/mips-got16-relocatable.s | 40 + test/ELF/mips-got16.s | 132 + test/ELF/mips-gp-disp.s | 37 + test/ELF/mips-gp-ext.s | 69 + test/ELF/mips-gp-local.s | 20 + test/ELF/mips-gp-lowest.s | 44 + test/ELF/mips-gprel-sec.s | 37 + test/ELF/mips-gprel32-relocs-gp0.s | 48 + test/ELF/mips-gprel32-relocs.s | 31 + test/ELF/mips-higher-highest.s | 21 + test/ELF/mips-hilo-gp-disp.s | 55 + test/ELF/mips-hilo-hi-only.s | 28 + test/ELF/mips-hilo.s | 53 + test/ELF/mips-jalr.test | 52 + test/ELF/mips-lo16-not-relative.s | 23 + test/ELF/mips-merge-abiflags.s | 63 + test/ELF/mips-n32-emul.s | 14 + test/ELF/mips-n32-rels.s | 71 + test/ELF/mips-no-objects.s | 5 + test/ELF/mips-nonalloc.s | 21 + test/ELF/mips-npic-call-pic-os.s | 138 + test/ELF/mips-npic-call-pic-script.s | 255 ++ test/ELF/mips-npic-call-pic.s | 145 + test/ELF/mips-options-r.test | 18 + test/ELF/mips-options.s | 31 + test/ELF/mips-pc-relocs.s | 45 + test/ELF/mips-plt-copy.s | 85 + test/ELF/mips-plt-r6.s | 38 + test/ELF/mips-reginfo.s | 26 + test/ELF/mips-relocatable.s | 21 + test/ELF/mips-sto-pic-flag.s | 58 + test/ELF/mips-sto-plt.s | 66 + test/ELF/mips-tls-64.s | 111 + test/ELF/mips-tls-hilo.s | 51 + test/ELF/mips-tls-static-64.s | 37 + test/ELF/mips-tls-static.s | 42 + test/ELF/mips-tls.s | 107 + test/ELF/mips-xgot-order.s | 49 + test/ELF/mips64-eh-abs-reloc.s | 38 + test/ELF/new-dtags.test | 16 + test/ELF/no-augmentation.s | 19 + test/ELF/no-dynamic-linker.s | 12 + test/ELF/no-inhibit-exec.s | 15 + test/ELF/no-merge.s | 19 + test/ELF/no-obj.s | 9 + test/ELF/no-plt-shared.s | 17 + test/ELF/no-soname.s | 32 + test/ELF/no-symtab.s | 5 + test/ELF/no-undefined.s | 8 + test/ELF/non-abs-reloc.s | 11 + test/ELF/noplt-pie.s | 21 + test/ELF/note-contiguous.s | 24 + test/ELF/note-loadaddr.c | 35 + test/ELF/note-multiple.s | 43 + test/ELF/note.s | 18 + test/ELF/oformat-binary-ttext.s | 18 + test/ELF/oformat-binary.s | 32 + test/ELF/openbsd-randomize.s | 20 + test/ELF/openbsd-wxneeded.s | 17 + test/ELF/output-section.s | 34 + test/ELF/phdr-align.s | 83 + test/ELF/pie-weak.s | 17 + test/ELF/pie.s | 56 + test/ELF/plt-aarch64.s | 203 ++ test/ELF/plt-i686.s | 174 ++ test/ELF/plt.s | 119 + test/ELF/ppc-relocs.s | 64 + test/ELF/ppc64-addr16-error.s | 8 + test/ELF/ppc64-rel-calls.s | 42 + test/ELF/ppc64-relocs.s | 130 + test/ELF/ppc64-shared-rel-toc.s | 27 + test/ELF/ppc64-toc-restore.s | 62 + test/ELF/ppc64-weak-undef-call-shared.s | 16 + test/ELF/ppc64-weak-undef-call.s | 27 + test/ELF/pre_init_fini_array.s | 152 + test/ELF/pre_init_fini_array_missing.s | 43 + test/ELF/progname.s | 32 + test/ELF/program-header-layout.s | 85 + test/ELF/protected-shared.s | 52 + test/ELF/rel-offset.s | 15 + test/ELF/relative-dynamic-reloc-pie.s | 27 + test/ELF/relative-dynamic-reloc-ppc64.s | 67 + test/ELF/relative-dynamic-reloc.s | 71 + test/ELF/relocatable-bss.s | 40 + test/ELF/relocatable-comdat-multiple.s | 31 + test/ELF/relocatable-comdat.s | 45 + test/ELF/relocatable-comment.s | 27 + test/ELF/relocatable-common.s | 36 + test/ELF/relocatable-compressed-input.s | 45 + test/ELF/relocatable-eh-frame-hdr.s | 11 + test/ELF/relocatable-eh-frame.s | 19 + test/ELF/relocatable-ehframe.s | 51 + test/ELF/relocatable-empty-archive.s | 10 + test/ELF/relocatable-local-sym.s | 16 + test/ELF/relocatable-non-alloc.s | 10 + test/ELF/relocatable-reloc.s | 15 + test/ELF/relocatable-script.s | 7 + test/ELF/relocatable-section-symbol.s | 50 + test/ELF/relocatable-sections.s | 31 + test/ELF/relocatable-symbol-name.s | 28 + test/ELF/relocatable-symbols.s | 201 ++ test/ELF/relocatable-tls.s | 16 + test/ELF/relocatable-visibility.s | 19 + test/ELF/relocatable.s | 120 + test/ELF/relocation-absolute.s | 12 + test/ELF/relocation-common.s | 14 + test/ELF/relocation-copy-alias.s | 67 + test/ELF/relocation-copy-align-common.s | 40 + test/ELF/relocation-copy-align.s | 31 + test/ELF/relocation-copy-flags.s | 73 + test/ELF/relocation-copy-i686.s | 63 + test/ELF/relocation-copy-relro.s | 32 + test/ELF/relocation-copy.s | 67 + test/ELF/relocation-dtrace.test | 24 + test/ELF/relocation-group.test | 43 + test/ELF/relocation-i686.s | 96 + test/ELF/relocation-in-merge.s | 12 + test/ELF/relocation-local.s | 38 + test/ELF/relocation-nocopy.s | 19 + test/ELF/relocation-non-alloc.s | 60 + test/ELF/relocation-none-aarch64.test | 24 + test/ELF/relocation-none-i686.test | 23 + test/ELF/relocation-past-merge-end.s | 9 + test/ELF/relocation-relative-absolute.s | 14 + test/ELF/relocation-relative-synthetic.s | 11 + test/ELF/relocation-relative-weak.s | 14 + test/ELF/relocation-shared.s | 36 + test/ELF/relocation-size-shared.s | 78 + test/ELF/relocation-size.s | 123 + test/ELF/relocation-undefined-weak.s | 27 + test/ELF/relocation.s | 142 + test/ELF/relro-omagic.s | 34 + test/ELF/relro-tls.s | 23 + test/ELF/relro.s | 41 + test/ELF/reproduce-backslash.s | 9 + test/ELF/reproduce-error.s | 14 + test/ELF/reproduce-linkerscript.s | 20 + test/ELF/reproduce-thin-archive.s | 15 + test/ELF/reproduce-windows.s | 12 + test/ELF/reproduce-windows2.s | 10 + test/ELF/reproduce.s | 75 + test/ELF/resolution-end.s | 38 + test/ELF/resolution-shared.s | 15 + test/ELF/resolution.s | 430 +++ test/ELF/retain-symbols-file.s | 74 + test/ELF/retain-und.s | 18 + test/ELF/rodynamic.s | 35 + test/ELF/section-align-0.test | 20 + test/ELF/section-layout.s | 59 + test/ELF/section-metadata-err.s | 15 + test/ELF/section-name.s | 58 + test/ELF/section-symbol.s | 40 + test/ELF/section-symbols.test | 35 + test/ELF/sectionstart-noallochdr.s | 23 + test/ELF/sectionstart.s | 67 + test/ELF/segments.s | 108 + test/ELF/shared-be.s | 37 + test/ELF/shared.s | 305 +++ test/ELF/shf-info-link.test | 32 + test/ELF/sht-group-gold-r.test | 17 + test/ELF/soname.s | 11 + test/ELF/soname2.s | 8 + test/ELF/sort-norosegment.s | 15 + test/ELF/splitstacks.s | 11 + test/ELF/start-lib-comdat.s | 23 + test/ELF/start-lib.s | 25 + test/ELF/startstop-gccollect.s | 34 + test/ELF/startstop-shared.s | 28 + test/ELF/startstop-shared2.s | 14 + test/ELF/startstop.s | 91 + test/ELF/static-with-export-dynamic.s | 32 + test/ELF/string-gc.s | 73 + test/ELF/string-table.s | 27 + test/ELF/strip-all.s | 29 + test/ELF/strip-debug.s | 25 + test/ELF/symbol-ordering-file.s | 44 + test/ELF/symbol-override.s | 46 + test/ELF/symbols.s | 188 ++ test/ELF/symver-archive.s | 15 + test/ELF/synthetic-got.s | 32 + test/ELF/sysroot.s | 38 + test/ELF/tail-merge-string-align.s | 35 + test/ELF/tls-align.s | 21 + test/ELF/tls-archive.s | 10 + test/ELF/tls-dynamic-i686.s | 99 + test/ELF/tls-dynamic.s | 87 + test/ELF/tls-error.s | 12 + test/ELF/tls-got-entry.s | 25 + test/ELF/tls-got.s | 58 + test/ELF/tls-i686.s | 69 + test/ELF/tls-in-archive.s | 11 + test/ELF/tls-initial-exec-local.s | 36 + test/ELF/tls-mismatch.s | 12 + test/ELF/tls-offset.s | 66 + test/ELF/tls-opt-gdie.s | 52 + test/ELF/tls-opt-gdiele-i686.s | 59 + test/ELF/tls-opt-i686.s | 69 + test/ELF/tls-opt-iele-i686-nopic.s | 100 + test/ELF/tls-opt-local.s | 52 + test/ELF/tls-opt-no-plt.s | 34 + test/ELF/tls-opt.s | 99 + test/ELF/tls-relocatable.s | 21 + test/ELF/tls-static.s | 14 + test/ELF/tls-two-relocs.s | 30 + test/ELF/tls-weak-undef.s | 16 + test/ELF/tls.s | 170 ++ test/ELF/trace-ar.s | 21 + test/ELF/trace-symbols.s | 78 + test/ELF/trace.s | 9 + test/ELF/ttext-tdata-tbss.s | 66 + test/ELF/undef-shared.s | 22 + test/ELF/undef-start.s | 3 + test/ELF/undef-version-script.s | 40 + test/ELF/undef-with-plt-addr-i686.s | 23 + test/ELF/undef-with-plt-addr.s | 48 + test/ELF/undef.s | 47 + test/ELF/undefined-opt.s | 68 + test/ELF/undefined-versioned-symbol.s | 74 + test/ELF/unresolved-symbols.s | 65 + test/ELF/user_def_init_array_start.s | 10 + test/ELF/verdef-defaultver.s | 201 ++ test/ELF/verdef-dependency.s | 38 + test/ELF/verdef.s | 119 + test/ELF/verneed-as-needed-weak.s | 14 + test/ELF/verneed-local.s | 9 + test/ELF/verneed.s | 173 ++ test/ELF/version-script-anonymous-local.s | 61 + test/ELF/version-script-complex-wildcards.s | 62 + test/ELF/version-script-copy-rel.s | 24 + test/ELF/version-script-err.s | 11 + test/ELF/version-script-extern-exact.s | 30 + .../version-script-extern-wildcards-anon.s | 74 + test/ELF/version-script-extern-wildcards.s | 29 + test/ELF/version-script-extern.s | 126 + test/ELF/version-script-glob.s | 72 + test/ELF/version-script-hide-so-symbol.s | 28 + test/ELF/version-script-locals-extern.s | 45 + test/ELF/version-script-locals.s | 45 + test/ELF/version-script-missing.s | 7 + test/ELF/version-script-no-warn.s | 12 + test/ELF/version-script-no-warn2.s | 8 + test/ELF/version-script-noundef.s | 23 + test/ELF/version-script-symver.s | 9 + test/ELF/version-script-symver2.s | 28 + test/ELF/version-script-twice.s | 14 + test/ELF/version-script-undef-version.s | 12 + test/ELF/version-script-weak.s | 28 + test/ELF/version-script.s | 226 ++ test/ELF/version-symbol-error.s | 12 + test/ELF/version-undef-sym.s | 42 + test/ELF/version-use.s | 9 + test/ELF/version-wildcard.test | 108 + test/ELF/visibility.s | 129 + test/ELF/warn-common.s | 25 + test/ELF/warn-unresolved-symbols-hidden.s | 14 + test/ELF/warn-unresolved-symbols.s | 51 + test/ELF/weak-and-strong-undef.s | 12 + test/ELF/weak-undef-hidden.s | 29 + test/ELF/weak-undef-shared.s | 19 + test/ELF/weak-undef.s | 21 + test/ELF/whole-archive.s | 40 + test/ELF/wrap-dynamic-undef.s | 15 + test/ELF/wrap.s | 31 + test/ELF/writable-merge.s | 7 + test/ELF/x86-64-dyn-rel-error.s | 12 + test/ELF/x86-64-dyn-rel-error2.s | 14 + test/ELF/x86-64-rela.s | 11 + test/ELF/x86-64-relax-got-abs.s | 16 + test/ELF/x86-64-relax-offset.s | 13 + test/ELF/x86-64-reloc-16.s | 14 + test/ELF/x86-64-reloc-32-fpic.s | 10 + test/ELF/x86-64-reloc-8.s | 14 + test/ELF/x86-64-reloc-error.s | 10 + test/ELF/x86-64-reloc-pc32-fpic.s | 10 + test/ELF/x86-64-reloc-range.s | 13 + test/ELF/x86-64-reloc-tpoff32-fpic.s | 14 + test/ELF/x86-64-tls-gd-got.s | 19 + test/ELF/x86-64-tls-gd-local.s | 52 + test/ELF/x86-64-tls-pie.s | 26 + test/ELF/zdefs.s | 8 + test/ELF/zstack-size.s | 33 + test/ELF/ztext-text-notext.s | 36 + test/Unit/lit.cfg | 23 + test/Unit/lit.site.cfg.in | 25 + test/darwin/Inputs/native-and-mach-o.objtxt | 17 + test/darwin/Inputs/native-and-mach-o2.objtxt | 19 + test/darwin/cmdline-objc_gc.objtxt | 15 + test/darwin/cmdline-objc_gc_compaction.objtxt | 15 + test/darwin/cmdline-objc_gc_only.objtxt | 15 + test/darwin/native-and-mach-o.objtxt | 27 + test/lit.cfg | 270 ++ test/lit.site.cfg.in | 25 + test/mach-o/Inputs/DependencyDump.py | 30 + test/mach-o/Inputs/PIE.yaml | 6 + test/mach-o/Inputs/arm-interworking.yaml | 83 + test/mach-o/Inputs/arm-shims.yaml | 60 + test/mach-o/Inputs/arm64/libSystem.yaml | 13 + test/mach-o/Inputs/armv7/libSystem.yaml | 13 + test/mach-o/Inputs/bar.yaml | 18 + test/mach-o/Inputs/cstring-sections.yaml | 25 + test/mach-o/Inputs/exported_symbols_list.exp | 6 + test/mach-o/Inputs/full.filelist | 3 + test/mach-o/Inputs/got-order.yaml | 53 + test/mach-o/Inputs/got-order2.yaml | 11 + test/mach-o/Inputs/hello-world-arm64.yaml | 8 + test/mach-o/Inputs/hello-world-armv6.yaml | 7 + test/mach-o/Inputs/hello-world-armv7.yaml | 7 + test/mach-o/Inputs/hello-world-x86.yaml | 7 + test/mach-o/Inputs/hello-world-x86_64.yaml | 8 + test/mach-o/Inputs/hw.raw_bytes | 1 + test/mach-o/Inputs/interposing-section.yaml | 6 + test/mach-o/Inputs/lazy-bind-x86_64-2.yaml | 8 + test/mach-o/Inputs/lazy-bind-x86_64-3.yaml | 8 + test/mach-o/Inputs/lazy-bind-x86_64.yaml | 8 + .../usr/lib/libmyshared.dylib | Bin 0 -> 20628 bytes .../lib-search-paths/usr/lib/libmystatic.a | Bin 0 -> 556 bytes .../lib-search-paths/usr/local/lib/file.o | Bin 0 -> 404 bytes test/mach-o/Inputs/libbar.a | Bin 0 -> 824 bytes test/mach-o/Inputs/libfoo.a | Bin 0 -> 1320 bytes test/mach-o/Inputs/linker-as-ld.yaml | 6 + .../no-version-min-load-command-object.yaml | 22 + test/mach-o/Inputs/order_file-basic.order | 11 + test/mach-o/Inputs/partial.filelist | 3 + .../Inputs/re-exported-dylib-ordinal.yaml | 21 + .../Inputs/re-exported-dylib-ordinal2.yaml | 18 + .../Inputs/re-exported-dylib-ordinal3.yaml | 19 + test/mach-o/Inputs/swift-version-1.yaml | 18 + .../Inputs/unwind-info-simple-arm64.yaml | 13 + .../Inputs/use-dylib-install-names.yaml | 28 + test/mach-o/Inputs/use-simple-dylib.yaml | 58 + test/mach-o/Inputs/write-final-sections.yaml | 20 + test/mach-o/Inputs/wrong-arch-error.yaml | 24 + test/mach-o/Inputs/x86/libSystem.yaml | 13 + test/mach-o/Inputs/x86_64/libSystem.yaml | 13 + test/mach-o/PIE.yaml | 40 + test/mach-o/align_text.yaml | 45 + test/mach-o/arm-interworking-movw.yaml | 393 +++ test/mach-o/arm-interworking.yaml | 288 ++ test/mach-o/arm-shims.yaml | 126 + test/mach-o/arm-subsections-via-symbols.yaml | 60 + test/mach-o/arm64-reloc-negDelta32-fixup.yaml | 124 + .../arm64-relocs-errors-delta64-offset.yaml | 65 + test/mach-o/arm64-section-order.yaml | 67 + test/mach-o/bind-opcodes.yaml | 143 + test/mach-o/cstring-sections.yaml | 65 + test/mach-o/data-in-code-load-command.yaml | 35 + test/mach-o/data-only-dylib.yaml | 27 + test/mach-o/dead-strip-globals.yaml | 31 + test/mach-o/debug-syms.yaml | 249 ++ test/mach-o/demangle.yaml | 74 + test/mach-o/dependency_info.yaml | 19 + test/mach-o/do-not-emit-unwind-fde-arm64.yaml | 208 ++ test/mach-o/dso_handle.yaml | 62 + test/mach-o/dylib-install-names.yaml | 74 + test/mach-o/eh-frame-relocs-arm64.yaml | 318 +++ test/mach-o/error-simulator-vs-macosx.yaml | 30 + test/mach-o/exe-offsets.yaml | 45 + test/mach-o/exe-segment-overlap.yaml | 44 + test/mach-o/executable-exports.yaml | 46 + test/mach-o/export-trie-order.yaml | 62 + 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/flat_namespace_undef_error.yaml | 17 + .../mach-o/flat_namespace_undef_suppress.yaml | 17 + 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/function-starts-load-command.yaml | 32 + test/mach-o/gcc_except_tab-got-arm64.yaml | 53 + test/mach-o/got-order.yaml | 69 + test/mach-o/hello-world-arm64.yaml | 102 + test/mach-o/hello-world-armv6.yaml | 64 + test/mach-o/hello-world-armv7.yaml | 76 + test/mach-o/hello-world-x86.yaml | 62 + test/mach-o/hello-world-x86_64.yaml | 120 + test/mach-o/image-base.yaml | 28 + test/mach-o/infer-arch.yaml | 29 + test/mach-o/interposing-section.yaml | 72 + test/mach-o/keep_private_externs.yaml | 63 + test/mach-o/lazy-bind-x86_64.yaml | 111 + test/mach-o/lc_segment_filesize.yaml | 31 + test/mach-o/lib-search-paths.yaml | 16 + test/mach-o/library-order.yaml | 45 + test/mach-o/library-rescan.yaml | 46 + .../libresolve-bizarre-root-override.yaml | 17 + .../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 | 32 + test/mach-o/lit.local.cfg | 4 + test/mach-o/mach_header-cpusubtype.yaml | 34 + test/mach-o/mh_bundle_header.yaml | 54 + test/mach-o/mh_dylib_header.yaml | 53 + test/mach-o/objc-category-list-atom.yaml | 70 + .../objc-image-info-host-vs-simulator.yaml | 23 + test/mach-o/objc-image-info-invalid-size.yaml | 20 + .../objc-image-info-invalid-version.yaml | 20 + ...c-image-info-mismatched-swift-version.yaml | 20 + test/mach-o/objc-image-info-pass-output.yaml | 30 + .../objc-image-info-simulator-vs-host.yaml | 23 + .../objc-image-info-unsupported-gc.yaml | 20 + 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 | 244 ++ test/mach-o/parse-data-relocs-x86_64.yaml | 372 +++ test/mach-o/parse-data.yaml | 119 + test/mach-o/parse-eh-frame-relocs-x86_64.yaml | 176 ++ 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 | 204 ++ test/mach-o/parse-tlv-relocs-x86-64.yaml | 100 + test/mach-o/re-exported-dylib-ordinal.yaml | 46 + test/mach-o/rpath.yaml | 38 + test/mach-o/run-tlv-pass-x86-64.yaml | 144 + test/mach-o/sdk-version-error.yaml | 22 + test/mach-o/sectalign.yaml | 80 + test/mach-o/sectattrs.yaml | 30 + test/mach-o/sectcreate.yaml | 12 + test/mach-o/seg-protection-arm64.yaml | 78 + test/mach-o/seg-protection-x86_64.yaml | 78 + test/mach-o/source-version.yaml | 28 + test/mach-o/stack-size.yaml | 24 + test/mach-o/string-table.yaml | 66 + .../subsections-via-symbols-default.yaml | 28 + ...olevel_namespace_undef_dynamic_lookup.yaml | 17 + ...evel_namespace_undef_warning_suppress.yaml | 23 + test/mach-o/unwind-info-simple-arm64.yaml | 267 ++ test/mach-o/unwind-info-simple-x86_64.yaml | 133 + 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-dylib.yaml | 39 + test/mach-o/use-simple-dylib.yaml | 73 + .../version-min-load-command-object.yaml | 35 + test/mach-o/version-min-load-command.yaml | 43 + test/mach-o/write-final-sections.yaml | 165 ++ test/mach-o/wrong-arch-error.yaml | 28 + tools/lld/CMakeLists.txt | 24 + tools/lld/lld.cpp | 113 + unittests/CMakeLists.txt | 16 + unittests/DriverTests/CMakeLists.txt | 8 + unittests/DriverTests/DarwinLdDriverTest.cpp | 267 ++ unittests/MachOTests/CMakeLists.txt | 13 + .../MachONormalizedFileBinaryReaderTests.cpp | 749 +++++ .../MachONormalizedFileBinaryWriterTests.cpp | 696 +++++ .../MachONormalizedFileToAtomsTests.cpp | 100 + .../MachONormalizedFileYAMLTests.cpp | 763 ++++++ unittests/MachOTests/empty_obj_x86_armv7.txt | 1272 +++++++++ 1759 files changed, 126250 insertions(+) create mode 100644 .arcconfig create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CODE_OWNERS.TXT create mode 100644 COFF/CMakeLists.txt create mode 100644 COFF/Chunks.cpp create mode 100644 COFF/Chunks.h create mode 100644 COFF/Config.h create mode 100644 COFF/DLL.cpp create mode 100644 COFF/DLL.h create mode 100644 COFF/Driver.cpp create mode 100644 COFF/Driver.h create mode 100644 COFF/DriverUtils.cpp create mode 100644 COFF/Error.cpp create mode 100644 COFF/Error.h create mode 100644 COFF/ICF.cpp create mode 100644 COFF/InputFiles.cpp create mode 100644 COFF/InputFiles.h create mode 100644 COFF/LTO.cpp create mode 100644 COFF/LTO.h create mode 100644 COFF/MapFile.cpp create mode 100644 COFF/MapFile.h create mode 100644 COFF/MarkLive.cpp create mode 100644 COFF/Memory.h create mode 100644 COFF/Options.td create mode 100644 COFF/PDB.cpp create mode 100644 COFF/PDB.h create mode 100644 COFF/README.md create mode 100644 COFF/Strings.cpp create mode 100644 COFF/Strings.h create mode 100644 COFF/SymbolTable.cpp create mode 100644 COFF/SymbolTable.h create mode 100644 COFF/Symbols.cpp create mode 100644 COFF/Symbols.h create mode 100644 COFF/Writer.cpp create mode 100644 COFF/Writer.h create mode 100644 ELF/Arch/AArch64.cpp create mode 100644 ELF/Arch/AMDGPU.cpp create mode 100644 ELF/Arch/ARM.cpp create mode 100644 ELF/Arch/AVR.cpp create mode 100644 ELF/Arch/Mips.cpp create mode 100644 ELF/Arch/MipsArchTree.cpp create mode 100644 ELF/Arch/PPC.cpp create mode 100644 ELF/Arch/PPC64.cpp create mode 100644 ELF/Arch/SPARCV9.cpp create mode 100644 ELF/Arch/X86.cpp create mode 100644 ELF/Arch/X86_64.cpp create mode 100644 ELF/CMakeLists.txt create mode 100644 ELF/Config.h create mode 100644 ELF/Driver.cpp create mode 100644 ELF/Driver.h create mode 100644 ELF/DriverUtils.cpp create mode 100644 ELF/EhFrame.cpp create mode 100644 ELF/EhFrame.h create mode 100644 ELF/Error.cpp create mode 100644 ELF/Error.h create mode 100644 ELF/Filesystem.cpp create mode 100644 ELF/Filesystem.h create mode 100644 ELF/GdbIndex.cpp create mode 100644 ELF/GdbIndex.h create mode 100644 ELF/ICF.cpp create mode 100644 ELF/ICF.h create mode 100644 ELF/InputFiles.cpp create mode 100644 ELF/InputFiles.h create mode 100644 ELF/InputSection.cpp create mode 100644 ELF/InputSection.h create mode 100644 ELF/LTO.cpp create mode 100644 ELF/LTO.h create mode 100644 ELF/LinkerScript.cpp create mode 100644 ELF/LinkerScript.h create mode 100644 ELF/MapFile.cpp create mode 100644 ELF/MapFile.h create mode 100644 ELF/MarkLive.cpp create mode 100644 ELF/Memory.h create mode 100644 ELF/Options.td create mode 100644 ELF/OutputSections.cpp create mode 100644 ELF/OutputSections.h create mode 100644 ELF/README.md create mode 100644 ELF/Relocations.cpp create mode 100644 ELF/Relocations.h create mode 100644 ELF/ScriptLexer.cpp create mode 100644 ELF/ScriptLexer.h create mode 100644 ELF/ScriptParser.cpp create mode 100644 ELF/ScriptParser.h create mode 100644 ELF/Strings.cpp create mode 100644 ELF/Strings.h create mode 100644 ELF/SymbolTable.cpp create mode 100644 ELF/SymbolTable.h create mode 100644 ELF/Symbols.cpp create mode 100644 ELF/Symbols.h create mode 100644 ELF/SyntheticSections.cpp create mode 100644 ELF/SyntheticSections.h create mode 100644 ELF/Target.cpp create mode 100644 ELF/Target.h create mode 100644 ELF/Threads.h create mode 100644 ELF/Thunks.cpp create mode 100644 ELF/Thunks.h create mode 100644 ELF/Writer.cpp create mode 100644 ELF/Writer.h create mode 100644 LICENSE.TXT create mode 100644 README.md create mode 100644 cmake/modules/AddLLD.cmake create mode 100644 cmake/modules/FindVTune.cmake create mode 100644 docs/AtomLLD.rst create mode 100644 docs/CMakeLists.txt create mode 100644 docs/Driver.rst create mode 100644 docs/NewLLD.rst create mode 100644 docs/README.txt create mode 100644 docs/Readers.rst create mode 100644 docs/ReleaseNotes.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/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/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/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/Reproduce.h create mode 100644 include/lld/Core/Resolver.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/TargetOptionsCommandFlags.h create mode 100644 include/lld/Core/UndefinedAtom.h create mode 100644 include/lld/Core/Writer.h create mode 100644 include/lld/Driver/Driver.h create mode 100644 include/lld/ReaderWriter/MachOLinkingContext.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/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/Reader.cpp create mode 100644 lib/Core/Reproduce.cpp create mode 100644 lib/Core/Resolver.cpp create mode 100644 lib/Core/SymbolTable.cpp create mode 100644 lib/Core/TargetOptionsCommandFlags.cpp create mode 100644 lib/Core/Writer.cpp create mode 100644 lib/Driver/CMakeLists.txt create mode 100644 lib/Driver/DarwinLdDriver.cpp create mode 100644 lib/Driver/DarwinLdOptions.td create mode 100644 lib/ReaderWriter/CMakeLists.txt create mode 100644 lib/ReaderWriter/FileArchive.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/DebugInfo.h create mode 100644 lib/ReaderWriter/MachO/ExecutableAtoms.h create mode 100644 lib/ReaderWriter/MachO/File.h create mode 100644 lib/ReaderWriter/MachO/FlatNamespaceFile.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/ObjCPass.cpp create mode 100644 lib/ReaderWriter/MachO/SectCreateFile.h create mode 100644 lib/ReaderWriter/MachO/ShimPass.cpp create mode 100644 lib/ReaderWriter/MachO/StubsPass.cpp create mode 100644 lib/ReaderWriter/MachO/TLVPass.cpp create mode 100644 lib/ReaderWriter/MachO/WriterMachO.cpp create mode 100644 lib/ReaderWriter/YAML/CMakeLists.txt create mode 100644 lib/ReaderWriter/YAML/ReaderWriterYAML.cpp create mode 100644 test/CMakeLists.txt create mode 100644 test/COFF/Inputs/armnt-executable.obj.yaml create mode 100644 test/COFF/Inputs/armnt-executable.s create mode 100644 test/COFF/Inputs/associative-comdat-2.s create mode 100644 test/COFF/Inputs/bar.ll create mode 100755 test/COFF/Inputs/cl-gl.obj create mode 100644 test/COFF/Inputs/combined-resources-2.rc create mode 100644 test/COFF/Inputs/combined-resources-2.res create mode 100644 test/COFF/Inputs/combined-resources-cursor.bmp create mode 100644 test/COFF/Inputs/combined-resources-okay.bmp create mode 100644 test/COFF/Inputs/combined-resources.rc create mode 100644 test/COFF/Inputs/combined-resources.res create mode 100644 test/COFF/Inputs/conflict.ll create mode 100644 test/COFF/Inputs/constant-export.ll create mode 100644 test/COFF/Inputs/constant-import.s create mode 100644 test/COFF/Inputs/default.def create mode 100644 test/COFF/Inputs/delayimports-error.yaml create mode 100644 test/COFF/Inputs/entry-mangled.ll create mode 100644 test/COFF/Inputs/export.ll create mode 100644 test/COFF/Inputs/export.yaml create mode 100644 test/COFF/Inputs/export2.yaml create mode 100644 test/COFF/Inputs/extension.def create mode 100644 test/COFF/Inputs/far-arm-thumb-abs.s create mode 100644 test/COFF/Inputs/hello32.yaml create mode 100644 test/COFF/Inputs/hello64.asm create mode 100644 test/COFF/Inputs/hello64.obj create mode 100644 test/COFF/Inputs/import.yaml create mode 100644 test/COFF/Inputs/imports-mangle.lib create mode 100644 test/COFF/Inputs/include1a.yaml create mode 100644 test/COFF/Inputs/include1b.yaml create mode 100644 test/COFF/Inputs/include1c.yaml create mode 100644 test/COFF/Inputs/library-arm64.lib create mode 100644 test/COFF/Inputs/library.def create mode 100755 test/COFF/Inputs/library.lib create mode 100644 test/COFF/Inputs/lto-chkstk-chkstk.s create mode 100644 test/COFF/Inputs/lto-chkstk-foo.s create mode 100644 test/COFF/Inputs/lto-comdat1.ll create mode 100644 test/COFF/Inputs/lto-comdat2.ll create mode 100644 test/COFF/Inputs/lto-dep.ll create mode 100644 test/COFF/Inputs/lto-lazy-reference-dummy.ll create mode 100644 test/COFF/Inputs/lto-lazy-reference-quadruple.ll create mode 100644 test/COFF/Inputs/machine-x64.yaml create mode 100644 test/COFF/Inputs/machine-x86.yaml create mode 100644 test/COFF/Inputs/manifestinput.test create mode 100644 test/COFF/Inputs/msvclto-order-a.ll create mode 100644 test/COFF/Inputs/msvclto-order-b.ll create mode 100644 test/COFF/Inputs/msvclto.s create mode 100644 test/COFF/Inputs/named.def create mode 100644 test/COFF/Inputs/object.s create mode 100644 test/COFF/Inputs/oldname.yaml create mode 100644 test/COFF/Inputs/pdb-diff-cl.pdb create mode 100644 test/COFF/Inputs/pdb-diff.cpp create mode 100644 test/COFF/Inputs/pdb-diff.obj create mode 100644 test/COFF/Inputs/pdb-global-gc.s create mode 100644 test/COFF/Inputs/pdb-import-gc.lib create mode 100644 test/COFF/Inputs/pdb-scopes-a.yaml create mode 100644 test/COFF/Inputs/pdb-scopes-b.yaml create mode 100644 test/COFF/Inputs/pdb-type-server-simple-a.yaml create mode 100644 test/COFF/Inputs/pdb-type-server-simple-b.yaml create mode 100644 test/COFF/Inputs/pdb-type-server-simple-ts.yaml create mode 100644 test/COFF/Inputs/pdb1.yaml create mode 100644 test/COFF/Inputs/pdb2.yaml create mode 100644 test/COFF/Inputs/pdb_comdat_bar.yaml create mode 100644 test/COFF/Inputs/pdb_comdat_main.yaml create mode 100644 test/COFF/Inputs/pdb_lines_1.yaml create mode 100644 test/COFF/Inputs/pdb_lines_2.yaml create mode 100644 test/COFF/Inputs/resource.res create mode 100644 test/COFF/Inputs/ret42.lib create mode 100644 test/COFF/Inputs/ret42.obj create mode 100644 test/COFF/Inputs/ret42.yaml create mode 100644 test/COFF/Inputs/std32.lib create mode 100644 test/COFF/Inputs/std64.lib create mode 100644 test/COFF/Inputs/thinlto-mangled-qux.ll create mode 100644 test/COFF/Inputs/weak-external.ll create mode 100644 test/COFF/Inputs/weak-external2.ll create mode 100644 test/COFF/Inputs/weak-external3.ll create mode 100644 test/COFF/alternatename.test create mode 100644 test/COFF/ar-comdat.test create mode 100644 test/COFF/arm-thumb-branch-error.s create mode 100644 test/COFF/arm64-magic.yaml create mode 100644 test/COFF/arm64-relocs-imports.test create mode 100644 test/COFF/armnt-blx23t.test create mode 100644 test/COFF/armnt-branch24t.test create mode 100644 test/COFF/armnt-entry-point.test create mode 100644 test/COFF/armnt-imports.test create mode 100644 test/COFF/armnt-mov32t-exec.test create mode 100644 test/COFF/armnt-movt32t.test create mode 100644 test/COFF/associative-comdat.s create mode 100644 test/COFF/base.test create mode 100644 test/COFF/baserel.test create mode 100644 test/COFF/cl-gl.test create mode 100644 test/COFF/combined-resources.test create mode 100644 test/COFF/common.test create mode 100644 test/COFF/conflict-mangled.test create mode 100644 test/COFF/conflict.test create mode 100644 test/COFF/constant-export.test create mode 100644 test/COFF/constant.test create mode 100644 test/COFF/debug.test create mode 100644 test/COFF/def-export-stdcall.s create mode 100644 test/COFF/def-name.test create mode 100644 test/COFF/defparser.test create mode 100644 test/COFF/delayimports-error.test create mode 100644 test/COFF/delayimports.test create mode 100644 test/COFF/delayimports32.test create mode 100644 test/COFF/dll.test create mode 100644 test/COFF/dllimport-gc.test create mode 100644 test/COFF/driver-windows.test create mode 100644 test/COFF/driver.test create mode 100644 test/COFF/entry-inference.test create mode 100644 test/COFF/entry-inference2.test create mode 100644 test/COFF/entry-inference32.test create mode 100644 test/COFF/entry-mangled.test create mode 100644 test/COFF/entrylib.ll create mode 100644 test/COFF/error-limit.test create mode 100644 test/COFF/export-exe.test create mode 100644 test/COFF/export.test create mode 100644 test/COFF/export32.test create mode 100644 test/COFF/failifmismatch.test create mode 100644 test/COFF/filetype.test create mode 100644 test/COFF/force.test create mode 100644 test/COFF/guardcf.test create mode 100644 test/COFF/heap.test create mode 100644 test/COFF/hello32.test create mode 100644 test/COFF/help.test create mode 100644 test/COFF/icf-associative.test create mode 100644 test/COFF/icf-circular.test create mode 100644 test/COFF/icf-circular2.test create mode 100644 test/COFF/icf-data.test create mode 100644 test/COFF/icf-different-align.test create mode 100644 test/COFF/icf-local.test create mode 100644 test/COFF/icf-simple.test create mode 100644 test/COFF/implib-name.test create mode 100644 test/COFF/imports-mangle.test create mode 100644 test/COFF/imports.test create mode 100644 test/COFF/include-lto.ll create mode 100644 test/COFF/include.test create mode 100644 test/COFF/include2.test create mode 100644 test/COFF/internal.test create mode 100644 test/COFF/invalid-debug-type.test create mode 100644 test/COFF/invalid-obj.test create mode 100644 test/COFF/largeaddressaware.test create mode 100644 test/COFF/lib.test create mode 100644 test/COFF/libpath.test create mode 100644 test/COFF/linkenv.test create mode 100644 test/COFF/linkrepro.test create mode 100644 test/COFF/lldmap.test create mode 100644 test/COFF/loadcfg.ll create mode 100644 test/COFF/loadcfg.test create mode 100644 test/COFF/loadcfg32.test create mode 100644 test/COFF/locally-imported.test create mode 100644 test/COFF/locally-imported32.test create mode 100644 test/COFF/long-section-name.test create mode 100644 test/COFF/lto-chkstk.ll create mode 100644 test/COFF/lto-comdat.ll create mode 100644 test/COFF/lto-debug-pass-arguments.ll create mode 100644 test/COFF/lto-lazy-reference.ll create mode 100644 test/COFF/lto-linker-opts.ll create mode 100644 test/COFF/lto-new-symbol.ll create mode 100644 test/COFF/lto-opt-level.ll create mode 100644 test/COFF/lto-parallel.ll create mode 100644 test/COFF/lto.ll create mode 100644 test/COFF/machine.test create mode 100644 test/COFF/manifest.test create mode 100644 test/COFF/manifestinput.test create mode 100644 test/COFF/merge.test create mode 100644 test/COFF/msvclto-archive.ll create mode 100644 test/COFF/msvclto-order.ll create mode 100644 test/COFF/msvclto.ll create mode 100644 test/COFF/nodefaultlib.test create mode 100644 test/COFF/noentry.test create mode 100644 test/COFF/nopdb.test create mode 100644 test/COFF/opt.test create mode 100644 test/COFF/options.test create mode 100644 test/COFF/order.test create mode 100644 test/COFF/out.test create mode 100644 test/COFF/pdb-comdat.test create mode 100644 test/COFF/pdb-diff.test create mode 100644 test/COFF/pdb-global-gc.yaml create mode 100644 test/COFF/pdb-import-gc.yaml create mode 100644 test/COFF/pdb-invalid-func-type.yaml create mode 100644 test/COFF/pdb-lib.s create mode 100644 test/COFF/pdb-linker-module.test create mode 100644 test/COFF/pdb-none.test create mode 100644 test/COFF/pdb-options.test create mode 100644 test/COFF/pdb-safeseh.yaml create mode 100644 test/COFF/pdb-scopes.test create mode 100644 test/COFF/pdb-secrel-absolute.yaml create mode 100644 test/COFF/pdb-source-lines.test create mode 100644 test/COFF/pdb-symbol-types.yaml create mode 100644 test/COFF/pdb-type-server-missing.yaml create mode 100644 test/COFF/pdb-type-server-simple.test create mode 100644 test/COFF/pdb.test create mode 100644 test/COFF/reloc-arm.test create mode 100644 test/COFF/reloc-discarded-dwarf.s create mode 100644 test/COFF/reloc-discarded.s create mode 100644 test/COFF/reloc-oob.yaml create mode 100644 test/COFF/reloc-x64.test create mode 100644 test/COFF/reloc-x86.test create mode 100644 test/COFF/resource.test create mode 100644 test/COFF/responsefile.test create mode 100644 test/COFF/rsds.test create mode 100644 test/COFF/safeseh-diag-feat.test create mode 100644 test/COFF/safeseh.s create mode 100644 test/COFF/savetemps.ll create mode 100644 test/COFF/secidx-absolute.s create mode 100644 test/COFF/secrel-absolute.s create mode 100644 test/COFF/secrel-common.s create mode 100644 test/COFF/section.test create mode 100644 test/COFF/seh.test create mode 100644 test/COFF/sort-debug.test create mode 100644 test/COFF/stack.test create mode 100644 test/COFF/subsystem-inference.test create mode 100644 test/COFF/subsystem.test create mode 100644 test/COFF/symtab.test create mode 100644 test/COFF/thinlto-archives.ll create mode 100644 test/COFF/thinlto-mangled.ll create mode 100644 test/COFF/thinlto.ll create mode 100644 test/COFF/tls.test create mode 100644 test/COFF/tls32.test create mode 100644 test/COFF/unwind.test create mode 100644 test/COFF/version.test create mode 100644 test/COFF/weak-external.test create mode 100644 test/COFF/weak-external2.test create mode 100644 test/COFF/weak-external3.test create mode 100644 test/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/ELF/Inputs/aarch64-condb-reloc.s create mode 100644 test/ELF/Inputs/aarch64-copy2.s create mode 100644 test/ELF/Inputs/aarch64-tls-gdie.s create mode 100644 test/ELF/Inputs/aarch64-tls-ie.s create mode 100644 test/ELF/Inputs/aarch64-tstbr14-reloc.s create mode 100644 test/ELF/Inputs/abs-hidden.s create mode 100644 test/ELF/Inputs/abs.s create mode 100644 test/ELF/Inputs/abs255.s create mode 100644 test/ELF/Inputs/abs256.s create mode 100644 test/ELF/Inputs/abs257.s create mode 100644 test/ELF/Inputs/allow-multiple-definition.s create mode 100644 test/ELF/Inputs/allow-shlib-undefined.s create mode 100644 test/ELF/Inputs/archive.s create mode 100644 test/ELF/Inputs/archive2.s create mode 100644 test/ELF/Inputs/archive3.s create mode 100644 test/ELF/Inputs/archive4.s create mode 100644 test/ELF/Inputs/arm-attributes1.s create mode 100644 test/ELF/Inputs/arm-exidx-cantunwind.s create mode 100644 test/ELF/Inputs/arm-plt-reloc.s create mode 100644 test/ELF/Inputs/arm-shared.s create mode 100644 test/ELF/Inputs/arm-thumb-blx-targets.s create mode 100644 test/ELF/Inputs/arm-thumb-narrow-branch.o create mode 100644 test/ELF/Inputs/arm-thumb-narrow-branch.s create mode 100644 test/ELF/Inputs/arm-tls-get-addr.s create mode 100644 test/ELF/Inputs/bad-archive.a create mode 100644 test/ELF/Inputs/comdat.s create mode 100644 test/ELF/Inputs/comment-gc.s create mode 100644 test/ELF/Inputs/common.s create mode 100644 test/ELF/Inputs/conflict-debug.s create mode 100644 test/ELF/Inputs/conflict.s create mode 100644 test/ELF/Inputs/copy-in-shared.s create mode 100644 test/ELF/Inputs/copy-rel-corrupted.s create mode 100644 test/ELF/Inputs/copy-rel-pie.s create mode 100644 test/ELF/Inputs/ctors_dtors_priority1.s create mode 100644 test/ELF/Inputs/ctors_dtors_priority2.s create mode 100644 test/ELF/Inputs/ctors_dtors_priority3.s create mode 100644 test/ELF/Inputs/discard-merge-unnamed.o create mode 100644 test/ELF/Inputs/dso-undef-size.s create mode 100644 test/ELF/Inputs/dtrace-r.o create mode 100644 test/ELF/Inputs/duplicated-plt-entry.s create mode 100644 test/ELF/Inputs/dynamic-reloc-weak.s create mode 100644 test/ELF/Inputs/dynamic-reloc.s create mode 100644 test/ELF/Inputs/eh-frame-end.s create mode 100644 test/ELF/Inputs/ehframe-relocation.s create mode 100644 test/ELF/Inputs/empty-ver.ver create mode 100644 test/ELF/Inputs/exclude-libs.s create mode 100644 test/ELF/Inputs/far-arm-abs.s create mode 100644 test/ELF/Inputs/far-arm-thumb-abs.s create mode 100644 test/ELF/Inputs/gc-sections-weak.s create mode 100644 test/ELF/Inputs/gdb-index.s create mode 100644 test/ELF/Inputs/gnu-ifunc-dso.s create mode 100644 test/ELF/Inputs/gnu-ifunc-gotpcrel.s create mode 100644 test/ELF/Inputs/gotpc-relax-und-dso.s create mode 100644 test/ELF/Inputs/i386-got32x-baseless.elf create mode 100644 test/ELF/Inputs/i386-reloc-16-error.s create mode 100644 test/ELF/Inputs/i386-reloc-16.s create mode 100644 test/ELF/Inputs/i386-reloc-8-error.s create mode 100644 test/ELF/Inputs/i386-reloc-8.s create mode 100644 test/ELF/Inputs/i386-tls-got.s create mode 100644 test/ELF/Inputs/icf-absolute.s create mode 100644 test/ELF/Inputs/icf-merge-sec.s create mode 100644 test/ELF/Inputs/icf-merge.s create mode 100644 test/ELF/Inputs/icf-merge2.s create mode 100644 test/ELF/Inputs/icf-merge3.s create mode 100644 test/ELF/Inputs/icf-non-mergeable.s create mode 100644 test/ELF/Inputs/icf2.s create mode 100644 test/ELF/Inputs/libsearch-dyn.s create mode 100644 test/ELF/Inputs/libsearch-st.s create mode 100644 test/ELF/Inputs/llvm33-rela-outside-group.o create mode 100644 test/ELF/Inputs/map-file2.s create mode 100644 test/ELF/Inputs/map-file3.s create mode 100644 test/ELF/Inputs/map-file4.s create mode 100644 test/ELF/Inputs/merge.s create mode 100644 test/ELF/Inputs/mips-align-err.s create mode 100644 test/ELF/Inputs/mips-concatenated-abiflags.o create mode 100644 test/ELF/Inputs/mips-dynamic.s create mode 100644 test/ELF/Inputs/mips-fnpic.s create mode 100644 test/ELF/Inputs/mips-fpic.s create mode 100644 test/ELF/Inputs/mips-gp-disp.so create mode 100755 test/ELF/Inputs/mips-gp0-non-zero.o create mode 100644 test/ELF/Inputs/mips-n32-rels.o create mode 100644 test/ELF/Inputs/mips-nonalloc.s create mode 100644 test/ELF/Inputs/mips-options.o create mode 100644 test/ELF/Inputs/mips-pic.s create mode 100644 test/ELF/Inputs/mips-tls.s create mode 100644 test/ELF/Inputs/no-symtab.o create mode 100644 test/ELF/Inputs/plt-aarch64.s create mode 100644 test/ELF/Inputs/ppc64-addr16-error.s create mode 100644 test/ELF/Inputs/progname-ver.s create mode 100644 test/ELF/Inputs/protected-shared.s create mode 100644 test/ELF/Inputs/relocatable-comdat-multiple.s create mode 100644 test/ELF/Inputs/relocatable-ehframe.s create mode 100644 test/ELF/Inputs/relocatable-non-alloc.s create mode 100644 test/ELF/Inputs/relocatable-tls.s create mode 100644 test/ELF/Inputs/relocatable.s create mode 100644 test/ELF/Inputs/relocatable2.s create mode 100644 test/ELF/Inputs/relocation-copy-alias.s create mode 100644 test/ELF/Inputs/relocation-copy-align-common.s create mode 100644 test/ELF/Inputs/relocation-copy-align.s create mode 100644 test/ELF/Inputs/relocation-copy-arm.s create mode 100644 test/ELF/Inputs/relocation-copy-relro.s create mode 100644 test/ELF/Inputs/relocation-copy.s create mode 100644 test/ELF/Inputs/relocation-relative-absolute.s create mode 100644 test/ELF/Inputs/relocation-size-shared.s create mode 100644 test/ELF/Inputs/resolution-end.s create mode 100644 test/ELF/Inputs/resolution-shared.s create mode 100644 test/ELF/Inputs/resolution.s create mode 100644 test/ELF/Inputs/rodynamic.s create mode 100644 test/ELF/Inputs/shared-ppc64.s create mode 100644 test/ELF/Inputs/shared.s create mode 100644 test/ELF/Inputs/shared2-x86-64.s create mode 100644 test/ELF/Inputs/shared2.s create mode 100644 test/ELF/Inputs/shared3.s create mode 100644 test/ELF/Inputs/shf-info-link.test create mode 100644 test/ELF/Inputs/sht-group-gold-r.elf create mode 100644 test/ELF/Inputs/sht-group-gold-r.s create mode 100644 test/ELF/Inputs/start-lib-comdat.s create mode 100644 test/ELF/Inputs/start-lib1.s create mode 100644 test/ELF/Inputs/start-lib2.s create mode 100644 test/ELF/Inputs/startstop-shared2.s create mode 100644 test/ELF/Inputs/symbol-override.s create mode 100644 test/ELF/Inputs/symver-archive1.s create mode 100644 test/ELF/Inputs/symver-archive2.s create mode 100644 test/ELF/Inputs/tls-got-entry.s create mode 100644 test/ELF/Inputs/tls-got.s create mode 100644 test/ELF/Inputs/tls-in-archive.s create mode 100644 test/ELF/Inputs/tls-mismatch.s create mode 100644 test/ELF/Inputs/tls-opt-gdie.s create mode 100644 test/ELF/Inputs/tls-opt-gdiele-i686.s create mode 100644 test/ELF/Inputs/tls-opt-iele-i686-nopic.s create mode 100644 test/ELF/Inputs/trace-ar1.s create mode 100644 test/ELF/Inputs/trace-ar2.s create mode 100644 test/ELF/Inputs/trace-symbols-foo-strong.s create mode 100644 test/ELF/Inputs/trace-symbols-foo-weak.s create mode 100644 test/ELF/Inputs/uabs_label.s create mode 100644 test/ELF/Inputs/undef-debug.s create mode 100644 test/ELF/Inputs/undef-with-plt-addr.s create mode 100644 test/ELF/Inputs/undef.s create mode 100644 test/ELF/Inputs/unknown-reloc.s create mode 100644 test/ELF/Inputs/unresolved-symbols.s create mode 100644 test/ELF/Inputs/use-bar.s create mode 100644 test/ELF/Inputs/verdef-defaultver.s create mode 100644 test/ELF/Inputs/verdef.s create mode 100755 test/ELF/Inputs/verneed.so.sh create mode 100755 test/ELF/Inputs/verneed1.so create mode 100755 test/ELF/Inputs/verneed2.so create mode 100644 test/ELF/Inputs/version-script-err.script create mode 100644 test/ELF/Inputs/version-script-no-warn2.s create mode 100644 test/ELF/Inputs/version-script-weak.s create mode 100755 test/ELF/Inputs/version-undef-sym.so create mode 100644 test/ELF/Inputs/version-use.script create mode 100755 test/ELF/Inputs/version-use.so create mode 100644 test/ELF/Inputs/visibility.s create mode 100644 test/ELF/Inputs/warn-common.s create mode 100644 test/ELF/Inputs/warn-common2.s create mode 100644 test/ELF/Inputs/weak-and-strong-undef.s create mode 100644 test/ELF/Inputs/whole-archive.s create mode 100644 test/ELF/Inputs/wrap-dynamic-undef.s create mode 100644 test/ELF/Inputs/wrap.s create mode 100644 test/ELF/Inputs/x86-64-relax-offset.s create mode 100644 test/ELF/Inputs/x86-64-reloc-16-error.s create mode 100644 test/ELF/Inputs/x86-64-reloc-16.s create mode 100644 test/ELF/Inputs/x86-64-reloc-8-error.s create mode 100644 test/ELF/Inputs/x86-64-reloc-8.s create mode 100644 test/ELF/Inputs/x86-64-reloc-error.s create mode 100644 test/ELF/Inputs/x86-64-tls-gd-got.s create mode 100644 test/ELF/Inputs/ztext-text-notext.s create mode 100644 test/ELF/aarch64-abs16.s create mode 100644 test/ELF/aarch64-abs32.s create mode 100644 test/ELF/aarch64-abs64-dyn.s create mode 100644 test/ELF/aarch64-call26-error.s create mode 100644 test/ELF/aarch64-condb-reloc.s create mode 100644 test/ELF/aarch64-copy.s create mode 100644 test/ELF/aarch64-copy2.s create mode 100644 test/ELF/aarch64-data-relocs.s create mode 100644 test/ELF/aarch64-fpic-abs16.s create mode 100644 test/ELF/aarch64-fpic-add_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-adr_prel_lo21.s create mode 100644 test/ELF/aarch64-fpic-adr_prel_pg_hi21.s create mode 100644 test/ELF/aarch64-fpic-got.s create mode 100644 test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s create mode 100644 test/ELF/aarch64-fpic-prel16.s create mode 100644 test/ELF/aarch64-fpic-prel32.s create mode 100644 test/ELF/aarch64-fpic-prel64.s create mode 100644 test/ELF/aarch64-gnu-ifunc-nosym.s create mode 100644 test/ELF/aarch64-gnu-ifunc-plt.s create mode 100644 test/ELF/aarch64-gnu-ifunc.s create mode 100644 test/ELF/aarch64-got-reloc.s create mode 100644 test/ELF/aarch64-got-relocations.s create mode 100644 test/ELF/aarch64-got.s create mode 100644 test/ELF/aarch64-hi21-error.s create mode 100644 test/ELF/aarch64-jump26-error.s create mode 100644 test/ELF/aarch64-lo21-error.s create mode 100644 test/ELF/aarch64-prel16.s create mode 100644 test/ELF/aarch64-prel32.s create mode 100644 test/ELF/aarch64-relative.s create mode 100644 test/ELF/aarch64-relocs.s create mode 100644 test/ELF/aarch64-relro.s create mode 100644 test/ELF/aarch64-tls-gdie.s create mode 100644 test/ELF/aarch64-tls-gdle.s create mode 100644 test/ELF/aarch64-tls-ie.s create mode 100644 test/ELF/aarch64-tls-iele.s create mode 100644 test/ELF/aarch64-tls-le.s create mode 100644 test/ELF/aarch64-tls-pie.s create mode 100644 test/ELF/aarch64-tls-static.s create mode 100644 test/ELF/aarch64-tlsdesc.s create mode 100644 test/ELF/aarch64-tstbr14-reloc.s create mode 100644 test/ELF/aarch64-undefined-weak.s create mode 100644 test/ELF/abs-conflict.s create mode 100644 test/ELF/abs-hidden.s create mode 100644 test/ELF/allow-multiple-definition.s create mode 100644 test/ELF/allow-shlib-undefined.s create mode 100644 test/ELF/amdgpu-globals.s create mode 100644 test/ELF/amdgpu-kernels.s create mode 100644 test/ELF/amdgpu-relocs.s create mode 100644 test/ELF/archive.s create mode 100644 test/ELF/arm-abs32-dyn.s create mode 100644 test/ELF/arm-attributes.s create mode 100644 test/ELF/arm-blx.s create mode 100644 test/ELF/arm-branch-error.s create mode 100644 test/ELF/arm-branch.s create mode 100644 test/ELF/arm-copy.s create mode 100644 test/ELF/arm-data-prel.s create mode 100644 test/ELF/arm-data-relocs.s create mode 100644 test/ELF/arm-eabi-version.s create mode 100644 test/ELF/arm-exidx-canunwind.s create mode 100644 test/ELF/arm-exidx-gc.s create mode 100644 test/ELF/arm-exidx-link.s create mode 100644 test/ELF/arm-exidx-order.s create mode 100644 test/ELF/arm-exidx-output.s create mode 100644 test/ELF/arm-exidx-relocatable.s create mode 100644 test/ELF/arm-exidx-sentinel-norelocatable.s create mode 100644 test/ELF/arm-exidx-sentinel-orphan.s create mode 100644 test/ELF/arm-exidx-shared.s create mode 100644 test/ELF/arm-fpic-got.s create mode 100644 test/ELF/arm-gnu-ifunc-nosym.s create mode 100644 test/ELF/arm-gnu-ifunc-plt.s create mode 100644 test/ELF/arm-gnu-ifunc.s create mode 100644 test/ELF/arm-got-relative.s create mode 100644 test/ELF/arm-gotoff.s create mode 100644 test/ELF/arm-icf-exidx.s create mode 100644 test/ELF/arm-mov-relocs.s create mode 100644 test/ELF/arm-pie-relative.s create mode 100644 test/ELF/arm-plt-reloc.s create mode 100644 test/ELF/arm-sbrel32.s create mode 100644 test/ELF/arm-static-defines.s create mode 100644 test/ELF/arm-target1.s create mode 100644 test/ELF/arm-target2.s create mode 100644 test/ELF/arm-thumb-blx.s create mode 100644 test/ELF/arm-thumb-branch-error.s create mode 100644 test/ELF/arm-thumb-branch.s create mode 100644 test/ELF/arm-thumb-interwork-shared.s create mode 100644 test/ELF/arm-thumb-interwork-thunk-range.s create mode 100644 test/ELF/arm-thumb-interwork-thunk.s create mode 100644 test/ELF/arm-thumb-narrow-branch-check.s create mode 100644 test/ELF/arm-thumb-no-undefined-thunk.s create mode 100644 test/ELF/arm-thumb-plt-reloc.s create mode 100644 test/ELF/arm-thumb-thunk-symbols.s create mode 100644 test/ELF/arm-thumb-undefined-weak.s create mode 100644 test/ELF/arm-tls-gd-nonpreemptible.s create mode 100644 test/ELF/arm-tls-gd32.s create mode 100644 test/ELF/arm-tls-ie32.s create mode 100644 test/ELF/arm-tls-ldm32.s create mode 100644 test/ELF/arm-tls-le32.s create mode 100644 test/ELF/arm-tls-norelax-gd-ie.s create mode 100644 test/ELF/arm-tls-norelax-gd-le.s create mode 100644 test/ELF/arm-tls-norelax-ie-le.s create mode 100644 test/ELF/arm-tls-norelax-ld-le.s create mode 100644 test/ELF/arm-undefined-weak.s create mode 100644 test/ELF/arm-use-r-output.s create mode 100644 test/ELF/as-needed-no-reloc.s create mode 100644 test/ELF/as-needed.s create mode 100644 test/ELF/auxiliary.s create mode 100644 test/ELF/avoid-empty-program-headers.s create mode 100644 test/ELF/bad-archive.s create mode 100644 test/ELF/basic-aarch64.s create mode 100644 test/ELF/basic-avr.s create mode 100644 test/ELF/basic-freebsd.s create mode 100644 test/ELF/basic-mips.s create mode 100644 test/ELF/basic-ppc.s create mode 100644 test/ELF/basic-sparcv9.s create mode 100644 test/ELF/basic.s create mode 100644 test/ELF/basic32.s create mode 100644 test/ELF/basic64be.s create mode 100644 test/ELF/bss-start-common.s create mode 100644 test/ELF/bss.s create mode 100644 test/ELF/bsymbolic-undef.s create mode 100644 test/ELF/bsymbolic.s create mode 100644 test/ELF/build-id.s create mode 100644 test/ELF/color-diagnostics.test create mode 100644 test/ELF/combrelocs.s create mode 100644 test/ELF/comdat-linkonce.s create mode 100644 test/ELF/comdat.s create mode 100644 test/ELF/comment-gc.s create mode 100644 test/ELF/common.s create mode 100644 test/ELF/compatible-section-types.s create mode 100644 test/ELF/compress-debug-sections.s create mode 100644 test/ELF/compressed-debug-input.s create mode 100644 test/ELF/conflict.s create mode 100644 test/ELF/copy-errors.s create mode 100644 test/ELF/copy-in-shared.s create mode 100644 test/ELF/copy-rel-corrupted.s create mode 100644 test/ELF/copy-rel-pie-error.s create mode 100644 test/ELF/copy-rel-pie.s create mode 100644 test/ELF/ctors_dtors_priority.s create mode 100644 test/ELF/debug-gc.s create mode 100644 test/ELF/debug-gnu-pubnames.s create mode 100644 test/ELF/default-fill.s create mode 100644 test/ELF/default-output.s create mode 100644 test/ELF/defined-tls_get_addr.s create mode 100644 test/ELF/defsym.s create mode 100644 test/ELF/discard-locals.s create mode 100644 test/ELF/discard-merge-locals.s create mode 100644 test/ELF/discard-merge-unnamed.s create mode 100644 test/ELF/discard-none.s create mode 100644 test/ELF/dont-export-hidden.s create mode 100644 test/ELF/driver-access.test create mode 100644 test/ELF/driver.test create mode 100644 test/ELF/dso-undef-size.s create mode 100644 test/ELF/dso_handle.s create mode 100644 test/ELF/dt_flags.s create mode 100644 test/ELF/dt_tags.s create mode 100644 test/ELF/dtrace-r.test create mode 100644 test/ELF/duplicated-plt-entry.s create mode 100644 test/ELF/duplicated-synthetic-sym.s create mode 100644 test/ELF/dynamic-got-rela.s create mode 100644 test/ELF/dynamic-got.s create mode 100644 test/ELF/dynamic-list-extern.s create mode 100644 test/ELF/dynamic-list.s create mode 100644 test/ELF/dynamic-reloc-in-ro.s create mode 100644 test/ELF/dynamic-reloc-index.s create mode 100644 test/ELF/dynamic-reloc-weak.s create mode 100644 test/ELF/dynamic-reloc.s create mode 100644 test/ELF/dynamic.s create mode 100644 test/ELF/dynsym-pie.s create mode 100644 test/ELF/early-exit-for-bad-paths.s create mode 100644 test/ELF/edata-etext.s create mode 100644 test/ELF/eh-align-cie.s create mode 100644 test/ELF/eh-frame-begin-end.s create mode 100644 test/ELF/eh-frame-dyn-rel.s create mode 100644 test/ELF/eh-frame-gc.s create mode 100644 test/ELF/eh-frame-gc2.s create mode 100644 test/ELF/eh-frame-hdr-abs-fde.s create mode 100644 test/ELF/eh-frame-hdr-augmentation.s create mode 100644 test/ELF/eh-frame-hdr-icf.s create mode 100644 test/ELF/eh-frame-hdr-no-out2.s create mode 100644 test/ELF/eh-frame-hdr.s create mode 100644 test/ELF/eh-frame-marker.s create mode 100644 test/ELF/eh-frame-merge.s create mode 100644 test/ELF/eh-frame-multilpe-cie.s create mode 100644 test/ELF/eh-frame-padding-no-rosegment.s create mode 100644 test/ELF/eh-frame-plt.s create mode 100644 test/ELF/eh-frame-rel.s create mode 100644 test/ELF/eh-frame-type.test create mode 100644 test/ELF/ehdr_start.s create mode 100644 test/ELF/ehframe-relocation.s create mode 100644 test/ELF/emit-relocs-merge.s create mode 100644 test/ELF/emit-relocs-shared.s create mode 100644 test/ELF/emit-relocs.s create mode 100644 test/ELF/empty-archive.s create mode 100644 test/ELF/empty-pt-load.s create mode 100644 test/ELF/empty-ver.s create mode 100644 test/ELF/emulation.s create mode 100644 test/ELF/end-abs.s create mode 100644 test/ELF/end-preserve.s create mode 100644 test/ELF/end-update.s create mode 100644 test/ELF/end.s create mode 100644 test/ELF/entry.s create mode 100644 test/ELF/error-limit.test create mode 100644 test/ELF/exclude-libs.s create mode 100644 test/ELF/exclude.s create mode 100644 test/ELF/fatal-warnings.s create mode 100644 test/ELF/file-sym.s create mode 100644 test/ELF/filter.s create mode 100644 test/ELF/format-binary.test create mode 100644 test/ELF/gc-absolute.s create mode 100644 test/ELF/gc-debuginfo-tls.s create mode 100644 test/ELF/gc-merge-local-sym.s create mode 100644 test/ELF/gc-sections-alloc.s create mode 100644 test/ELF/gc-sections-eh.s create mode 100644 test/ELF/gc-sections-implicit-addend.s create mode 100644 test/ELF/gc-sections-keep-shared-start.s create mode 100644 test/ELF/gc-sections-local-sym.s create mode 100644 test/ELF/gc-sections-lsda.s create mode 100644 test/ELF/gc-sections-merge-addend.s create mode 100644 test/ELF/gc-sections-merge-implicit-addend.s create mode 100644 test/ELF/gc-sections-merge.s create mode 100644 test/ELF/gc-sections-metadata-startstop.s create mode 100644 test/ELF/gc-sections-metadata.s create mode 100644 test/ELF/gc-sections-metadata2.s create mode 100644 test/ELF/gc-sections-non-alloc-to-merge.s create mode 100644 test/ELF/gc-sections-print.s create mode 100644 test/ELF/gc-sections-protected.s create mode 100644 test/ELF/gc-sections-shared.s create mode 100644 test/ELF/gc-sections-synthetic.s create mode 100644 test/ELF/gc-sections-weak.s create mode 100644 test/ELF/gc-sections.s create mode 100644 test/ELF/gdb-index-dup-types.s create mode 100644 test/ELF/gdb-index-empty.s create mode 100644 test/ELF/gdb-index-gc-sections.s create mode 100644 test/ELF/gdb-index-ranges.s create mode 100644 test/ELF/gdb-index.s create mode 100644 test/ELF/global-offset-table-position-aarch64.s create mode 100644 test/ELF/global-offset-table-position-arm.s create mode 100644 test/ELF/global-offset-table-position-i386.s create mode 100644 test/ELF/global-offset-table-position-mips.s create mode 100644 test/ELF/global-offset-table-position.s create mode 100644 test/ELF/global_offset_table.s create mode 100644 test/ELF/global_offset_table_shared.s create mode 100644 test/ELF/gnu-hash-table.s create mode 100644 test/ELF/gnu-ifunc-dso.s create mode 100644 test/ELF/gnu-ifunc-gotpcrel.s create mode 100644 test/ELF/gnu-ifunc-i386.s create mode 100644 test/ELF/gnu-ifunc-nosym-i386.s create mode 100644 test/ELF/gnu-ifunc-nosym.s create mode 100644 test/ELF/gnu-ifunc-plt-i386.s create mode 100644 test/ELF/gnu-ifunc-plt.s create mode 100644 test/ELF/gnu-ifunc-relative.s create mode 100644 test/ELF/gnu-ifunc-shared.s create mode 100644 test/ELF/gnu-ifunc.s create mode 100644 test/ELF/gnu-unique.s create mode 100644 test/ELF/gnustack.s create mode 100644 test/ELF/got-aarch64.s create mode 100644 test/ELF/got-i386.s create mode 100644 test/ELF/got-plt-header.s create mode 100644 test/ELF/got.s create mode 100644 test/ELF/got32-i386.s create mode 100644 test/ELF/got32x-i386.s create mode 100644 test/ELF/gotpc-relax-nopic.s create mode 100644 test/ELF/gotpc-relax-und-dso.s create mode 100644 test/ELF/gotpc-relax.s create mode 100644 test/ELF/gotpcrelx.s create mode 100644 test/ELF/hidden-vis-shared.s create mode 100644 test/ELF/i386-got-and-copy.s create mode 100644 test/ELF/i386-gotoff-shared.s create mode 100644 test/ELF/i386-gotpc-dynamic.s create mode 100644 test/ELF/i386-gotpc.s create mode 100644 test/ELF/i386-merge.s create mode 100644 test/ELF/i386-pc16.test create mode 100644 test/ELF/i386-pc8-pc16-addend.s create mode 100644 test/ELF/i386-pc8.s create mode 100644 test/ELF/i386-relative.s create mode 100644 test/ELF/i386-relax-reloc.s create mode 100644 test/ELF/i386-reloc-16.s create mode 100644 test/ELF/i386-reloc-8.s create mode 100644 test/ELF/i386-reloc-large-addend.s create mode 100644 test/ELF/i386-reloc-range.s create mode 100644 test/ELF/i386-reloc8-reloc16-addend.s create mode 100644 test/ELF/i386-tls-got.s create mode 100644 test/ELF/i386-tls-ie-shared.s create mode 100644 test/ELF/icf-absolute.s create mode 100644 test/ELF/icf-comdat.s create mode 100644 test/ELF/icf-i386.s create mode 100644 test/ELF/icf-merge-sec.s create mode 100644 test/ELF/icf-merge.s create mode 100644 test/ELF/icf-non-mergeable.s create mode 100644 test/ELF/icf-none.s create mode 100644 test/ELF/icf1.s create mode 100644 test/ELF/icf2.s create mode 100644 test/ELF/icf3.s create mode 100644 test/ELF/icf4.s create mode 100644 test/ELF/icf5.s create mode 100644 test/ELF/icf6.s create mode 100644 test/ELF/icf7.s create mode 100644 test/ELF/icf8.s create mode 100644 test/ELF/icf9.s create mode 100644 test/ELF/image-base.s create mode 100644 test/ELF/incompatible-ar-first.s create mode 100644 test/ELF/incompatible-section-flags.s create mode 100644 test/ELF/incompatible-section-types2.s create mode 100644 test/ELF/incompatible.s create mode 100644 test/ELF/init-fini-progbits.s create mode 100644 test/ELF/init-fini.s create mode 100644 test/ELF/init_fini_priority.s create mode 100644 test/ELF/invalid-cie-length.s create mode 100644 test/ELF/invalid-cie-length2.s create mode 100644 test/ELF/invalid-cie-length3.s create mode 100644 test/ELF/invalid-cie-length4.s create mode 100644 test/ELF/invalid-cie-length5.s create mode 100644 test/ELF/invalid-cie-reference.s create mode 100644 test/ELF/invalid-dynamic-list.test create mode 100644 test/ELF/invalid-fde-rel.s create mode 100644 test/ELF/invalid-linkerscript.test create mode 100644 test/ELF/invalid-relocations.test create mode 100644 test/ELF/invalid-z.s create mode 100644 test/ELF/invalid/Inputs/binding.elf create mode 100644 test/ELF/invalid/Inputs/broken-relaxation-x64.elf create mode 100644 test/ELF/invalid/Inputs/cie-version2.elf create mode 100644 test/ELF/invalid/Inputs/common-symbol-alignment.elf create mode 100644 test/ELF/invalid/Inputs/common-symbol-alignment2.elf create mode 100644 test/ELF/invalid/Inputs/data-encoding.a create mode 100644 test/ELF/invalid/Inputs/dynamic-section-sh_size.elf create mode 100644 test/ELF/invalid/Inputs/file-class.a create mode 100644 test/ELF/invalid/Inputs/invalid-e_shnum.elf create mode 100644 test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf create mode 100644 test/ELF/invalid/Inputs/multiple-eh-relocs.elf create mode 100644 test/ELF/invalid/Inputs/section-alignment-notpow2.elf create mode 100644 test/ELF/invalid/Inputs/section-index.elf create mode 100644 test/ELF/invalid/Inputs/section-index2.elf create mode 100644 test/ELF/invalid/Inputs/shentsize-zero.elf create mode 100644 test/ELF/invalid/Inputs/sht-group.elf create mode 100644 test/ELF/invalid/Inputs/symbol-index.elf create mode 100644 test/ELF/invalid/Inputs/symbol-name-offset.elf create mode 100644 test/ELF/invalid/Inputs/symtab-sh_info.elf create mode 100644 test/ELF/invalid/Inputs/symtab-sh_info2.elf create mode 100644 test/ELF/invalid/Inputs/symtab-sh_info3.elf create mode 100644 test/ELF/invalid/Inputs/tls-symbol.elf create mode 100644 test/ELF/invalid/Inputs/too-short.elf create mode 100644 test/ELF/invalid/broken-relaxation-x64.test create mode 100644 test/ELF/invalid/common-symbol-alignment.s create mode 100644 test/ELF/invalid/dynamic-section-size.s create mode 100644 test/ELF/invalid/eh-frame-hdr-no-out.s create mode 100644 test/ELF/invalid/invalid-debug-relocations.test create mode 100644 test/ELF/invalid/invalid-e_shnum.s create mode 100644 test/ELF/invalid/invalid-elf.test create mode 100644 test/ELF/invalid/invalid-relocation-x64.test create mode 100644 test/ELF/invalid/merge-invalid-size.s create mode 100644 test/ELF/invalid/mips-invalid-options-descriptor.s create mode 100644 test/ELF/invalid/section-alignment.test create mode 100644 test/ELF/invalid/section-alignment2.s create mode 100644 test/ELF/invalid/sht-group.s create mode 100644 test/ELF/invalid/symbol-index.s create mode 100644 test/ELF/invalid/symbol-name.s create mode 100644 test/ELF/invalid/symtab-sh-info.s create mode 100644 test/ELF/invalid/symtab-symbols.test create mode 100644 test/ELF/invalid/tls-symbol.s create mode 100644 test/ELF/invalid/too-short.s create mode 100644 test/ELF/invalid/verdef-no-symtab.test create mode 100644 test/ELF/libsearch.s create mode 100644 test/ELF/linkerscript/Inputs/comdat-gc.s create mode 100644 test/ELF/linkerscript/Inputs/compress-debug-sections.s create mode 100644 test/ELF/linkerscript/Inputs/exclude-multiple1.s create mode 100644 test/ELF/linkerscript/Inputs/exclude-multiple2.s create mode 100644 test/ELF/linkerscript/Inputs/filename-spec.s create mode 100644 test/ELF/linkerscript/Inputs/implicit-program-header.script create mode 100644 test/ELF/linkerscript/Inputs/include.s create mode 100644 test/ELF/linkerscript/Inputs/keep.s create mode 100644 test/ELF/linkerscript/Inputs/lazy-symbols.s create mode 100644 test/ELF/linkerscript/Inputs/libsearch-dyn.s create mode 100644 test/ELF/linkerscript/Inputs/libsearch-st.s create mode 100644 test/ELF/linkerscript/Inputs/merge-sections-reloc.s create mode 100644 test/ELF/linkerscript/Inputs/notinclude.s create mode 100644 test/ELF/linkerscript/Inputs/segment-start.script create mode 100644 test/ELF/linkerscript/Inputs/shared.s create mode 100644 test/ELF/linkerscript/Inputs/sort-nested.s create mode 100644 test/ELF/linkerscript/Inputs/sort.s create mode 100644 test/ELF/linkerscript/absolute-expr.s create mode 100644 test/ELF/linkerscript/absolute.s create mode 100644 test/ELF/linkerscript/addr-zero.s create mode 100644 test/ELF/linkerscript/addr.s create mode 100644 test/ELF/linkerscript/align-empty.s create mode 100644 test/ELF/linkerscript/align.s create mode 100644 test/ELF/linkerscript/alignof.s create mode 100644 test/ELF/linkerscript/alternate-sections.s create mode 100644 test/ELF/linkerscript/arm-exidx-phdrs.s create mode 100644 test/ELF/linkerscript/arm-lscript.s create mode 100644 test/ELF/linkerscript/assert.s create mode 100644 test/ELF/linkerscript/at-addr.s create mode 100644 test/ELF/linkerscript/at.s create mode 100644 test/ELF/linkerscript/bss-fill.s create mode 100644 test/ELF/linkerscript/comdat-gc.s create mode 100644 test/ELF/linkerscript/common-assign.s create mode 100644 test/ELF/linkerscript/common.s create mode 100644 test/ELF/linkerscript/compress-debug-sections.s create mode 100644 test/ELF/linkerscript/constructor.s create mode 100644 test/ELF/linkerscript/data-commands-gc.s create mode 100644 test/ELF/linkerscript/data-commands.s create mode 100644 test/ELF/linkerscript/data-segment-relro.s create mode 100644 test/ELF/linkerscript/define.s create mode 100644 test/ELF/linkerscript/diagnostic.s create mode 100644 test/ELF/linkerscript/discard-interp.s create mode 100644 test/ELF/linkerscript/discard-print-gc.s create mode 100644 test/ELF/linkerscript/discard-section-err.s create mode 100644 test/ELF/linkerscript/discard-section-metadata.s create mode 100644 test/ELF/linkerscript/discard-section.s create mode 100644 test/ELF/linkerscript/dot-is-not-abs.s create mode 100644 test/ELF/linkerscript/double-bss.s create mode 100644 test/ELF/linkerscript/dynamic-sym.s create mode 100644 test/ELF/linkerscript/dynamic.s create mode 100644 test/ELF/linkerscript/early-assign-symbol.s create mode 100644 test/ELF/linkerscript/edata-etext.s create mode 100644 test/ELF/linkerscript/eh-frame-hdr.s create mode 100644 test/ELF/linkerscript/eh-frame-reloc-out-of-range.s create mode 100644 test/ELF/linkerscript/eh-frame.s create mode 100644 test/ELF/linkerscript/ehdr_start.s create mode 100644 test/ELF/linkerscript/emit-reloc.s create mode 100644 test/ELF/linkerscript/emit-relocs-discard.s create mode 100644 test/ELF/linkerscript/emit-relocs-ehframe-discard.s create mode 100644 test/ELF/linkerscript/emit-relocs-multiple.s create mode 100644 test/ELF/linkerscript/empty-load.s create mode 100644 test/ELF/linkerscript/empty-tls.s create mode 100644 test/ELF/linkerscript/entry.s create mode 100644 test/ELF/linkerscript/exclude-multiple.s create mode 100644 test/ELF/linkerscript/excludefile.s create mode 100644 test/ELF/linkerscript/exidx-crash.s create mode 100644 test/ELF/linkerscript/expr-invalid-sec.s create mode 100644 test/ELF/linkerscript/expr-sections.s create mode 100644 test/ELF/linkerscript/extend-pt-load.s create mode 100644 test/ELF/linkerscript/filename-spec.s create mode 100644 test/ELF/linkerscript/fill-exec-sections.s create mode 100644 test/ELF/linkerscript/fill.s create mode 100644 test/ELF/linkerscript/got-write-offset.s create mode 100644 test/ELF/linkerscript/group.s create mode 100644 test/ELF/linkerscript/header-addr.s create mode 100644 test/ELF/linkerscript/huge-temporary-file.s create mode 100644 test/ELF/linkerscript/implicit-program-header.s create mode 100644 test/ELF/linkerscript/input-order.s create mode 100644 test/ELF/linkerscript/input-sec-dup.s create mode 100644 test/ELF/linkerscript/lazy-symbols.s create mode 100644 test/ELF/linkerscript/linkerscript.s create mode 100644 test/ELF/linkerscript/loadaddr.s create mode 100644 test/ELF/linkerscript/locationcountererr.s create mode 100644 test/ELF/linkerscript/locationcountererr2.s create mode 100644 test/ELF/linkerscript/memory.s create mode 100644 test/ELF/linkerscript/merge-sections-reloc.s create mode 100644 test/ELF/linkerscript/merge-sections-syms.s create mode 100644 test/ELF/linkerscript/merge-sections.s create mode 100644 test/ELF/linkerscript/multi-sections-constraint.s create mode 100644 test/ELF/linkerscript/multiple-tbss.s create mode 100644 test/ELF/linkerscript/no-pt-load.s create mode 100644 test/ELF/linkerscript/no-space.s create mode 100644 test/ELF/linkerscript/noload.s create mode 100644 test/ELF/linkerscript/non-absolute.s create mode 100644 test/ELF/linkerscript/non-absolute2.s create mode 100644 test/ELF/linkerscript/non-alloc-segment.s create mode 100644 test/ELF/linkerscript/non-alloc.s create mode 100644 test/ELF/linkerscript/numbers.s create mode 100644 test/ELF/linkerscript/obj-symbol-value.s create mode 100644 test/ELF/linkerscript/openbsd-bootdata.s create mode 100644 test/ELF/linkerscript/openbsd-randomize.s create mode 100644 test/ELF/linkerscript/openbsd-wxneeded.s create mode 100644 test/ELF/linkerscript/operators.s create mode 100644 test/ELF/linkerscript/orphan-align.s create mode 100644 test/ELF/linkerscript/orphan-first-cmd.s create mode 100644 test/ELF/linkerscript/orphan.s create mode 100644 test/ELF/linkerscript/orphans.s create mode 100644 test/ELF/linkerscript/ouputformat.s create mode 100644 test/ELF/linkerscript/out-of-order.s create mode 100644 test/ELF/linkerscript/output-too-large.s create mode 100644 test/ELF/linkerscript/outputarch.s create mode 100644 test/ELF/linkerscript/outsections-addr.s create mode 100644 test/ELF/linkerscript/page-size-align.s create mode 100644 test/ELF/linkerscript/page-size.s create mode 100644 test/ELF/linkerscript/phdr-check.s create mode 100644 test/ELF/linkerscript/phdrs-flags.s create mode 100644 test/ELF/linkerscript/phdrs.s create mode 100644 test/ELF/linkerscript/pt_gnu_eh_frame.s create mode 100644 test/ELF/linkerscript/repsection-symbol.s create mode 100644 test/ELF/linkerscript/repsection-va.s create mode 100644 test/ELF/linkerscript/rosegment.s create mode 100644 test/ELF/linkerscript/searchdir.s create mode 100644 test/ELF/linkerscript/section-align.s create mode 100644 test/ELF/linkerscript/section-metadata.s create mode 100644 test/ELF/linkerscript/sections-constraint.s create mode 100644 test/ELF/linkerscript/sections-constraint2.s create mode 100644 test/ELF/linkerscript/sections-constraint3.s create mode 100644 test/ELF/linkerscript/sections-constraint4.s create mode 100644 test/ELF/linkerscript/sections-constraint5.s create mode 100644 test/ELF/linkerscript/sections-gc.s create mode 100644 test/ELF/linkerscript/sections-gc2.s create mode 100644 test/ELF/linkerscript/sections-keep.s create mode 100644 test/ELF/linkerscript/sections-padding.s create mode 100644 test/ELF/linkerscript/sections-sort.s create mode 100644 test/ELF/linkerscript/sections.s create mode 100644 test/ELF/linkerscript/segment-none.s create mode 100644 test/ELF/linkerscript/segment-start.s create mode 100644 test/ELF/linkerscript/sizeof.s create mode 100644 test/ELF/linkerscript/sizeofheaders.s create mode 100644 test/ELF/linkerscript/sort-constructors.s create mode 100644 test/ELF/linkerscript/sort-init.s create mode 100644 test/ELF/linkerscript/sort-nested.s create mode 100644 test/ELF/linkerscript/sort-non-script.s create mode 100644 test/ELF/linkerscript/sort.s create mode 100644 test/ELF/linkerscript/sort2.s create mode 100644 test/ELF/linkerscript/start-end.s create mode 100644 test/ELF/linkerscript/subalign.s create mode 100644 test/ELF/linkerscript/symbol-assignexpr.s create mode 100644 test/ELF/linkerscript/symbol-conflict.s create mode 100644 test/ELF/linkerscript/symbol-memoryexpr.s create mode 100644 test/ELF/linkerscript/symbol-only.s create mode 100644 test/ELF/linkerscript/symbol-reserved.s create mode 100644 test/ELF/linkerscript/symbolreferenced.s create mode 100644 test/ELF/linkerscript/symbols-non-alloc.s create mode 100644 test/ELF/linkerscript/symbols-synthetic.s create mode 100644 test/ELF/linkerscript/symbols.s create mode 100644 test/ELF/linkerscript/tbss.s create mode 100644 test/ELF/linkerscript/ttext-script.s create mode 100644 test/ELF/linkerscript/undef.s create mode 100644 test/ELF/linkerscript/unused-synthetic.s create mode 100644 test/ELF/linkerscript/va.s create mode 100644 test/ELF/linkerscript/visibility.s create mode 100644 test/ELF/linkerscript/wildcards.s create mode 100644 test/ELF/linkerscript/wildcards2.s create mode 100644 test/ELF/lit.local.cfg create mode 100644 test/ELF/llvm33-rela-outside-group.s create mode 100644 test/ELF/local-dynamic.s create mode 100644 test/ELF/local-got-pie.s create mode 100644 test/ELF/local-got-shared.s create mode 100644 test/ELF/local-got.s create mode 100644 test/ELF/local-undefined-symbol.s create mode 100644 test/ELF/local.s create mode 100644 test/ELF/lto/Inputs/archive-2.ll create mode 100644 test/ELF/lto/Inputs/archive-3.ll create mode 100644 test/ELF/lto/Inputs/archive.ll create mode 100644 test/ELF/lto/Inputs/available-externally.ll create mode 100644 test/ELF/lto/Inputs/cache.ll create mode 100644 test/ELF/lto/Inputs/comdat.s create mode 100644 test/ELF/lto/Inputs/common.s create mode 100644 test/ELF/lto/Inputs/common3.ll create mode 100644 test/ELF/lto/Inputs/defsym-bar.ll create mode 100644 test/ELF/lto/Inputs/drop-debug-info.bc create mode 100644 test/ELF/lto/Inputs/drop-linkage.ll create mode 100644 test/ELF/lto/Inputs/duplicated-name.ll create mode 100644 test/ELF/lto/Inputs/dynsym.s create mode 100644 test/ELF/lto/Inputs/internalize-exportdyn.ll create mode 100644 test/ELF/lto/Inputs/internalize-undef.ll create mode 100644 test/ELF/lto/Inputs/irmover-error.ll create mode 100644 test/ELF/lto/Inputs/linkonce-odr.ll create mode 100644 test/ELF/lto/Inputs/linkonce.ll create mode 100644 test/ELF/lto/Inputs/relocation-model-pic.ll create mode 100644 test/ELF/lto/Inputs/resolution.s create mode 100644 test/ELF/lto/Inputs/save-temps.ll create mode 100644 test/ELF/lto/Inputs/shared.s create mode 100644 test/ELF/lto/Inputs/start-lib1.ll create mode 100644 test/ELF/lto/Inputs/start-lib2.ll create mode 100644 test/ELF/lto/Inputs/thin1.ll create mode 100644 test/ELF/lto/Inputs/thin2.ll create mode 100644 test/ELF/lto/Inputs/thinlto.ll create mode 100644 test/ELF/lto/Inputs/tls-mixed.s create mode 100644 test/ELF/lto/Inputs/type-merge.ll create mode 100644 test/ELF/lto/Inputs/type-merge2.ll create mode 100644 test/ELF/lto/Inputs/undef-mixed.s create mode 100644 test/ELF/lto/Inputs/unnamed-addr-drop.ll create mode 100644 test/ELF/lto/Inputs/unnamed-addr-lib.s create mode 100644 test/ELF/lto/Inputs/visibility.s create mode 100644 test/ELF/lto/Inputs/wrap-bar.ll create mode 100644 test/ELF/lto/archive-2.ll create mode 100644 test/ELF/lto/archive-3.ll create mode 100644 test/ELF/lto/archive-no-index.ll create mode 100644 test/ELF/lto/archive.ll create mode 100644 test/ELF/lto/asmundef.ll create mode 100644 test/ELF/lto/available-externally.ll create mode 100644 test/ELF/lto/bitcode-nodatalayout.ll create mode 100644 test/ELF/lto/cache.ll create mode 100644 test/ELF/lto/codemodel.ll create mode 100644 test/ELF/lto/combined-lto-object-name.ll create mode 100644 test/ELF/lto/comdat.ll create mode 100644 test/ELF/lto/comdat2.ll create mode 100644 test/ELF/lto/common.ll create mode 100644 test/ELF/lto/common2.ll create mode 100644 test/ELF/lto/common3.ll create mode 100644 test/ELF/lto/ctors.ll create mode 100644 test/ELF/lto/defsym.ll create mode 100644 test/ELF/lto/discard-value-names.ll create mode 100644 test/ELF/lto/drop-debug-info.ll create mode 100644 test/ELF/lto/drop-linkage.ll create mode 100644 test/ELF/lto/duplicated-name.ll create mode 100644 test/ELF/lto/duplicated.ll create mode 100644 test/ELF/lto/dynamic-list.ll create mode 100644 test/ELF/lto/dynsym.ll create mode 100644 test/ELF/lto/inline-asm.ll create mode 100644 test/ELF/lto/internalize-basic.ll create mode 100644 test/ELF/lto/internalize-exportdyn.ll create mode 100644 test/ELF/lto/internalize-llvmused.ll create mode 100644 test/ELF/lto/internalize-undef.ll create mode 100644 test/ELF/lto/internalize-version-script.ll create mode 100644 test/ELF/lto/irmover-error.ll create mode 100644 test/ELF/lto/linkage.ll create mode 100644 test/ELF/lto/linkonce-odr.ll create mode 100644 test/ELF/lto/linkonce.ll create mode 100644 test/ELF/lto/lto-start.ll create mode 100644 test/ELF/lto/ltopasses-basic.ll create mode 100644 test/ELF/lto/ltopasses-custom.ll create mode 100644 test/ELF/lto/metadata.ll create mode 100644 test/ELF/lto/mix-platforms.ll create mode 100644 test/ELF/lto/module-asm.ll create mode 100644 test/ELF/lto/opt-level.ll create mode 100644 test/ELF/lto/opt-remarks.ll create mode 100644 test/ELF/lto/parallel-internalize.ll create mode 100644 test/ELF/lto/parallel.ll create mode 100644 test/ELF/lto/pic.ll create mode 100644 test/ELF/lto/relax-relocs.ll create mode 100644 test/ELF/lto/relocation-model.ll create mode 100644 test/ELF/lto/resolution.ll create mode 100644 test/ELF/lto/save-temps.ll create mode 100644 test/ELF/lto/shlib-undefined.ll create mode 100644 test/ELF/lto/start-lib.ll create mode 100644 test/ELF/lto/thin-archivecollision.ll create mode 100644 test/ELF/lto/thinlto.ll create mode 100644 test/ELF/lto/timepasses.ll create mode 100644 test/ELF/lto/tls-mixed.ll create mode 100644 test/ELF/lto/tls-preserve.ll create mode 100644 test/ELF/lto/type-merge.ll create mode 100644 test/ELF/lto/type-merge2.ll create mode 100644 test/ELF/lto/undef-mixed.ll create mode 100644 test/ELF/lto/undef-weak.ll create mode 100644 test/ELF/lto/undef.ll create mode 100644 test/ELF/lto/undefined-puts.ll create mode 100644 test/ELF/lto/unnamed-addr-comdat.ll create mode 100644 test/ELF/lto/unnamed-addr-drop.ll create mode 100644 test/ELF/lto/unnamed-addr-lib.ll create mode 100644 test/ELF/lto/unnamed-addr.ll create mode 100644 test/ELF/lto/verify-invalid.ll create mode 100644 test/ELF/lto/version-script.ll create mode 100644 test/ELF/lto/visibility.ll create mode 100644 test/ELF/lto/weak.ll create mode 100644 test/ELF/lto/wrap-1.ll create mode 100644 test/ELF/lto/wrap-2.ll create mode 100644 test/ELF/many-alloc-sections.s create mode 100644 test/ELF/many-sections.s create mode 100644 test/ELF/map-file.s create mode 100644 test/ELF/map-gc-sections.s create mode 100644 test/ELF/merge-reloc.s create mode 100644 test/ELF/merge-section-types.s create mode 100644 test/ELF/merge-shared-str.s create mode 100644 test/ELF/merge-shared.s create mode 100644 test/ELF/merge-string-align.s create mode 100644 test/ELF/merge-string-empty.s create mode 100644 test/ELF/merge-string-error.s create mode 100644 test/ELF/merge-string-no-null.s create mode 100644 test/ELF/merge-string.s create mode 100644 test/ELF/merge-sym.s create mode 100644 test/ELF/merge.s create mode 100644 test/ELF/mips-26-mask.s create mode 100644 test/ELF/mips-26.s create mode 100644 test/ELF/mips-32.s create mode 100644 test/ELF/mips-64-disp.s create mode 100644 test/ELF/mips-64-got.s create mode 100644 test/ELF/mips-64-gprel-so.s create mode 100644 test/ELF/mips-64-rels.s create mode 100644 test/ELF/mips-64.s create mode 100644 test/ELF/mips-align-err.s create mode 100644 test/ELF/mips-call-hilo.s create mode 100644 test/ELF/mips-call16.s create mode 100644 test/ELF/mips-dynamic.s create mode 100644 test/ELF/mips-dynsym-sort.s create mode 100644 test/ELF/mips-elf-flags-err.s create mode 100644 test/ELF/mips-elf-flags.s create mode 100644 test/ELF/mips-gnu-hash.s create mode 100644 test/ELF/mips-got-and-copy.s create mode 100644 test/ELF/mips-got-extsym.s create mode 100644 test/ELF/mips-got-hilo.s create mode 100644 test/ELF/mips-got-page.s create mode 100644 test/ELF/mips-got-redundant.s create mode 100644 test/ELF/mips-got-relocs.s create mode 100644 test/ELF/mips-got-string.s create mode 100644 test/ELF/mips-got-weak.s create mode 100644 test/ELF/mips-got16-relocatable.s create mode 100644 test/ELF/mips-got16.s create mode 100644 test/ELF/mips-gp-disp.s create mode 100644 test/ELF/mips-gp-ext.s create mode 100644 test/ELF/mips-gp-local.s create mode 100644 test/ELF/mips-gp-lowest.s create mode 100644 test/ELF/mips-gprel-sec.s create mode 100644 test/ELF/mips-gprel32-relocs-gp0.s create mode 100644 test/ELF/mips-gprel32-relocs.s create mode 100644 test/ELF/mips-higher-highest.s create mode 100644 test/ELF/mips-hilo-gp-disp.s create mode 100644 test/ELF/mips-hilo-hi-only.s create mode 100644 test/ELF/mips-hilo.s create mode 100644 test/ELF/mips-jalr.test create mode 100644 test/ELF/mips-lo16-not-relative.s create mode 100644 test/ELF/mips-merge-abiflags.s create mode 100644 test/ELF/mips-n32-emul.s create mode 100644 test/ELF/mips-n32-rels.s create mode 100644 test/ELF/mips-no-objects.s create mode 100644 test/ELF/mips-nonalloc.s create mode 100644 test/ELF/mips-npic-call-pic-os.s create mode 100644 test/ELF/mips-npic-call-pic-script.s create mode 100644 test/ELF/mips-npic-call-pic.s create mode 100644 test/ELF/mips-options-r.test create mode 100644 test/ELF/mips-options.s create mode 100644 test/ELF/mips-pc-relocs.s create mode 100644 test/ELF/mips-plt-copy.s create mode 100644 test/ELF/mips-plt-r6.s create mode 100644 test/ELF/mips-reginfo.s create mode 100644 test/ELF/mips-relocatable.s create mode 100644 test/ELF/mips-sto-pic-flag.s create mode 100644 test/ELF/mips-sto-plt.s create mode 100644 test/ELF/mips-tls-64.s create mode 100644 test/ELF/mips-tls-hilo.s create mode 100644 test/ELF/mips-tls-static-64.s create mode 100644 test/ELF/mips-tls-static.s create mode 100644 test/ELF/mips-tls.s create mode 100644 test/ELF/mips-xgot-order.s create mode 100644 test/ELF/mips64-eh-abs-reloc.s create mode 100644 test/ELF/new-dtags.test create mode 100644 test/ELF/no-augmentation.s create mode 100644 test/ELF/no-dynamic-linker.s create mode 100644 test/ELF/no-inhibit-exec.s create mode 100644 test/ELF/no-merge.s create mode 100644 test/ELF/no-obj.s create mode 100644 test/ELF/no-plt-shared.s create mode 100644 test/ELF/no-soname.s create mode 100644 test/ELF/no-symtab.s create mode 100644 test/ELF/no-undefined.s create mode 100644 test/ELF/non-abs-reloc.s create mode 100644 test/ELF/noplt-pie.s create mode 100644 test/ELF/note-contiguous.s create mode 100644 test/ELF/note-loadaddr.c create mode 100644 test/ELF/note-multiple.s create mode 100644 test/ELF/note.s create mode 100644 test/ELF/oformat-binary-ttext.s create mode 100644 test/ELF/oformat-binary.s create mode 100644 test/ELF/openbsd-randomize.s create mode 100644 test/ELF/openbsd-wxneeded.s create mode 100644 test/ELF/output-section.s create mode 100644 test/ELF/phdr-align.s create mode 100644 test/ELF/pie-weak.s create mode 100644 test/ELF/pie.s create mode 100644 test/ELF/plt-aarch64.s create mode 100644 test/ELF/plt-i686.s create mode 100644 test/ELF/plt.s create mode 100644 test/ELF/ppc-relocs.s create mode 100644 test/ELF/ppc64-addr16-error.s create mode 100644 test/ELF/ppc64-rel-calls.s create mode 100644 test/ELF/ppc64-relocs.s create mode 100644 test/ELF/ppc64-shared-rel-toc.s create mode 100644 test/ELF/ppc64-toc-restore.s create mode 100644 test/ELF/ppc64-weak-undef-call-shared.s create mode 100644 test/ELF/ppc64-weak-undef-call.s create mode 100644 test/ELF/pre_init_fini_array.s create mode 100644 test/ELF/pre_init_fini_array_missing.s create mode 100644 test/ELF/progname.s create mode 100644 test/ELF/program-header-layout.s create mode 100644 test/ELF/protected-shared.s create mode 100644 test/ELF/rel-offset.s create mode 100644 test/ELF/relative-dynamic-reloc-pie.s create mode 100644 test/ELF/relative-dynamic-reloc-ppc64.s create mode 100644 test/ELF/relative-dynamic-reloc.s create mode 100644 test/ELF/relocatable-bss.s create mode 100644 test/ELF/relocatable-comdat-multiple.s create mode 100644 test/ELF/relocatable-comdat.s create mode 100644 test/ELF/relocatable-comment.s create mode 100644 test/ELF/relocatable-common.s create mode 100644 test/ELF/relocatable-compressed-input.s create mode 100644 test/ELF/relocatable-eh-frame-hdr.s create mode 100644 test/ELF/relocatable-eh-frame.s create mode 100644 test/ELF/relocatable-ehframe.s create mode 100644 test/ELF/relocatable-empty-archive.s create mode 100644 test/ELF/relocatable-local-sym.s create mode 100644 test/ELF/relocatable-non-alloc.s create mode 100644 test/ELF/relocatable-reloc.s create mode 100644 test/ELF/relocatable-script.s create mode 100644 test/ELF/relocatable-section-symbol.s create mode 100644 test/ELF/relocatable-sections.s create mode 100644 test/ELF/relocatable-symbol-name.s create mode 100644 test/ELF/relocatable-symbols.s create mode 100644 test/ELF/relocatable-tls.s create mode 100644 test/ELF/relocatable-visibility.s create mode 100644 test/ELF/relocatable.s create mode 100644 test/ELF/relocation-absolute.s create mode 100644 test/ELF/relocation-common.s create mode 100644 test/ELF/relocation-copy-alias.s create mode 100644 test/ELF/relocation-copy-align-common.s create mode 100644 test/ELF/relocation-copy-align.s create mode 100644 test/ELF/relocation-copy-flags.s create mode 100644 test/ELF/relocation-copy-i686.s create mode 100644 test/ELF/relocation-copy-relro.s create mode 100644 test/ELF/relocation-copy.s create mode 100644 test/ELF/relocation-dtrace.test create mode 100644 test/ELF/relocation-group.test create mode 100644 test/ELF/relocation-i686.s create mode 100644 test/ELF/relocation-in-merge.s create mode 100644 test/ELF/relocation-local.s create mode 100644 test/ELF/relocation-nocopy.s create mode 100644 test/ELF/relocation-non-alloc.s create mode 100644 test/ELF/relocation-none-aarch64.test create mode 100644 test/ELF/relocation-none-i686.test create mode 100644 test/ELF/relocation-past-merge-end.s create mode 100644 test/ELF/relocation-relative-absolute.s create mode 100644 test/ELF/relocation-relative-synthetic.s create mode 100644 test/ELF/relocation-relative-weak.s create mode 100644 test/ELF/relocation-shared.s create mode 100644 test/ELF/relocation-size-shared.s create mode 100644 test/ELF/relocation-size.s create mode 100644 test/ELF/relocation-undefined-weak.s create mode 100644 test/ELF/relocation.s create mode 100644 test/ELF/relro-omagic.s create mode 100644 test/ELF/relro-tls.s create mode 100644 test/ELF/relro.s create mode 100644 test/ELF/reproduce-backslash.s create mode 100644 test/ELF/reproduce-error.s create mode 100644 test/ELF/reproduce-linkerscript.s create mode 100644 test/ELF/reproduce-thin-archive.s create mode 100644 test/ELF/reproduce-windows.s create mode 100644 test/ELF/reproduce-windows2.s create mode 100644 test/ELF/reproduce.s create mode 100644 test/ELF/resolution-end.s create mode 100644 test/ELF/resolution-shared.s create mode 100644 test/ELF/resolution.s create mode 100644 test/ELF/retain-symbols-file.s create mode 100644 test/ELF/retain-und.s create mode 100644 test/ELF/rodynamic.s create mode 100644 test/ELF/section-align-0.test create mode 100644 test/ELF/section-layout.s create mode 100644 test/ELF/section-metadata-err.s create mode 100644 test/ELF/section-name.s create mode 100644 test/ELF/section-symbol.s create mode 100644 test/ELF/section-symbols.test create mode 100644 test/ELF/sectionstart-noallochdr.s create mode 100644 test/ELF/sectionstart.s create mode 100644 test/ELF/segments.s create mode 100644 test/ELF/shared-be.s create mode 100644 test/ELF/shared.s create mode 100644 test/ELF/shf-info-link.test create mode 100644 test/ELF/sht-group-gold-r.test create mode 100644 test/ELF/soname.s create mode 100644 test/ELF/soname2.s create mode 100644 test/ELF/sort-norosegment.s create mode 100644 test/ELF/splitstacks.s create mode 100644 test/ELF/start-lib-comdat.s create mode 100644 test/ELF/start-lib.s create mode 100644 test/ELF/startstop-gccollect.s create mode 100644 test/ELF/startstop-shared.s create mode 100644 test/ELF/startstop-shared2.s create mode 100644 test/ELF/startstop.s create mode 100644 test/ELF/static-with-export-dynamic.s create mode 100644 test/ELF/string-gc.s create mode 100644 test/ELF/string-table.s create mode 100644 test/ELF/strip-all.s create mode 100644 test/ELF/strip-debug.s create mode 100644 test/ELF/symbol-ordering-file.s create mode 100644 test/ELF/symbol-override.s create mode 100644 test/ELF/symbols.s create mode 100644 test/ELF/symver-archive.s create mode 100644 test/ELF/synthetic-got.s create mode 100644 test/ELF/sysroot.s create mode 100644 test/ELF/tail-merge-string-align.s create mode 100644 test/ELF/tls-align.s create mode 100644 test/ELF/tls-archive.s create mode 100644 test/ELF/tls-dynamic-i686.s create mode 100644 test/ELF/tls-dynamic.s create mode 100644 test/ELF/tls-error.s create mode 100644 test/ELF/tls-got-entry.s create mode 100644 test/ELF/tls-got.s create mode 100644 test/ELF/tls-i686.s create mode 100644 test/ELF/tls-in-archive.s create mode 100644 test/ELF/tls-initial-exec-local.s create mode 100644 test/ELF/tls-mismatch.s create mode 100644 test/ELF/tls-offset.s create mode 100644 test/ELF/tls-opt-gdie.s create mode 100644 test/ELF/tls-opt-gdiele-i686.s create mode 100644 test/ELF/tls-opt-i686.s create mode 100644 test/ELF/tls-opt-iele-i686-nopic.s create mode 100644 test/ELF/tls-opt-local.s create mode 100644 test/ELF/tls-opt-no-plt.s create mode 100644 test/ELF/tls-opt.s create mode 100644 test/ELF/tls-relocatable.s create mode 100644 test/ELF/tls-static.s create mode 100644 test/ELF/tls-two-relocs.s create mode 100644 test/ELF/tls-weak-undef.s create mode 100644 test/ELF/tls.s create mode 100644 test/ELF/trace-ar.s create mode 100644 test/ELF/trace-symbols.s create mode 100644 test/ELF/trace.s create mode 100644 test/ELF/ttext-tdata-tbss.s create mode 100644 test/ELF/undef-shared.s create mode 100644 test/ELF/undef-start.s create mode 100644 test/ELF/undef-version-script.s create mode 100644 test/ELF/undef-with-plt-addr-i686.s create mode 100644 test/ELF/undef-with-plt-addr.s create mode 100644 test/ELF/undef.s create mode 100644 test/ELF/undefined-opt.s create mode 100644 test/ELF/undefined-versioned-symbol.s create mode 100644 test/ELF/unresolved-symbols.s create mode 100644 test/ELF/user_def_init_array_start.s create mode 100644 test/ELF/verdef-defaultver.s create mode 100644 test/ELF/verdef-dependency.s create mode 100644 test/ELF/verdef.s create mode 100644 test/ELF/verneed-as-needed-weak.s create mode 100644 test/ELF/verneed-local.s create mode 100644 test/ELF/verneed.s create mode 100644 test/ELF/version-script-anonymous-local.s create mode 100644 test/ELF/version-script-complex-wildcards.s create mode 100644 test/ELF/version-script-copy-rel.s create mode 100644 test/ELF/version-script-err.s create mode 100644 test/ELF/version-script-extern-exact.s create mode 100644 test/ELF/version-script-extern-wildcards-anon.s create mode 100644 test/ELF/version-script-extern-wildcards.s create mode 100644 test/ELF/version-script-extern.s create mode 100644 test/ELF/version-script-glob.s create mode 100644 test/ELF/version-script-hide-so-symbol.s create mode 100644 test/ELF/version-script-locals-extern.s create mode 100644 test/ELF/version-script-locals.s create mode 100644 test/ELF/version-script-missing.s create mode 100644 test/ELF/version-script-no-warn.s create mode 100644 test/ELF/version-script-no-warn2.s create mode 100644 test/ELF/version-script-noundef.s create mode 100644 test/ELF/version-script-symver.s create mode 100644 test/ELF/version-script-symver2.s create mode 100644 test/ELF/version-script-twice.s create mode 100644 test/ELF/version-script-undef-version.s create mode 100644 test/ELF/version-script-weak.s create mode 100644 test/ELF/version-script.s create mode 100644 test/ELF/version-symbol-error.s create mode 100644 test/ELF/version-undef-sym.s create mode 100644 test/ELF/version-use.s create mode 100644 test/ELF/version-wildcard.test create mode 100644 test/ELF/visibility.s create mode 100644 test/ELF/warn-common.s create mode 100644 test/ELF/warn-unresolved-symbols-hidden.s create mode 100644 test/ELF/warn-unresolved-symbols.s create mode 100644 test/ELF/weak-and-strong-undef.s create mode 100644 test/ELF/weak-undef-hidden.s create mode 100644 test/ELF/weak-undef-shared.s create mode 100644 test/ELF/weak-undef.s create mode 100644 test/ELF/whole-archive.s create mode 100644 test/ELF/wrap-dynamic-undef.s create mode 100644 test/ELF/wrap.s create mode 100644 test/ELF/writable-merge.s create mode 100644 test/ELF/x86-64-dyn-rel-error.s create mode 100644 test/ELF/x86-64-dyn-rel-error2.s create mode 100644 test/ELF/x86-64-rela.s create mode 100644 test/ELF/x86-64-relax-got-abs.s create mode 100644 test/ELF/x86-64-relax-offset.s create mode 100644 test/ELF/x86-64-reloc-16.s create mode 100644 test/ELF/x86-64-reloc-32-fpic.s create mode 100644 test/ELF/x86-64-reloc-8.s create mode 100644 test/ELF/x86-64-reloc-error.s create mode 100644 test/ELF/x86-64-reloc-pc32-fpic.s create mode 100644 test/ELF/x86-64-reloc-range.s create mode 100644 test/ELF/x86-64-reloc-tpoff32-fpic.s create mode 100644 test/ELF/x86-64-tls-gd-got.s create mode 100644 test/ELF/x86-64-tls-gd-local.s create mode 100644 test/ELF/x86-64-tls-pie.s create mode 100644 test/ELF/zdefs.s create mode 100644 test/ELF/zstack-size.s create mode 100644 test/ELF/ztext-text-notext.s create mode 100644 test/Unit/lit.cfg create mode 100644 test/Unit/lit.site.cfg.in create mode 100644 test/darwin/Inputs/native-and-mach-o.objtxt create mode 100644 test/darwin/Inputs/native-and-mach-o2.objtxt create mode 100644 test/darwin/cmdline-objc_gc.objtxt create mode 100644 test/darwin/cmdline-objc_gc_compaction.objtxt create mode 100644 test/darwin/cmdline-objc_gc_only.objtxt create mode 100644 test/darwin/native-and-mach-o.objtxt 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/PIE.yaml create mode 100644 test/mach-o/Inputs/arm-interworking.yaml create mode 100644 test/mach-o/Inputs/arm-shims.yaml create mode 100644 test/mach-o/Inputs/arm64/libSystem.yaml create mode 100644 test/mach-o/Inputs/armv7/libSystem.yaml create mode 100644 test/mach-o/Inputs/bar.yaml create mode 100644 test/mach-o/Inputs/cstring-sections.yaml create mode 100644 test/mach-o/Inputs/exported_symbols_list.exp create mode 100644 test/mach-o/Inputs/full.filelist create mode 100644 test/mach-o/Inputs/got-order.yaml create mode 100644 test/mach-o/Inputs/got-order2.yaml create mode 100644 test/mach-o/Inputs/hello-world-arm64.yaml create mode 100644 test/mach-o/Inputs/hello-world-armv6.yaml create mode 100644 test/mach-o/Inputs/hello-world-armv7.yaml create mode 100644 test/mach-o/Inputs/hello-world-x86.yaml create mode 100644 test/mach-o/Inputs/hello-world-x86_64.yaml create mode 100644 test/mach-o/Inputs/hw.raw_bytes create mode 100644 test/mach-o/Inputs/interposing-section.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64-2.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64-3.yaml create mode 100644 test/mach-o/Inputs/lazy-bind-x86_64.yaml create mode 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/libbar.a create mode 100644 test/mach-o/Inputs/libfoo.a create mode 100644 test/mach-o/Inputs/linker-as-ld.yaml create mode 100644 test/mach-o/Inputs/no-version-min-load-command-object.yaml 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/re-exported-dylib-ordinal.yaml create mode 100644 test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml create mode 100644 test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml create mode 100644 test/mach-o/Inputs/swift-version-1.yaml create mode 100644 test/mach-o/Inputs/unwind-info-simple-arm64.yaml create mode 100644 test/mach-o/Inputs/use-dylib-install-names.yaml create mode 100644 test/mach-o/Inputs/use-simple-dylib.yaml create mode 100644 test/mach-o/Inputs/write-final-sections.yaml create mode 100644 test/mach-o/Inputs/wrong-arch-error.yaml create mode 100644 test/mach-o/Inputs/x86/libSystem.yaml create mode 100644 test/mach-o/Inputs/x86_64/libSystem.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/arm64-reloc-negDelta32-fixup.yaml create mode 100644 test/mach-o/arm64-relocs-errors-delta64-offset.yaml create mode 100644 test/mach-o/arm64-section-order.yaml create mode 100644 test/mach-o/bind-opcodes.yaml create mode 100644 test/mach-o/cstring-sections.yaml create mode 100644 test/mach-o/data-in-code-load-command.yaml create mode 100644 test/mach-o/data-only-dylib.yaml create mode 100644 test/mach-o/dead-strip-globals.yaml create mode 100644 test/mach-o/debug-syms.yaml create mode 100644 test/mach-o/demangle.yaml create mode 100644 test/mach-o/dependency_info.yaml create mode 100644 test/mach-o/do-not-emit-unwind-fde-arm64.yaml create mode 100644 test/mach-o/dso_handle.yaml create mode 100644 test/mach-o/dylib-install-names.yaml create mode 100644 test/mach-o/eh-frame-relocs-arm64.yaml create mode 100644 test/mach-o/error-simulator-vs-macosx.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/executable-exports.yaml create mode 100644 test/mach-o/export-trie-order.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/flat_namespace_undef_error.yaml create mode 100644 test/mach-o/flat_namespace_undef_suppress.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/function-starts-load-command.yaml create mode 100644 test/mach-o/gcc_except_tab-got-arm64.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/lc_segment_filesize.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/mach_header-cpusubtype.yaml 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-category-list-atom.yaml create mode 100644 test/mach-o/objc-image-info-host-vs-simulator.yaml create mode 100644 test/mach-o/objc-image-info-invalid-size.yaml create mode 100644 test/mach-o/objc-image-info-invalid-version.yaml create mode 100644 test/mach-o/objc-image-info-mismatched-swift-version.yaml create mode 100644 test/mach-o/objc-image-info-pass-output.yaml create mode 100644 test/mach-o/objc-image-info-simulator-vs-host.yaml create mode 100644 test/mach-o/objc-image-info-unsupported-gc.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-relocs-x86_64.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/parse-tlv-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/run-tlv-pass-x86-64.yaml create mode 100644 test/mach-o/sdk-version-error.yaml create mode 100644 test/mach-o/sectalign.yaml create mode 100644 test/mach-o/sectattrs.yaml create mode 100644 test/mach-o/sectcreate.yaml create mode 100644 test/mach-o/seg-protection-arm64.yaml create mode 100644 test/mach-o/seg-protection-x86_64.yaml create mode 100644 test/mach-o/source-version.yaml create mode 100644 test/mach-o/stack-size.yaml create mode 100644 test/mach-o/string-table.yaml create mode 100644 test/mach-o/subsections-via-symbols-default.yaml create mode 100644 test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml create mode 100644 test/mach-o/twolevel_namespace_undef_warning_suppress.yaml 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-dylib.yaml create mode 100644 test/mach-o/use-simple-dylib.yaml create mode 100644 test/mach-o/version-min-load-command-object.yaml create mode 100644 test/mach-o/version-min-load-command.yaml create mode 100644 test/mach-o/write-final-sections.yaml create mode 100644 test/mach-o/wrong-arch-error.yaml create mode 100644 tools/lld/CMakeLists.txt create mode 100644 tools/lld/lld.cpp create mode 100644 unittests/CMakeLists.txt create mode 100644 unittests/DriverTests/CMakeLists.txt create mode 100644 unittests/DriverTests/DarwinLdDriverTest.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 diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 000000000..ebf4a4a6f --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "project_id" : "lld", + "conduit_uri" : "https://reviews.llvm.org/" +} diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..9b3aa8b72 --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: LLVM diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..0a288ee8c --- /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 000000000..e2ab0e35f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,224 @@ +# Check if lld is built as a standalone project. +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(lld) + cmake_minimum_required(VERSION 3.4.3) + + set(CMAKE_INCLUDE_CURRENT_DIR ON) + set(LLD_BUILT_STANDALONE TRUE) + + find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary") + if(NOT LLVM_CONFIG_PATH) + message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH") + endif() + + execute_process(COMMAND "${LLVM_CONFIG_PATH}" + "--obj-root" + "--includedir" + "--cmakedir" + "--src-root" + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(HAD_ERROR) + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + + string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}") + + list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT) + list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR) + list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH) + list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR) + + set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree") + set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + + file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR) + + if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake") + message(FATAL_ERROR "LLVMConfig.cmake not found") + endif() + include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake") + + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + + set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}") + include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS}) + link_directories(${LLVM_LIBRARY_DIRS}) + + set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) + find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) + + include(AddLLVM) + include(TableGen) + include(HandleLLVMOptions) + + if(LLVM_INCLUDE_TESTS) + set(Python_ADDITIONAL_VERSIONS 2.7) + include(FindPythonInterp) + if(NOT PYTHONINTERP_FOUND) + message(FATAL_ERROR +"Unable to find Python interpreter, required for testing. + +Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") + endif() + + if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7) + message(FATAL_ERROR "Python 2.7 or newer is required") + endif() + + # Check prebuilt llvm/utils. + if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX} + AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX}) + set(LLVM_UTILS_PROVIDED ON) + endif() + + if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) + # Note: path not really used, except for checking if lit was found + set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) + if(NOT LLVM_UTILS_PROVIDED) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not) + set(LLVM_UTILS_PROVIDED ON) + set(LLD_TEST_DEPS FileCheck not) + endif() + set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest) + if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h + AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX} + AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt) + add_subdirectory(${UNITTEST_DIR} utils/unittest) + endif() + else() + # Seek installed Lit. + find_program(LLVM_LIT + NAMES llvm-lit lit.py lit + PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit" + DOC "Path to lit.py") + endif() + + if(LLVM_LIT) + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. + if(WIN32 AND NOT CYGWIN) + set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") + endif() + else() + set(LLVM_INCLUDE_TESTS OFF) + endif() + endif() +endif() + +set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include ) +set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +# Compute the LLD version from the LLVM version. +string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION + ${PACKAGE_VERSION}) +message(STATUS "LLD version: ${LLD_VERSION}") + +string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR + ${LLD_VERSION}) +string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR + ${LLD_VERSION}) + +# Determine LLD revision and repository. +# TODO: Figure out a way to get the revision and the repository on windows. +if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" ) + execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR} + OUTPUT_VARIABLE LLD_REVISION) + + execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR} + OUTPUT_VARIABLE LLD_REPOSITORY) + if ( LLD_REPOSITORY ) + # Replace newline characters with spaces + string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY}) + # Remove leading spaces + STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" ) + # Remove trailing spaces + string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY}) + endif() + + if ( LLD_REVISION ) + # Replace newline characters with spaces + string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION}) + # Remove leading spaces + STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" ) + # Remove trailing spaces + string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION}) + endif() +endif () + +# Configure the Version.inc file. +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/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") + +include(AddLLD) + +option(LLD_USE_VTUNE + "Enable VTune user task tracking." + OFF) +if (LLD_USE_VTUNE) + find_package(VTune) + if (VTUNE_FOUND) + include_directories(${VTune_INCLUDE_DIRS}) + list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES}) + add_definitions(-DLLD_HAS_VTUNE) + endif() +endif() + +option(LLD_BUILD_TOOLS + "Build the lld tools. If OFF, just generate build targets." ON) + +if (MSVC) + add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.' + add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header. +endif() + +include_directories(BEFORE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include + ) + +if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + install(DIRECTORY include/ + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN ".svn" EXCLUDE + ) +endif() + +add_subdirectory(lib) +add_subdirectory(tools/lld) + +if (LLVM_INCLUDE_TESTS) + add_subdirectory(test) + add_subdirectory(unittests) +endif() + +add_subdirectory(docs) +add_subdirectory(COFF) +add_subdirectory(ELF) + diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT new file mode 100644 index 000000000..292967e58 --- /dev/null +++ b/CODE_OWNERS.TXT @@ -0,0 +1,19 @@ +This file is a list of the people responsible for ensuring that patches for a +particular part of LLD are reviewed, either by themself or by someone else. +They are also the gatekeepers for their part of LLD, with the final word on +what goes in or not. + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). Each entry should contain at least the (N), (E) and (D) fields. + + +N: Rui Ueyama +E: ruiu@google.com +D: COFF, ELF backends (COFF/* ELF/*) + +N: Lang Hames, Nick Kledzik +E: lhames@gmail.com, kledzik@apple.com +D: Mach-O backend + diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt new file mode 100644 index 000000000..e56593497 --- /dev/null +++ b/COFF/CMakeLists.txt @@ -0,0 +1,50 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(COFFOptionsTableGen) + +if(NOT LLD_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_lld_library(lldCOFF + Chunks.cpp + DLL.cpp + Driver.cpp + DriverUtils.cpp + Error.cpp + ICF.cpp + InputFiles.cpp + LTO.cpp + MapFile.cpp + MarkLive.cpp + PDB.cpp + Strings.cpp + SymbolTable.cpp + Symbols.cpp + Writer.cpp + + LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + BinaryFormat + BitReader + Core + DebugInfoCodeView + DebugInfoMSF + DebugInfoPDB + LTO + LibDriver + Object + MC + MCDisassembler + Target + Option + Support + + LINK_LIBS + lldCore + ${LLVM_PTHREAD_LIB} + + DEPENDS + COFFOptionsTableGen + ${tablegen_deps} + ) diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp new file mode 100644 index 000000000..7d93c28c8 --- /dev/null +++ b/COFF/Chunks.cpp @@ -0,0 +1,500 @@ +//===- Chunks.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "Writer.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::COFF; +using llvm::support::ulittle32_t; + +namespace lld { +namespace coff { + +SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H) + : Chunk(SectionKind), Repl(this), Header(H), File(F), + Relocs(File->getCOFFObj()->getRelocations(Header)), + NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { + // Initialize SectionName. + File->getCOFFObj()->getSectionName(Header, SectionName); + + Align = Header->getAlignment(); + + // Chunks may be discarded during comdat merging. + Discarded = false; + + // If linker GC is disabled, every chunk starts out alive. If linker GC is + // enabled, treat non-comdat sections as roots. Generally optimized object + // files will be built with -ffunction-sections or /Gy, so most things worth + // stripping will be in a comdat. + Live = !Config->DoGC || !isCOMDAT(); +} + +static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } +static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } +static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } +static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } + +static void applySecRel(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!OS) { + if (Sec->isCodeView()) + return; + fatal("SECREL relocation cannot be applied to absolute symbols"); + } + uint64_t SecRel = S - OS->getRVA(); + assert(SecRel < INT32_MAX && "overflow in SECREL relocation"); + add32(Off, SecRel); +} + +static void applySecIdx(uint8_t *Off, OutputSection *OS) { + // If we have no output section, this must be an absolute symbol. Use the + // sentinel absolute symbol section index. + uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex; + add16(Off, SecIdx); +} + +void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; + case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; + case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; + case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; + case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; + case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; + case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + +void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_I386_ABSOLUTE: break; + case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; + case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + +static void applyMOV(uint8_t *Off, uint16_t V) { + write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); + write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); +} + +static uint16_t readMOV(uint8_t *Off) { + uint16_t Opcode1 = read16le(Off); + uint16_t Opcode2 = read16le(Off + 2); + uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); + Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); + return Imm; +} + +static void applyMOV32T(uint8_t *Off, uint32_t V) { + uint16_t ImmW = readMOV(Off); // read MOVW operand + uint16_t ImmT = readMOV(Off + 4); // read MOVT operand + uint32_t Imm = ImmW | (ImmT << 16); + V += Imm; // add the immediate offset + applyMOV(Off, V); // set MOVW operand + applyMOV(Off + 4, V >> 16); // set MOVT operand +} + +static void applyBranch20T(uint8_t *Off, int32_t V) { + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = (V >> 19) & 1; + uint32_t J2 = (V >> 18) & 1; + or16(Off, (S << 10) | ((V >> 12) & 0x3f)); + or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); +} + +static void applyBranch24T(uint8_t *Off, int32_t V) { + if (!isInt<25>(V)) + fatal("relocation out of range"); + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = ((~V >> 23) & 1) ^ S; + uint32_t J2 = ((~V >> 22) & 1) ^ S; + or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); + // Clear out the J1 and J2 bits which may be set. + write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); +} + +void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + // Pointer to thumb code must have the LSB set. + uint64_t SX = S; + if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + SX |= 1; + switch (Type) { + case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; + case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + +static void applyArm64Addr(uint8_t *Off, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi); +} + +// Update the immediate field in a AARCH64 ldr, str, and add instruction. +static void applyArm64Imm(uint8_t *Off, uint64_t Imm) { + uint32_t Orig = read32le(Off); + Imm += (Orig >> 10) & 0xFFF; + Orig &= ~(0xFFF << 10); + write32le(Off, Orig | ((Imm & 0xFFF) << 10)); +} + +static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { + int Size = read32le(Off) >> 30; + Imm >>= Size; + applyArm64Imm(Off, Imm); +} + +void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; + case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + +void SectionChunk::writeTo(uint8_t *Buf) const { + if (!hasData()) + return; + // Copy section contents from source object file to output file. + ArrayRef A = getContents(); + memcpy(Buf + OutputSectionOff, A.data(), A.size()); + + // Apply relocations. + size_t InputSize = getSize(); + for (const coff_relocation &Rel : Relocs) { + // Check for an invalid relocation offset. This check isn't perfect, because + // we don't have the relocation size, which is only known after checking the + // machine and relocation type. As a result, a relocation may overwrite the + // beginning of the following input section. + if (Rel.VirtualAddress >= InputSize) + fatal("relocation points beyond the end of its parent section"); + + uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; + + // Get the output section of the symbol for this relocation. The output + // section is needed to compute SECREL and SECTION relocations used in debug + // info. + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); + Defined *Sym = cast(Body); + Chunk *C = Sym->getChunk(); + OutputSection *OS = C ? C->getOutputSection() : nullptr; + + // Only absolute and __ImageBase symbols lack an output section. For any + // other symbol, this indicates that the chunk was discarded. Normally + // relocations against discarded sections are an error. However, debug info + // sections are not GC roots and can end up with these kinds of relocations. + // Skip these relocations. + if (!OS && !isa(Sym) && !isa(Sym)) { + if (isCodeView() || isDWARF()) + continue; + fatal("relocation against symbol in discarded section: " + + Sym->getName()); + } + uint64_t S = Sym->getRVA(); + + // Compute the RVA of the relocation for relative relocations. + uint64_t P = RVA + Rel.VirtualAddress; + switch (Config->Machine) { + case AMD64: + applyRelX64(Off, Rel.Type, OS, S, P); + break; + case I386: + applyRelX86(Off, Rel.Type, OS, S, P); + break; + case ARMNT: + applyRelARM(Off, Rel.Type, OS, S, P); + break; + case ARM64: + applyRelARM64(Off, Rel.Type, OS, S, P); + break; + default: + llvm_unreachable("unknown machine type"); + } + } +} + +void SectionChunk::addAssociative(SectionChunk *Child) { + AssocChildren.push_back(Child); +} + +static uint8_t getBaserelType(const coff_relocation &Rel) { + switch (Config->Machine) { + case AMD64: + if (Rel.Type == IMAGE_REL_AMD64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; + case I386: + if (Rel.Type == IMAGE_REL_I386_DIR32) + return IMAGE_REL_BASED_HIGHLOW; + return IMAGE_REL_BASED_ABSOLUTE; + case ARMNT: + if (Rel.Type == IMAGE_REL_ARM_ADDR32) + return IMAGE_REL_BASED_HIGHLOW; + if (Rel.Type == IMAGE_REL_ARM_MOV32T) + return IMAGE_REL_BASED_ARM_MOV32T; + return IMAGE_REL_BASED_ABSOLUTE; + case ARM64: + if (Rel.Type == IMAGE_REL_ARM64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Windows-specific. +// Collect all locations that contain absolute addresses, which need to be +// fixed by the loader if load-time relocation is needed. +// Only called when base relocation is enabled. +void SectionChunk::getBaserels(std::vector *Res) { + for (const coff_relocation &Rel : Relocs) { + uint8_t Ty = getBaserelType(Rel); + if (Ty == IMAGE_REL_BASED_ABSOLUTE) + continue; + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); + if (isa(Body)) + continue; + Res->emplace_back(RVA + Rel.VirtualAddress, Ty); + } +} + +bool SectionChunk::hasData() const { + return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); +} + +uint32_t SectionChunk::getPermissions() const { + return Header->Characteristics & PermMask; +} + +bool SectionChunk::isCOMDAT() const { + return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; +} + +void SectionChunk::printDiscardedMessage() const { + // Removed by dead-stripping. If it's removed by ICF, ICF already + // printed out the name, so don't repeat that here. + if (Sym && this == Repl) { + if (Discarded) + message("Discarded comdat symbol " + Sym->getName()); + else if (!Live) + message("Discarded " + Sym->getName()); + } +} + +StringRef SectionChunk::getDebugName() { + if (Sym) + return Sym->getName(); + return ""; +} + +ArrayRef SectionChunk::getContents() const { + ArrayRef A; + File->getCOFFObj()->getSectionContents(Header, A); + return A; +} + +void SectionChunk::replace(SectionChunk *Other) { + Other->Repl = Repl; + Other->Live = false; +} + +CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { + // Common symbols are aligned on natural boundaries up to 32 bytes. + // This is what MSVC link.exe does. + Align = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); +} + +uint32_t CommonChunk::getPermissions() const { + return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | + IMAGE_SCN_MEM_WRITE; +} + +void StringChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); +} + +ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { + // Intel Optimization Manual says that all branch targets + // should be 16-byte aligned. MSVC linker does this too. + Align = 16; +} + +void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); + // The first two bytes is a JMP instruction. Fill its operand. + write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); +} + +void ImportThunkChunkX86::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA() + 2); +} + +void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); + // The first two bytes is a JMP instruction. Fill its operand. + write32le(Buf + OutputSectionOff + 2, + ImpSymbol->getRVA() + Config->ImageBase); +} + +void ImportThunkChunkARM::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); +} + +void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); + // Fix mov.w and mov.t operands. + applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); +} + +void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { + int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12); + int64_t Off = ImpSymbol->getRVA() & 0xfff; + memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); + applyArm64Addr(Buf + OutputSectionOff, PageOff); + applyArm64Ldr(Buf + OutputSectionOff + 4, Off); +} + +void LocalImportChunk::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA()); +} + +size_t LocalImportChunk::getSize() const { + return Config->is64() ? 8 : 4; +} + +void LocalImportChunk::writeTo(uint8_t *Buf) const { + if (Config->is64()) { + write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + } else { + write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + } +} + +void SEHTableChunk::writeTo(uint8_t *Buf) const { + ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); + size_t Cnt = 0; + for (Defined *D : Syms) + Begin[Cnt++] = D->getRVA(); + std::sort(Begin, Begin + Cnt); +} + +// Windows-specific. This class represents a block in .reloc section. +// The format is described here. +// +// On Windows, each DLL is linked against a fixed base address and +// usually loaded to that address. However, if there's already another +// DLL that overlaps, the loader has to relocate it. To do that, DLLs +// contain .reloc sections which contain offsets that need to be fixed +// up at runtime. If the loader finds that a DLL cannot be loaded to its +// desired base address, it loads it to somewhere else, and add - to each offset that is +// specified by the .reloc section. In ELF terms, .reloc sections +// contain relative relocations in REL format (as opposed to RELA.) +// +// This already significantly reduces the size of relocations compared +// to ELF .rel.dyn, but Windows does more to reduce it (probably because +// it was invented for PCs in the late '80s or early '90s.) Offsets in +// .reloc are grouped by page where the page size is 12 bits, and +// offsets sharing the same page address are stored consecutively to +// represent them with less space. This is very similar to the page +// table which is grouped by (multiple stages of) pages. +// +// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00, +// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4 +// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they +// are represented like this: +// +// 0x00000 -- page address (4 bytes) +// 16 -- size of this block (4 bytes) +// 0xA030 -- entries (2 bytes each) +// 0xA500 +// 0xA700 +// 0xAA00 +// 0x20000 -- page address (4 bytes) +// 12 -- size of this block (4 bytes) +// 0xA004 -- entries (2 bytes each) +// 0xA008 +// +// Usually we have a lot of relocations for each page, so the number of +// bytes for one .reloc entry is close to 2 bytes on average. +BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { + // Block header consists of 4 byte page RVA and 4 byte block size. + // Each entry is 2 byte. Last entry may be padding. + Data.resize(alignTo((End - Begin) * 2 + 8, 4)); + uint8_t *P = Data.data(); + write32le(P, Page); + write32le(P + 4, Data.size()); + P += 8; + for (Baserel *I = Begin; I != End; ++I) { + write16le(P, (I->Type << 12) | (I->RVA - Page)); + P += 2; + } +} + +void BaserelChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); +} + +uint8_t Baserel::getDefaultType() { + switch (Config->Machine) { + case AMD64: + return IMAGE_REL_BASED_DIR64; + case I386: + return IMAGE_REL_BASED_HIGHLOW; + default: + llvm_unreachable("unknown machine type"); + } +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Chunks.h b/COFF/Chunks.h new file mode 100644 index 000000000..ece5419e2 --- /dev/null +++ b/COFF/Chunks.h @@ -0,0 +1,375 @@ +//===- Chunks.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_CHUNKS_H +#define LLD_COFF_CHUNKS_H + +#include "Config.h" +#include "InputFiles.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/COFF.h" +#include +#include + +namespace lld { +namespace coff { + +using llvm::COFF::ImportDirectoryTableEntry; +using llvm::object::COFFSymbolRef; +using llvm::object::SectionRef; +using llvm::object::coff_relocation; +using llvm::object::coff_section; + +class Baserel; +class Defined; +class DefinedImportData; +class DefinedRegular; +class ObjectFile; +class OutputSection; +class SymbolBody; + +// Mask for section types (code, data, bss, disacardable, etc.) +// and permissions (writable, readable or executable). +const uint32_t PermMask = 0xFF0000F0; + +// A Chunk represents a chunk of data that will occupy space in the +// output (if the resolver chose that). It may or may not be backed by +// a section of an input file. It could be linker-created data, or +// doesn't even have actual data (if common or bss). +class Chunk { +public: + enum Kind { SectionKind, OtherKind }; + Kind kind() const { return ChunkKind; } + virtual ~Chunk() = default; + + // Returns the size of this chunk (even if this is a common or BSS.) + virtual size_t getSize() const = 0; + + // Write this chunk to a mmap'ed file, assuming Buf is pointing to + // beginning of the file. Because this function may use RVA values + // of other chunks for relocations, you need to set them properly + // before calling this function. + virtual void writeTo(uint8_t *Buf) const {} + + // The writer sets and uses the addresses. + uint64_t getRVA() const { return RVA; } + uint32_t getAlign() const { return Align; } + void setRVA(uint64_t V) { RVA = V; } + + // Returns true if this has non-zero data. BSS chunks return + // false. If false is returned, the space occupied by this chunk + // will be filled with zeros. + virtual bool hasData() const { return true; } + + // Returns readable/writable/executable bits. + virtual uint32_t getPermissions() const { return 0; } + + // Returns the section name if this is a section chunk. + // It is illegal to call this function on non-section chunks. + virtual StringRef getSectionName() const { + llvm_unreachable("unimplemented getSectionName"); + } + + // An output section has pointers to chunks in the section, and each + // chunk has a back pointer to an output section. + void setOutputSection(OutputSection *O) { Out = O; } + OutputSection *getOutputSection() { return Out; } + + // Windows-specific. + // Collect all locations that contain absolute addresses for base relocations. + virtual void getBaserels(std::vector *Res) {} + + // Returns a human-readable name of this chunk. Chunks are unnamed chunks of + // bytes, so this is used only for logging or debugging. + virtual StringRef getDebugName() { return ""; } + +protected: + Chunk(Kind K = OtherKind) : ChunkKind(K) {} + const Kind ChunkKind; + + // The alignment of this chunk. The writer uses the value. + uint32_t Align = 1; + + // The RVA of this chunk in the output. The writer sets a value. + uint64_t RVA = 0; + +public: + // The offset from beginning of the output section. The writer sets a value. + uint64_t OutputSectionOff = 0; + +protected: + // The output section for this chunk. + OutputSection *Out = nullptr; +}; + +// A chunk corresponding a section of an input file. +class SectionChunk final : public Chunk { + // Identical COMDAT Folding feature accesses section internal data. + friend class ICF; + +public: + class symbol_iterator : public llvm::iterator_adaptor_base< + symbol_iterator, const coff_relocation *, + std::random_access_iterator_tag, SymbolBody *> { + friend SectionChunk; + + ObjectFile *File; + + symbol_iterator(ObjectFile *File, const coff_relocation *I) + : symbol_iterator::iterator_adaptor_base(I), File(File) {} + + public: + symbol_iterator() = default; + + SymbolBody *operator*() const { + return File->getSymbolBody(I->SymbolTableIndex); + } + }; + + SectionChunk(ObjectFile *File, const coff_section *Header); + static bool classof(const Chunk *C) { return C->kind() == SectionKind; } + size_t getSize() const override { return Header->SizeOfRawData; } + ArrayRef getContents() const; + void writeTo(uint8_t *Buf) const override; + bool hasData() const override; + uint32_t getPermissions() const override; + StringRef getSectionName() const override { return SectionName; } + void getBaserels(std::vector *Res) override; + bool isCOMDAT() const; + void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + + // Called if the garbage collector decides to not include this chunk + // in a final output. It's supposed to print out a log message to stdout. + void printDiscardedMessage() const; + + // Adds COMDAT associative sections to this COMDAT section. A chunk + // and its children are treated as a group by the garbage collector. + void addAssociative(SectionChunk *Child); + + StringRef getDebugName() override; + void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; } + + // Returns true if the chunk was not dropped by GC or COMDAT deduplication. + bool isLive() { return Live && !Discarded; } + + // Used by the garbage collector. + void markLive() { + assert(Config->DoGC && "should only mark things live from GC"); + assert(!isLive() && "Cannot mark an already live section!"); + Live = true; + } + + // Returns true if this chunk was dropped by COMDAT deduplication. + bool isDiscarded() const { return Discarded; } + + // Used by the SymbolTable when discarding unused comdat sections. This is + // redundant when GC is enabled, as all comdat sections will start out dead. + void markDiscarded() { Discarded = true; } + + // True if this is a codeview debug info chunk. These will not be laid out in + // the image. Instead they will end up in the PDB, if one is requested. + bool isCodeView() const { + return SectionName == ".debug" || SectionName.startswith(".debug$"); + } + + // True if this is a DWARF debug info chunk. + bool isDWARF() const { return SectionName.startswith(".debug_"); } + + // Allow iteration over the bodies of this chunk's relocated symbols. + llvm::iterator_range symbols() const { + return llvm::make_range(symbol_iterator(File, Relocs.begin()), + symbol_iterator(File, Relocs.end())); + } + + // Allow iteration over the associated child chunks for this section. + ArrayRef children() const { return AssocChildren; } + + // A pointer pointing to a replacement for this chunk. + // Initially it points to "this" object. If this chunk is merged + // with other chunk by ICF, it points to another chunk, + // and this chunk is considrered as dead. + SectionChunk *Repl; + + // The CRC of the contents as described in the COFF spec 4.5.5. + // Auxiliary Format 5: Section Definitions. Used for ICF. + uint32_t Checksum = 0; + + const coff_section *Header; + + // The file that this chunk was created from. + ObjectFile *File; + +private: + StringRef SectionName; + std::vector AssocChildren; + llvm::iterator_range Relocs; + size_t NumRelocs; + + // True if this chunk was discarded because it was a duplicate comdat section. + bool Discarded; + + // Used by the garbage collector. + bool Live; + + // Used for ICF (Identical COMDAT Folding) + void replace(SectionChunk *Other); + uint32_t Class[2] = {0, 0}; + + // Sym points to a section symbol if this is a COMDAT chunk. + DefinedRegular *Sym = nullptr; +}; + +// A chunk for common symbols. Common chunks don't have actual data. +class CommonChunk : public Chunk { +public: + CommonChunk(const COFFSymbolRef Sym); + size_t getSize() const override { return Sym.getValue(); } + bool hasData() const override { return false; } + uint32_t getPermissions() const override; + StringRef getSectionName() const override { return ".bss"; } + +private: + const COFFSymbolRef Sym; +}; + +// A chunk for linker-created strings. +class StringChunk : public Chunk { +public: + explicit StringChunk(StringRef S) : Str(S) {} + size_t getSize() const override { return Str.size() + 1; } + void writeTo(uint8_t *Buf) const override; + +private: + StringRef Str; +}; + +static const uint8_t ImportThunkX86[] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 +}; + +static const uint8_t ImportThunkARM[] = { + 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 + 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 + 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] +}; + +static const uint8_t ImportThunkARM64[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 + 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] + 0x00, 0x02, 0x1f, 0xd6, // br x16 +}; + +// Windows-specific. +// A chunk for DLL import jump table entry. In a final output, it's +// contents will be a JMP instruction to some __imp_ symbol. +class ImportThunkChunkX64 : public Chunk { +public: + explicit ImportThunkChunkX64(Defined *S); + size_t getSize() const override { return sizeof(ImportThunkX86); } + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +class ImportThunkChunkX86 : public Chunk { +public: + explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkX86); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +class ImportThunkChunkARM : public Chunk { +public: + explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +class ImportThunkChunkARM64 : public Chunk { +public: + explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM64); } + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + +// Windows-specific. +// See comments for DefinedLocalImport class. +class LocalImportChunk : public Chunk { +public: + explicit LocalImportChunk(Defined *S) : Sym(S) {} + size_t getSize() const override; + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *Sym; +}; + +// Windows-specific. +// A chunk for SEH table which contains RVAs of safe exception handler +// functions. x86-only. +class SEHTableChunk : public Chunk { +public: + explicit SEHTableChunk(std::set S) : Syms(std::move(S)) {} + size_t getSize() const override { return Syms.size() * 4; } + void writeTo(uint8_t *Buf) const override; + +private: + std::set Syms; +}; + +// Windows-specific. +// This class represents a block in .reloc section. +// See the PE/COFF spec 5.6 for details. +class BaserelChunk : public Chunk { +public: + BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); + size_t getSize() const override { return Data.size(); } + void writeTo(uint8_t *Buf) const override; + +private: + std::vector Data; +}; + +class Baserel { +public: + Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} + explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} + uint8_t getDefaultType(); + + uint32_t RVA; + uint8_t Type; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Config.h b/COFF/Config.h new file mode 100644 index 000000000..7f8259d01 --- /dev/null +++ b/COFF/Config.h @@ -0,0 +1,174 @@ +//===- Config.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_CONFIG_H +#define LLD_COFF_CONFIG_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFF.h" +#include +#include +#include +#include + +namespace lld { +namespace coff { + +using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; +using llvm::COFF::WindowsSubsystem; +using llvm::StringRef; +class DefinedAbsolute; +class DefinedRelative; +class StringChunk; +struct Symbol; +class SymbolBody; + +// Short aliases. +static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; +static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64; +static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; +static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; + +// Represents an /export option. +struct Export { + StringRef Name; // N in /export:N or /export:E=N + StringRef ExtName; // E in /export:E=N + SymbolBody *Sym = nullptr; + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + bool Constant = false; + + // If an export is a form of /export:foo=dllname.bar, that means + // that foo should be exported as an alias to bar in the DLL. + // ForwardTo is set to "dllname.bar" part. Usually empty. + StringRef ForwardTo; + StringChunk *ForwardChunk = nullptr; + + // True if this /export option was in .drectves section. + bool Directives = false; + StringRef SymbolName; + StringRef ExportName; // Name in DLL + + bool operator==(const Export &E) { + return (Name == E.Name && ExtName == E.ExtName && + Ordinal == E.Ordinal && Noname == E.Noname && + Data == E.Data && Private == E.Private); + } +}; + +enum class DebugType { + None = 0x0, + CV = 0x1, /// CodeView + PData = 0x2, /// Procedure Data + Fixup = 0x4, /// Relocation Table +}; + +// Global configuration. +struct Configuration { + enum ManifestKind { SideBySide, Embed, No }; + bool is64() { return Machine == AMD64 || Machine == ARM64; } + + llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; + bool Verbose = false; + WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; + SymbolBody *Entry = nullptr; + bool NoEntry = false; + std::string OutputFile; + std::string ImportName; + bool ColorDiagnostics; + bool DoGC = true; + bool DoICF = true; + uint64_t ErrorLimit = 20; + bool Relocatable = true; + bool Force = false; + bool Debug = false; + bool WriteSymtab = true; + unsigned DebugTypes = static_cast(DebugType::None); + llvm::SmallString<128> PDBPath; + std::vector Argv; + + // Symbols in this set are considered as live by the garbage collector. + std::set GCRoot; + + std::set NoDefaultLibs; + bool NoDefaultLibAll = false; + + // True if we are creating a DLL. + bool DLL = false; + StringRef Implib; + std::vector Exports; + std::set DelayLoads; + std::map DLLOrder; + SymbolBody *DelayLoadHelper = nullptr; + + bool SaveTemps = false; + + // Used for SafeSEH. + Symbol *SEHTable = nullptr; + Symbol *SEHCount = nullptr; + + // Used for /opt:lldlto=N + unsigned LTOOptLevel = 2; + + // Used for /opt:lldltojobs=N + unsigned LTOJobs = 0; + // Used for /opt:lldltopartitions=N + unsigned LTOPartitions = 1; + + // Used for /merge:from=to (e.g. /merge:.rdata=.text) + std::map Merge; + + // Used for /section=.name,{DEKPRSW} to set section attributes. + std::map Section; + + // Options for manifest files. + ManifestKind Manifest = No; + int ManifestID = 1; + StringRef ManifestDependency; + bool ManifestUAC = true; + std::vector ManifestInput; + StringRef ManifestLevel = "'asInvoker'"; + StringRef ManifestUIAccess = "'false'"; + StringRef ManifestFile; + + // Used for /failifmismatch. + std::map MustMatch; + + // Used for /alternatename. + std::map AlternateNames; + + // Used for /lldmap. + std::string MapFile; + + uint64_t ImageBase = -1; + uint64_t StackReserve = 1024 * 1024; + uint64_t StackCommit = 4096; + uint64_t HeapReserve = 1024 * 1024; + uint64_t HeapCommit = 4096; + uint32_t MajorImageVersion = 0; + uint32_t MinorImageVersion = 0; + uint32_t MajorOSVersion = 6; + uint32_t MinorOSVersion = 0; + bool DynamicBase = true; + bool NxCompat = true; + bool AllowIsolation = true; + bool TerminalServerAware = true; + bool LargeAddressAware = false; + bool HighEntropyVA = false; + bool AppContainer = false; +}; + +extern Configuration *Config; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp new file mode 100644 index 000000000..d76410b67 --- /dev/null +++ b/COFF/DLL.cpp @@ -0,0 +1,548 @@ +//===- DLL.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines various types of chunks for the DLL import or export +// descriptor tables. They are inherently Windows-specific. +// You need to read Microsoft PE/COFF spec to understand details +// about the data structures. +// +// If you are not particularly interested in linking against Windows +// DLL, you can skip this file, and you should still be able to +// understand the rest of the linker. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "DLL.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Path.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::COFF; + +namespace lld { +namespace coff { +namespace { + +// Import table + +static int ptrSize() { return Config->is64() ? 8 : 4; } + +// A chunk for the import descriptor table. +class HintNameChunk : public Chunk { +public: + HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} + + size_t getSize() const override { + // Starts with 2 byte Hint field, followed by a null-terminated string, + // ends with 0 or 1 byte padding. + return alignTo(Name.size() + 3, 2); + } + + void writeTo(uint8_t *Buf) const override { + write16le(Buf + OutputSectionOff, Hint); + memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); + } + +private: + StringRef Name; + uint16_t Hint; +}; + +// A chunk for the import descriptor table. +class LookupChunk : public Chunk { +public: + explicit LookupChunk(Chunk *C) : HintName(C) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + write32le(Buf + OutputSectionOff, HintName->getRVA()); + } + + Chunk *HintName; +}; + +// A chunk for the import descriptor table. +// This chunk represent import-by-ordinal symbols. +// See Microsoft PE/COFF spec 7.1. Import Header for details. +class OrdinalOnlyChunk : public Chunk { +public: + explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + // An import-by-ordinal slot has MSB 1 to indicate that + // this is import-by-ordinal (and not import-by-name). + if (Config->is64()) { + write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); + } else { + write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); + } + } + + uint16_t Ordinal; +}; + +// A chunk for the import descriptor table. +class ImportDirectoryChunk : public Chunk { +public: + explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} + size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } + + void writeTo(uint8_t *Buf) const override { + auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); + E->ImportLookupTableRVA = LookupTab->getRVA(); + E->NameRVA = DLLName->getRVA(); + E->ImportAddressTableRVA = AddressTab->getRVA(); + } + + Chunk *DLLName; + Chunk *LookupTab; + Chunk *AddressTab; +}; + +// A chunk representing null terminator in the import table. +// Contents of this chunk is always null bytes. +class NullChunk : public Chunk { +public: + explicit NullChunk(size_t N) : Size(N) {} + bool hasData() const override { return false; } + size_t getSize() const override { return Size; } + void setAlign(size_t N) { Align = N; } + +private: + size_t Size; +}; + +static std::vector> +binImports(const std::vector &Imports) { + // Group DLL-imported symbols by DLL name because that's how + // symbols are layed out in the import descriptor table. + auto Less = [](const std::string &A, const std::string &B) { + return Config->DLLOrder[A] < Config->DLLOrder[B]; + }; + std::map, + bool(*)(const std::string &, const std::string &)> M(Less); + for (DefinedImportData *Sym : Imports) + M[Sym->getDLLName().lower()].push_back(Sym); + + std::vector> V; + for (auto &KV : M) { + // Sort symbols by name for each group. + std::vector &Syms = KV.second; + std::sort(Syms.begin(), Syms.end(), + [](DefinedImportData *A, DefinedImportData *B) { + return A->getName() < B->getName(); + }); + V.push_back(std::move(Syms)); + } + return V; +} + +// Export table +// See Microsoft PE/COFF spec 4.3 for details. + +// A chunk for the delay import descriptor table etnry. +class DelayDirectoryChunk : public Chunk { +public: + explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} + + size_t getSize() const override { + return sizeof(delay_import_directory_table_entry); + } + + void writeTo(uint8_t *Buf) const override { + auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); + E->Attributes = 1; + E->Name = DLLName->getRVA(); + E->ModuleHandle = ModuleHandle->getRVA(); + E->DelayImportAddressTable = AddressTab->getRVA(); + E->DelayImportNameTable = NameTab->getRVA(); + } + + Chunk *DLLName; + Chunk *ModuleHandle; + Chunk *AddressTab; + Chunk *NameTab; +}; + +// Initial contents for delay-loaded functions. +// This code calls __delayLoadHelper2 function to resolve a symbol +// and then overwrites its jump table slot with the result +// for subsequent function calls. +static const uint8_t ThunkX64[] = { + 0x51, // push rcx + 0x52, // push rdx + 0x41, 0x50, // push r8 + 0x41, 0x51, // push r9 + 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h + 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 + 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 + 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 + 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 + 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] + 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] + 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 + 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] + 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] + 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] + 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] + 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h + 0x41, 0x59, // pop r9 + 0x41, 0x58, // pop r8 + 0x5A, // pop rdx + 0x59, // pop rcx + 0xFF, 0xE0, // jmp rax +}; + +static const uint8_t ThunkX86[] = { + 0x51, // push ecx + 0x52, // push edx + 0x68, 0, 0, 0, 0, // push offset ___imp__ + 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll + 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 + 0x5A, // pop edx + 0x59, // pop ecx + 0xFF, 0xE0, // jmp eax +}; + +// A chunk for the delay import thunk. +class ThunkChunkX64 : public Chunk { +public: + ThunkChunkX64(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkX64); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); + write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); + write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); + write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); + } + + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; +}; + +class ThunkChunkX86 : public Chunk { +public: + ThunkChunkX86(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkX86); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); + write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); + } + + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA + 3); + Res->emplace_back(RVA + 8); + } + + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; +}; + +// A chunk for the import descriptor table. +class DelayAddressChunk : public Chunk { +public: + explicit DelayAddressChunk(Chunk *C) : Thunk(C) {} + size_t getSize() const override { return ptrSize(); } + + void writeTo(uint8_t *Buf) const override { + if (Config->is64()) { + write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + } else { + write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + } + } + + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA); + } + + Chunk *Thunk; +}; + +// Export table +// Read Microsoft PE/COFF spec 5.3 for details. + +// A chunk for the export descriptor table. +class ExportDirectoryChunk : public Chunk { +public: + ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) + : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), + OrdinalTab(O) {} + + size_t getSize() const override { + return sizeof(export_directory_table_entry); + } + + void writeTo(uint8_t *Buf) const override { + auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); + E->NameRVA = DLLName->getRVA(); + E->OrdinalBase = 0; + E->AddressTableEntries = MaxOrdinal + 1; + E->NumberOfNamePointers = NameTabSize; + E->ExportAddressTableRVA = AddressTab->getRVA(); + E->NamePointerRVA = NameTab->getRVA(); + E->OrdinalTableRVA = OrdinalTab->getRVA(); + } + + uint16_t MaxOrdinal; + uint16_t NameTabSize; + Chunk *DLLName; + Chunk *AddressTab; + Chunk *NameTab; + Chunk *OrdinalTab; +}; + +class AddressTableChunk : public Chunk { +public: + explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} + size_t getSize() const override { return Size * 4; } + + void writeTo(uint8_t *Buf) const override { + for (Export &E : Config->Exports) { + uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; + if (E.ForwardChunk) { + write32le(P, E.ForwardChunk->getRVA()); + } else { + write32le(P, cast(E.Sym)->getRVA()); + } + } + } + +private: + size_t Size; +}; + +class NamePointersChunk : public Chunk { +public: + explicit NamePointersChunk(std::vector &V) : Chunks(V) {} + size_t getSize() const override { return Chunks.size() * 4; } + + void writeTo(uint8_t *Buf) const override { + uint8_t *P = Buf + OutputSectionOff; + for (Chunk *C : Chunks) { + write32le(P, C->getRVA()); + P += 4; + } + } + +private: + std::vector Chunks; +}; + +class ExportOrdinalChunk : public Chunk { +public: + explicit ExportOrdinalChunk(size_t I) : Size(I) {} + size_t getSize() const override { return Size * 2; } + + void writeTo(uint8_t *Buf) const override { + uint8_t *P = Buf + OutputSectionOff; + for (Export &E : Config->Exports) { + if (E.Noname) + continue; + write16le(P, E.Ordinal); + P += 2; + } + } + +private: + size_t Size; +}; + +} // anonymous namespace + +uint64_t IdataContents::getDirSize() { + return Dirs.size() * sizeof(ImportDirectoryTableEntry); +} + +uint64_t IdataContents::getIATSize() { + return Addresses.size() * ptrSize(); +} + +// Returns a list of .idata contents. +// See Microsoft PE/COFF spec 5.4 for details. +std::vector IdataContents::getChunks() { + create(); + + // The loader assumes a specific order of data. + // Add each type in the correct order. + std::vector V; + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Lookups.begin(), Lookups.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); + V.insert(V.end(), Hints.begin(), Hints.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); + return V; +} + +void IdataContents::create() { + std::vector> V = binImports(Imports); + + // Create .idata contents for each DLL. + for (std::vector &Syms : V) { + // Create lookup and address tables. If they have external names, + // we need to create HintName chunks to store the names. + // If they don't (if they are import-by-ordinals), we store only + // ordinal values to the table. + size_t Base = Lookups.size(); + for (DefinedImportData *S : Syms) { + uint16_t Ord = S->getOrdinal(); + if (S->getExternalName().empty()) { + Lookups.push_back(make(Ord)); + Addresses.push_back(make(Ord)); + continue; + } + auto *C = make(S->getExternalName(), Ord); + Lookups.push_back(make(C)); + Addresses.push_back(make(C)); + Hints.push_back(C); + } + // Terminate with null values. + Lookups.push_back(make(ptrSize())); + Addresses.push_back(make(ptrSize())); + + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I]); + + // Create the import table header. + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); + Dir->LookupTab = Lookups[Base]; + Dir->AddressTab = Addresses[Base]; + Dirs.push_back(Dir); + } + // Add null terminator. + Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); +} + +std::vector DelayLoadContents::getChunks() { + std::vector V; + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Names.begin(), Names.end()); + V.insert(V.end(), HintNames.begin(), HintNames.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); + return V; +} + +std::vector DelayLoadContents::getDataChunks() { + std::vector V; + V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); + return V; +} + +uint64_t DelayLoadContents::getDirSize() { + return Dirs.size() * sizeof(delay_import_directory_table_entry); +} + +void DelayLoadContents::create(Defined *H) { + Helper = H; + std::vector> V = binImports(Imports); + + // Create .didat contents for each DLL. + for (std::vector &Syms : V) { + // Create the delay import table header. + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); + + size_t Base = Addresses.size(); + for (DefinedImportData *S : Syms) { + Chunk *T = newThunkChunk(S, Dir); + auto *A = make(T); + Addresses.push_back(A); + Thunks.push_back(T); + StringRef ExtName = S->getExternalName(); + if (ExtName.empty()) { + Names.push_back(make(S->getOrdinal())); + } else { + auto *C = make(ExtName, 0); + Names.push_back(make(C)); + HintNames.push_back(C); + } + } + // Terminate with null values. + Addresses.push_back(make(8)); + Names.push_back(make(8)); + + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I]); + auto *MH = make(8); + MH->setAlign(8); + ModuleHandles.push_back(MH); + + // Fill the delay import table header fields. + Dir->ModuleHandle = MH; + Dir->AddressTab = Addresses[Base]; + Dir->NameTab = Names[Base]; + Dirs.push_back(Dir); + } + // Add null terminator. + Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); +} + +Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { + switch (Config->Machine) { + case AMD64: + return make(S, Dir, Helper); + case I386: + return make(S, Dir, Helper); + default: + llvm_unreachable("unsupported machine type"); + } +} + +EdataContents::EdataContents() { + uint16_t MaxOrdinal = 0; + for (Export &E : Config->Exports) + MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); + + auto *DLLName = make(sys::path::filename(Config->OutputFile)); + auto *AddressTab = make(MaxOrdinal); + std::vector Names; + for (Export &E : Config->Exports) + if (!E.Noname) + Names.push_back(make(E.ExportName)); + + std::vector Forwards; + for (Export &E : Config->Exports) { + if (E.ForwardTo.empty()) + continue; + E.ForwardChunk = make(E.ForwardTo); + Forwards.push_back(E.ForwardChunk); + } + + auto *NameTab = make(Names); + auto *OrdinalTab = make(Names.size()); + auto *Dir = make(MaxOrdinal, Names.size(), DLLName, + AddressTab, NameTab, OrdinalTab); + Chunks.push_back(Dir); + Chunks.push_back(DLLName); + Chunks.push_back(AddressTab); + Chunks.push_back(NameTab); + Chunks.push_back(OrdinalTab); + Chunks.insert(Chunks.end(), Names.begin(), Names.end()); + Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/DLL.h b/COFF/DLL.h new file mode 100644 index 000000000..ad312789e --- /dev/null +++ b/COFF/DLL.h @@ -0,0 +1,84 @@ +//===- DLL.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DLL_H +#define LLD_COFF_DLL_H + +#include "Chunks.h" +#include "Symbols.h" + +namespace lld { +namespace coff { + +// Windows-specific. +// IdataContents creates all chunks for the DLL import table. +// You are supposed to call add() to add symbols and then +// call getChunks() to get a list of chunks. +class IdataContents { +public: + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } + std::vector getChunks(); + + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } + uint64_t getDirSize(); + uint64_t getIATRVA() { return Addresses[0]->getRVA(); } + uint64_t getIATSize(); + +private: + void create(); + + std::vector Imports; + std::vector Dirs; + std::vector Lookups; + std::vector Addresses; + std::vector Hints; + std::vector DLLNames; +}; + +// Windows-specific. +// DelayLoadContents creates all chunks for the delay-load DLL import table. +class DelayLoadContents { +public: + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } + void create(Defined *Helper); + std::vector getChunks(); + std::vector getDataChunks(); + ArrayRef getCodeChunks() { return Thunks; } + + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } + uint64_t getDirSize(); + +private: + Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); + + Defined *Helper; + std::vector Imports; + std::vector Dirs; + std::vector ModuleHandles; + std::vector Addresses; + std::vector Names; + std::vector HintNames; + std::vector Thunks; + std::vector DLLNames; +}; + +// Windows-specific. +// EdataContents creates all chunks for the DLL export table. +class EdataContents { +public: + EdataContents(); + std::vector Chunks; +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp new file mode 100644 index 000000000..854c3e690 --- /dev/null +++ b/COFF/Driver.cpp @@ -0,0 +1,1181 @@ +//===- Driver.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Driver.h" +#include "Config.h" +#include "Error.h" +#include "InputFiles.h" +#include "Memory.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "Writer.h" +#include "lld/Driver/Driver.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFFModuleDefinition.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/TarWriter.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" +#include +#include + +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::COFF; +using llvm::sys::Process; + +namespace lld { +namespace coff { + +Configuration *Config; +LinkerDriver *Driver; + +BumpPtrAllocator BAlloc; +StringSaver Saver{BAlloc}; +std::vector SpecificAllocBase::Instances; + +bool link(ArrayRef Args, raw_ostream &Diag) { + ErrorCount = 0; + ErrorOS = &Diag; + Config = make(); + Config->Argv = {Args.begin(), Args.end()}; + Config->ColorDiagnostics = + (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); + Driver = make(); + Driver->link(Args); + return !ErrorCount; +} + +// Drop directory components and replace extension with ".exe" or ".dll". +static std::string getOutputPath(StringRef Path) { + auto P = Path.find_last_of("\\/"); + StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); + const char* E = Config->DLL ? ".dll" : ".exe"; + return (S.substr(0, S.rfind('.')) + E).str(); +} + +// ErrorOr is not default constructible, so it cannot be used as the type +// parameter of a future. +// FIXME: We could open the file in createFutureForFile and avoid needing to +// return an error here, but for the moment that would cost us a file descriptor +// (a limited resource on Windows) for the duration that the future is pending. +typedef std::pair, std::error_code> MBErrPair; + +// Create a std::future that opens and maps a file using the best strategy for +// the host platform. +static std::future createFutureForFile(std::string Path) { +#if LLVM_ON_WIN32 + // On Windows, file I/O is relatively slow so it is best to do this + // asynchronously. + auto Strategy = std::launch::async; +#else + auto Strategy = std::launch::deferred; +#endif + return std::async(Strategy, [=]() { + auto MBOrErr = MemoryBuffer::getFile(Path); + if (!MBOrErr) + return MBErrPair{nullptr, MBOrErr.getError()}; + return MBErrPair{std::move(*MBOrErr), std::error_code()}; + }); +} + +MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { + MemoryBufferRef MBRef = *MB; + make>(std::move(MB)); // take ownership + + if (Driver->Tar) + Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), + MBRef.getBuffer()); + return MBRef; +} + +void LinkerDriver::addBuffer(std::unique_ptr MB) { + MemoryBufferRef MBRef = takeBuffer(std::move(MB)); + + // File type is detected by contents, not by file extension. + file_magic Magic = identify_magic(MBRef.getBuffer()); + if (Magic == file_magic::windows_resource) { + Resources.push_back(MBRef); + return; + } + + FilePaths.push_back(MBRef.getBufferIdentifier()); + if (Magic == file_magic::archive) + return Symtab.addFile(make(MBRef)); + if (Magic == file_magic::bitcode) + return Symtab.addFile(make(MBRef)); + + if (Magic == file_magic::coff_cl_gl_object) + error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " + "Recompile without /GL"); + else + Symtab.addFile(make(MBRef)); +} + +void LinkerDriver::enqueuePath(StringRef Path) { + auto Future = + std::make_shared>(createFutureForFile(Path)); + std::string PathStr = Path; + enqueueTask([=]() { + auto MBOrErr = Future->get(); + if (MBOrErr.second) + error("could not open " + PathStr + ": " + MBOrErr.second.message()); + else + Driver->addBuffer(std::move(MBOrErr.first)); + }); +} + +void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, + StringRef ParentName) { + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::coff_import_library) { + Symtab.addFile(make(MB)); + return; + } + + InputFile *Obj; + if (Magic == file_magic::coff_object) { + Obj = make(MB); + } else if (Magic == file_magic::bitcode) { + Obj = make(MB); + } else { + error("unknown file type: " + MB.getBufferIdentifier()); + return; + } + + Obj->ParentName = ParentName; + Symtab.addFile(Obj); + log("Loaded " + toString(Obj) + " for " + SymName); +} + +void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, + StringRef SymName, + StringRef ParentName) { + if (!C.getParent()->isThin()) { + MemoryBufferRef MB = check( + C.getMemoryBufferRef(), + "could not get the buffer for the member defining symbol " + SymName); + enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); }); + return; + } + + auto Future = std::make_shared>(createFutureForFile( + check(C.getFullName(), + "could not get the filename for the member defining symbol " + + SymName))); + enqueueTask([=]() { + auto MBOrErr = Future->get(); + if (MBOrErr.second) + fatal(MBOrErr.second, + "could not get the buffer for the member defining " + SymName); + Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, + ParentName); + }); +} + +static bool isDecorated(StringRef Sym) { + return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); +} + +// Parses .drectve section contents and returns a list of files +// specified by /defaultlib. +void LinkerDriver::parseDirectives(StringRef S) { + opt::InputArgList Args = Parser.parse(S); + + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_alternatename: + parseAlternateName(Arg->getValue()); + break; + case OPT_defaultlib: + if (Optional Path = findLib(Arg->getValue())) + enqueuePath(*Path); + break; + case OPT_export: { + Export E = parseExport(Arg->getValue()); + E.Directives = true; + Config->Exports.push_back(E); + break; + } + case OPT_failifmismatch: + checkFailIfMismatch(Arg->getValue()); + break; + case OPT_incl: + addUndefined(Arg->getValue()); + break; + case OPT_merge: + parseMerge(Arg->getValue()); + break; + case OPT_nodefaultlib: + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); + break; + case OPT_section: + parseSection(Arg->getValue()); + break; + case OPT_editandcontinue: + case OPT_fastfail: + case OPT_guardsym: + case OPT_throwingnew: + break; + default: + error(Arg->getSpelling() + " is not allowed in .drectve"); + } + } +} + +// Find file from search paths. You can omit ".obj", this function takes +// care of that. Note that the returned path is not guaranteed to exist. +StringRef LinkerDriver::doFindFile(StringRef Filename) { + bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); + if (HasPathSep) + return Filename; + bool HasExt = (Filename.find('.') != StringRef::npos); + for (StringRef Dir : SearchPaths) { + SmallString<128> Path = Dir; + sys::path::append(Path, Filename); + if (sys::fs::exists(Path.str())) + return Saver.save(Path.str()); + if (!HasExt) { + Path.append(".obj"); + if (sys::fs::exists(Path.str())) + return Saver.save(Path.str()); + } + } + return Filename; +} + +// Resolves a file path. This never returns the same path +// (in that case, it returns None). +Optional LinkerDriver::findFile(StringRef Filename) { + StringRef Path = doFindFile(Filename); + bool Seen = !VisitedFiles.insert(Path.lower()).second; + if (Seen) + return None; + return Path; +} + +// Find library file from search path. +StringRef LinkerDriver::doFindLib(StringRef Filename) { + // Add ".lib" to Filename if that has no file extension. + bool HasExt = (Filename.find('.') != StringRef::npos); + if (!HasExt) + Filename = Saver.save(Filename + ".lib"); + return doFindFile(Filename); +} + +// Resolves a library path. /nodefaultlib options are taken into +// consideration. This never returns the same path (in that case, +// it returns None). +Optional LinkerDriver::findLib(StringRef Filename) { + if (Config->NoDefaultLibAll) + return None; + if (!VisitedLibs.insert(Filename.lower()).second) + return None; + StringRef Path = doFindLib(Filename); + if (Config->NoDefaultLibs.count(Path)) + return None; + if (!VisitedFiles.insert(Path.lower()).second) + return None; + return Path; +} + +// Parses LIB environment which contains a list of search paths. +void LinkerDriver::addLibSearchPaths() { + Optional EnvOpt = Process::GetEnv("LIB"); + if (!EnvOpt.hasValue()) + return; + StringRef Env = Saver.save(*EnvOpt); + while (!Env.empty()) { + StringRef Path; + std::tie(Path, Env) = Env.split(';'); + SearchPaths.push_back(Path); + } +} + +SymbolBody *LinkerDriver::addUndefined(StringRef Name) { + SymbolBody *B = Symtab.addUndefined(Name); + Config->GCRoot.insert(B); + return B; +} + +// Symbol names are mangled by appending "_" prefix on x86. +StringRef LinkerDriver::mangle(StringRef Sym) { + assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); + if (Config->Machine == I386) + return Saver.save("_" + Sym); + return Sym; +} + +// Windows specific -- find default entry point name. +StringRef LinkerDriver::findDefaultEntry() { + // User-defined main functions and their corresponding entry points. + static const char *Entries[][2] = { + {"main", "mainCRTStartup"}, + {"wmain", "wmainCRTStartup"}, + {"WinMain", "WinMainCRTStartup"}, + {"wWinMain", "wWinMainCRTStartup"}, + }; + for (auto E : Entries) { + StringRef Entry = Symtab.findMangle(mangle(E[0])); + if (!Entry.empty() && !isa(Symtab.find(Entry)->body())) + return mangle(E[1]); + } + return ""; +} + +WindowsSubsystem LinkerDriver::inferSubsystem() { + if (Config->DLL) + return IMAGE_SUBSYSTEM_WINDOWS_GUI; + if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain")) + return IMAGE_SUBSYSTEM_WINDOWS_CUI; + if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain")) + return IMAGE_SUBSYSTEM_WINDOWS_GUI; + return IMAGE_SUBSYSTEM_UNKNOWN; +} + +static uint64_t getDefaultImageBase() { + if (Config->is64()) + return Config->DLL ? 0x180000000 : 0x140000000; + return Config->DLL ? 0x10000000 : 0x400000; +} + +static std::string createResponseFile(const opt::InputArgList &Args, + ArrayRef FilePaths, + ArrayRef SearchPaths) { + SmallString<0> Data; + raw_svector_ostream OS(Data); + + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_linkrepro: + case OPT_INPUT: + case OPT_defaultlib: + case OPT_libpath: + break; + default: + OS << toString(Arg) << "\n"; + } + } + + for (StringRef Path : SearchPaths) { + std::string RelPath = relativeToRoot(Path); + OS << "/libpath:" << quote(RelPath) << "\n"; + } + + for (StringRef Path : FilePaths) + OS << quote(relativeToRoot(Path)) << "\n"; + + return Data.str(); +} + +static unsigned getDefaultDebugType(const opt::InputArgList &Args) { + unsigned DebugTypes = static_cast(DebugType::CV); + if (Args.hasArg(OPT_driver)) + DebugTypes |= static_cast(DebugType::PData); + if (Args.hasArg(OPT_profile)) + DebugTypes |= static_cast(DebugType::Fixup); + return DebugTypes; +} + +static unsigned parseDebugType(StringRef Arg) { + SmallVector Types; + Arg.split(Types, ',', /*KeepEmpty=*/false); + + unsigned DebugTypes = static_cast(DebugType::None); + for (StringRef Type : Types) + DebugTypes |= StringSwitch(Type.lower()) + .Case("cv", static_cast(DebugType::CV)) + .Case("pdata", static_cast(DebugType::PData)) + .Case("fixup", static_cast(DebugType::Fixup)) + .Default(0); + return DebugTypes; +} + +static std::string getMapFile(const opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); + if (!Arg) + return ""; + if (Arg->getOption().getID() == OPT_lldmap_file) + return Arg->getValue(); + + assert(Arg->getOption().getID() == OPT_lldmap); + StringRef OutFile = Config->OutputFile; + return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); +} + +static std::string getImplibPath() { + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); +} + +// +// The import name is caculated as the following: +// +// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY +// -----+----------------+---------------------+------------------ +// LINK | {value} | {value}.{.dll/.exe} | {output name} +// LIB | {value} | {value}.dll | {output name}.dll +// +static std::string getImportName(bool AsLib) { + SmallString<128> Out; + + if (Config->ImportName.empty()) { + Out.assign(sys::path::filename(Config->OutputFile)); + if (AsLib) + sys::path::replace_extension(Out, ".dll"); + } else { + Out.assign(Config->ImportName); + if (!sys::path::has_extension(Out)) + sys::path::replace_extension(Out, + (Config->DLL || AsLib) ? ".dll" : ".exe"); + } + + return Out.str(); +} + +static void createImportLibrary(bool AsLib) { + std::vector Exports; + for (Export &E1 : Config->Exports) { + COFFShortExport E2; + E2.Name = E1.Name; + E2.SymbolName = E1.SymbolName; + E2.ExtName = E1.ExtName; + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Exports.push_back(E2); + } + + writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports, + Config->Machine, false); +} + +static void parseModuleDefs(StringRef Path) { + std::unique_ptr MB = check( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + COFFModuleDefinition M = + check(parseCOFFModuleDefinition(MB->getMemBufferRef(), Config->Machine)); + + if (Config->OutputFile.empty()) + Config->OutputFile = Saver.save(M.OutputFile); + Config->ImportName = Saver.save(M.ImportName); + if (M.ImageBase) + Config->ImageBase = M.ImageBase; + if (M.StackReserve) + Config->StackReserve = M.StackReserve; + if (M.StackCommit) + Config->StackCommit = M.StackCommit; + if (M.HeapReserve) + Config->HeapReserve = M.HeapReserve; + if (M.HeapCommit) + Config->HeapCommit = M.HeapCommit; + if (M.MajorImageVersion) + Config->MajorImageVersion = M.MajorImageVersion; + if (M.MinorImageVersion) + Config->MinorImageVersion = M.MinorImageVersion; + if (M.MajorOSVersion) + Config->MajorOSVersion = M.MajorOSVersion; + if (M.MinorOSVersion) + Config->MinorOSVersion = M.MinorOSVersion; + + for (COFFShortExport E1 : M.Exports) { + Export E2; + E2.Name = Saver.save(E1.Name); + if (E1.isWeak()) + E2.ExtName = Saver.save(E1.ExtName); + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Config->Exports.push_back(E2); + } +} + +std::vector getArchiveMembers(Archive *File) { + std::vector V; + Error Err = Error::success(); + for (const ErrorOr &COrErr : File->children(Err)) { + Archive::Child C = + check(COrErr, + File->getFileName() + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + check(C.getMemoryBufferRef(), + File->getFileName() + + ": could not get the buffer for a child of the archive"); + V.push_back(MBRef); + } + if (Err) + fatal(File->getFileName() + + ": Archive::children failed: " + toString(std::move(Err))); + return V; +} + +// A helper function for filterBitcodeFiles. +static bool needsRebuilding(MemoryBufferRef MB) { + // The MSVC linker doesn't support thin archives, so if it's a thin + // archive, we always need to rebuild it. + std::unique_ptr File = + check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); + if (File->isThin()) + return true; + + // Returns true if the archive contains at least one bitcode file. + for (MemoryBufferRef Member : getArchiveMembers(File.get())) + if (identify_magic(Member.getBuffer()) == file_magic::bitcode) + return true; + return false; +} + +// Opens a given path as an archive file and removes bitcode files +// from them if exists. This function is to appease the MSVC linker as +// their linker doesn't like archive files containing non-native +// object files. +// +// If a given archive doesn't contain bitcode files, the archive path +// is returned as-is. Otherwise, a new temporary file is created and +// its path is returned. +static Optional +filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { + std::unique_ptr MB = check( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + MemoryBufferRef MBRef = MB->getMemBufferRef(); + file_magic Magic = identify_magic(MBRef.getBuffer()); + + if (Magic == file_magic::bitcode) + return None; + if (Magic != file_magic::archive) + return Path.str(); + if (!needsRebuilding(MBRef)) + return Path.str(); + + std::unique_ptr File = + check(Archive::create(MBRef), + MBRef.getBufferIdentifier() + ": failed to parse archive"); + + std::vector New; + for (MemoryBufferRef Member : getArchiveMembers(File.get())) + if (identify_magic(Member.getBuffer()) != file_magic::bitcode) + New.emplace_back(Member); + + if (New.empty()) + return None; + + log("Creating a temporary archive for " + Path + " to remove bitcode files"); + + SmallString<128> S; + if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), + ".lib", S)) + fatal(EC, "cannot create a temporary file"); + std::string Temp = S.str(); + TemporaryFiles.push_back(Temp); + + std::pair Ret = + llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, + /*Deterministics=*/true, + /*Thin=*/false); + if (Ret.second) + error("failed to create a new archive " + S.str() + ": " + Ret.first); + return Temp; +} + +// Create response file contents and invoke the MSVC linker. +void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { + std::string Rsp = "/nologo\n"; + std::vector Temps; + + // Write out archive members that we used in symbol resolution and pass these + // to MSVC before any archives, so that MSVC uses the same objects to satisfy + // references. + for (const auto *O : Symtab.ObjectFiles) { + if (O->ParentName.empty()) + continue; + SmallString<128> S; + int Fd; + if (auto EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) + fatal(EC, "cannot create a temporary file"); + raw_fd_ostream OS(Fd, /*shouldClose*/ true); + OS << O->MB.getBuffer(); + Temps.push_back(S.str()); + Rsp += quote(S) + "\n"; + } + + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_linkrepro: + case OPT_lldmap: + case OPT_lldmap_file: + case OPT_lldsavetemps: + case OPT_msvclto: + // LLD-specific options are stripped. + break; + case OPT_opt: + if (!StringRef(Arg->getValue()).startswith("lld")) + Rsp += toString(Arg) + " "; + break; + case OPT_INPUT: { + if (Optional Path = doFindFile(Arg->getValue())) { + if (Optional S = filterBitcodeFiles(*Path, Temps)) + Rsp += quote(*S) + "\n"; + continue; + } + Rsp += quote(Arg->getValue()) + "\n"; + break; + } + default: + Rsp += toString(Arg) + "\n"; + } + } + + std::vector ObjectFiles = Symtab.compileBitcodeFiles(); + runMSVCLinker(Rsp, ObjectFiles); + + for (StringRef Path : Temps) + sys::fs::remove(Path); +} + +void LinkerDriver::enqueueTask(std::function Task) { + TaskQueue.push_back(std::move(Task)); +} + +bool LinkerDriver::run() { + bool DidWork = !TaskQueue.empty(); + while (!TaskQueue.empty()) { + TaskQueue.front()(); + TaskQueue.pop_front(); + } + return DidWork; +} + +void LinkerDriver::link(ArrayRef ArgsArr) { + // If the first command line argument is "/lib", link.exe acts like lib.exe. + // We call our own implementation of lib.exe that understands bitcode files. + if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { + if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) + fatal("lib failed"); + return; + } + + // Needed for LTO. + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + InitializeAllDisassemblers(); + + // Parse command line options. + opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); + + // Parse and evaluate -mllvm options. + std::vector V; + V.push_back("lld-link (LLVM option parsing)"); + for (auto *Arg : Args.filtered(OPT_mllvm)) + V.push_back(Arg->getValue()); + cl::ParseCommandLineOptions(V.size(), V.data()); + + // Handle /errorlimit early, because error() depends on it. + if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { + int N = 20; + StringRef S = Arg->getValue(); + if (S.getAsInteger(10, N)) + error(Arg->getSpelling() + " number expected, but got " + S); + Config->ErrorLimit = N; + } + + // Handle /help + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); + return; + } + + if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { + SmallString<64> Path = StringRef(Arg->getValue()); + sys::path::append(Path, "repro.tar"); + + Expected> ErrOrWriter = + TarWriter::create(Path, "repro"); + + if (ErrOrWriter) { + Tar = std::move(*ErrOrWriter); + } else { + error("/linkrepro: failed to open " + Path + ": " + + toString(ErrOrWriter.takeError())); + } + } + + if (!Args.hasArgNoClaim(OPT_INPUT)) { + if (Args.hasArgNoClaim(OPT_deffile)) + Config->NoEntry = true; + else + fatal("no input files"); + } + + // Construct search path list. + SearchPaths.push_back(""); + for (auto *Arg : Args.filtered(OPT_libpath)) + SearchPaths.push_back(Arg->getValue()); + addLibSearchPaths(); + + // Handle /out + if (auto *Arg = Args.getLastArg(OPT_out)) + Config->OutputFile = Arg->getValue(); + + // Handle /verbose + if (Args.hasArg(OPT_verbose)) + Config->Verbose = true; + + // Handle /force or /force:unresolved + if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) + Config->Force = true; + + // Handle /debug + if (Args.hasArg(OPT_debug)) { + Config->Debug = true; + Config->DebugTypes = + Args.hasArg(OPT_debugtype) + ? parseDebugType(Args.getLastArg(OPT_debugtype)->getValue()) + : getDefaultDebugType(Args); + } + + // Create a dummy PDB file to satisfy build sytem rules. + if (auto *Arg = Args.getLastArg(OPT_pdb)) + Config->PDBPath = Arg->getValue(); + + // Handle /noentry + if (Args.hasArg(OPT_noentry)) { + if (Args.hasArg(OPT_dll)) + Config->NoEntry = true; + else + error("/noentry must be specified with /dll"); + } + + // Handle /dll + if (Args.hasArg(OPT_dll)) { + Config->DLL = true; + Config->ManifestID = 2; + } + + // Handle /fixed + if (Args.hasArg(OPT_fixed)) { + if (Args.hasArg(OPT_dynamicbase)) { + error("/fixed must not be specified with /dynamicbase"); + } else { + Config->Relocatable = false; + Config->DynamicBase = false; + } + } + + if (Args.hasArg(OPT_appcontainer)) + Config->AppContainer = true; + + // Handle /machine + if (auto *Arg = Args.getLastArg(OPT_machine)) + Config->Machine = getMachineType(Arg->getValue()); + + // Handle /nodefaultlib: + for (auto *Arg : Args.filtered(OPT_nodefaultlib)) + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); + + // Handle /nodefaultlib + if (Args.hasArg(OPT_nodefaultlib_all)) + Config->NoDefaultLibAll = true; + + // Handle /base + if (auto *Arg = Args.getLastArg(OPT_base)) + parseNumbers(Arg->getValue(), &Config->ImageBase); + + // Handle /stack + if (auto *Arg = Args.getLastArg(OPT_stack)) + parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); + + // Handle /heap + if (auto *Arg = Args.getLastArg(OPT_heap)) + parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); + + // Handle /version + if (auto *Arg = Args.getLastArg(OPT_version)) + parseVersion(Arg->getValue(), &Config->MajorImageVersion, + &Config->MinorImageVersion); + + // Handle /subsystem + if (auto *Arg = Args.getLastArg(OPT_subsystem)) + parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, + &Config->MinorOSVersion); + + // Handle /alternatename + for (auto *Arg : Args.filtered(OPT_alternatename)) + parseAlternateName(Arg->getValue()); + + // Handle /include + for (auto *Arg : Args.filtered(OPT_incl)) + addUndefined(Arg->getValue()); + + // Handle /implib + if (auto *Arg = Args.getLastArg(OPT_implib)) + Config->Implib = Arg->getValue(); + + // Handle /opt + for (auto *Arg : Args.filtered(OPT_opt)) { + std::string Str = StringRef(Arg->getValue()).lower(); + SmallVector Vec; + StringRef(Str).split(Vec, ','); + for (StringRef S : Vec) { + if (S == "noref") { + Config->DoGC = false; + Config->DoICF = false; + continue; + } + if (S == "icf" || StringRef(S).startswith("icf=")) { + Config->DoICF = true; + continue; + } + if (S == "noicf") { + Config->DoICF = false; + continue; + } + if (StringRef(S).startswith("lldlto=")) { + StringRef OptLevel = StringRef(S).substr(7); + if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || + Config->LTOOptLevel > 3) + error("/opt:lldlto: invalid optimization level: " + OptLevel); + continue; + } + if (StringRef(S).startswith("lldltojobs=")) { + StringRef Jobs = StringRef(S).substr(11); + if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) + error("/opt:lldltojobs: invalid job count: " + Jobs); + continue; + } + if (StringRef(S).startswith("lldltopartitions=")) { + StringRef N = StringRef(S).substr(17); + if (N.getAsInteger(10, Config->LTOPartitions) || + Config->LTOPartitions == 0) + error("/opt:lldltopartitions: invalid partition count: " + N); + continue; + } + if (S != "ref" && S != "lbr" && S != "nolbr") + error("/opt: unknown option: " + S); + } + } + + // Handle /lldsavetemps + if (Args.hasArg(OPT_lldsavetemps)) + Config->SaveTemps = true; + + // Handle /failifmismatch + for (auto *Arg : Args.filtered(OPT_failifmismatch)) + checkFailIfMismatch(Arg->getValue()); + + // Handle /merge + for (auto *Arg : Args.filtered(OPT_merge)) + parseMerge(Arg->getValue()); + + // Handle /section + for (auto *Arg : Args.filtered(OPT_section)) + parseSection(Arg->getValue()); + + // Handle /manifestdependency. This enables /manifest unless /manifest:no is + // also passed. + if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { + Config->ManifestDependency = Arg->getValue(); + Config->Manifest = Configuration::SideBySide; + } + + // Handle /manifest and /manifest: + if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { + if (Arg->getOption().getID() == OPT_manifest) + Config->Manifest = Configuration::SideBySide; + else + parseManifest(Arg->getValue()); + } + + // Handle /manifestuac + if (auto *Arg = Args.getLastArg(OPT_manifestuac)) + parseManifestUAC(Arg->getValue()); + + // Handle /manifestfile + if (auto *Arg = Args.getLastArg(OPT_manifestfile)) + Config->ManifestFile = Arg->getValue(); + + // Handle /manifestinput + for (auto *Arg : Args.filtered(OPT_manifestinput)) + Config->ManifestInput.push_back(Arg->getValue()); + + if (!Config->ManifestInput.empty() && + Config->Manifest != Configuration::Embed) { + fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED"); + } + + // Handle miscellaneous boolean flags. + if (Args.hasArg(OPT_allowisolation_no)) + Config->AllowIsolation = false; + if (Args.hasArg(OPT_dynamicbase_no)) + Config->DynamicBase = false; + if (Args.hasArg(OPT_nxcompat_no)) + Config->NxCompat = false; + if (Args.hasArg(OPT_tsaware_no)) + Config->TerminalServerAware = false; + if (Args.hasArg(OPT_nosymtab)) + Config->WriteSymtab = false; + + Config->MapFile = getMapFile(Args); + + if (ErrorCount) + return; + + // Create a list of input files. Files can be given as arguments + // for /defaultlib option. + std::vector MBs; + for (auto *Arg : Args.filtered(OPT_INPUT)) + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path); + for (auto *Arg : Args.filtered(OPT_defaultlib)) + if (Optional Path = findLib(Arg->getValue())) + enqueuePath(*Path); + + // Windows specific -- Create a resource file containing a manifest file. + if (Config->Manifest == Configuration::Embed) + addBuffer(createManifestRes()); + + // Read all input files given via the command line. + run(); + + // We should have inferred a machine type by now from the input files, but if + // not we assume x64. + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + warn("/machine is not specified. x64 is assumed"); + Config->Machine = AMD64; + } + + // Input files can be Windows resource files (.res files). We use + // WindowsResource to convert resource files to a regular COFF file, + // then link the resulting file normally. + if (!Resources.empty()) + addBuffer(convertResToCOFF(Resources)); + + if (Tar) + Tar->append("response.txt", + createResponseFile(Args, FilePaths, + ArrayRef(SearchPaths).slice(1))); + + // Handle /largeaddressaware + if (Config->is64() || Args.hasArg(OPT_largeaddressaware)) + Config->LargeAddressAware = true; + + // Handle /highentropyva + if (Config->is64() && !Args.hasArg(OPT_highentropyva_no)) + Config->HighEntropyVA = true; + + // Handle /entry and /dll + if (auto *Arg = Args.getLastArg(OPT_entry)) { + Config->Entry = addUndefined(mangle(Arg->getValue())); + } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) { + StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" + : "_DllMainCRTStartup"; + Config->Entry = addUndefined(S); + } else if (!Config->NoEntry) { + // Windows specific -- If entry point name is not given, we need to + // infer that from user-defined entry name. + StringRef S = findDefaultEntry(); + if (S.empty()) + fatal("entry point must be defined"); + Config->Entry = addUndefined(S); + log("Entry name inferred: " + S); + } + + // Handle /export + for (auto *Arg : Args.filtered(OPT_export)) { + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386) { + if (!isDecorated(E.Name)) + E.Name = Saver.save("_" + E.Name); + if (!E.ExtName.empty() && !isDecorated(E.ExtName)) + E.ExtName = Saver.save("_" + E.ExtName); + } + Config->Exports.push_back(E); + } + + // Handle /def + if (auto *Arg = Args.getLastArg(OPT_deffile)) { + // parseModuleDefs mutates Config object. + parseModuleDefs(Arg->getValue()); + } + + // Handle generation of import library from a def file. + if (!Args.hasArgNoClaim(OPT_INPUT)) { + fixupExports(); + createImportLibrary(/*AsLib=*/true); + exit(0); + } + + // Handle /delayload + for (auto *Arg : Args.filtered(OPT_delayload)) { + Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); + if (Config->Machine == I386) { + Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); + } else { + Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); + } + } + + // Set default image name if neither /out or /def set it. + if (Config->OutputFile.empty()) { + Config->OutputFile = + getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); + } + + // Put the PDB next to the image if no /pdb flag was passed. + if (Config->Debug && Config->PDBPath.empty()) { + Config->PDBPath = Config->OutputFile; + sys::path::replace_extension(Config->PDBPath, ".pdb"); + } + + // Disable PDB generation if the user requested it. + if (Args.hasArg(OPT_nopdb)) + Config->PDBPath = ""; + + // Set default image base if /base is not given. + if (Config->ImageBase == uint64_t(-1)) + Config->ImageBase = getDefaultImageBase(); + + Symtab.addSynthetic(mangle("__ImageBase"), nullptr); + if (Config->Machine == I386) { + Symtab.addAbsolute("___safe_se_handler_table", 0); + Symtab.addAbsolute("___safe_se_handler_count", 0); + } + + // We do not support /guard:cf (control flow protection) yet. + // Define CFG symbols anyway so that we can link MSVC 2015 CRT. + Symtab.addAbsolute(mangle("__guard_fids_count"), 0); + Symtab.addAbsolute(mangle("__guard_fids_table"), 0); + Symtab.addAbsolute(mangle("__guard_flags"), 0x100); + Symtab.addAbsolute(mangle("__guard_iat_count"), 0); + Symtab.addAbsolute(mangle("__guard_iat_table"), 0); + Symtab.addAbsolute(mangle("__guard_longjmp_count"), 0); + Symtab.addAbsolute(mangle("__guard_longjmp_table"), 0); + + // This code may add new undefined symbols to the link, which may enqueue more + // symbol resolution tasks, so we need to continue executing tasks until we + // converge. + do { + // Windows specific -- if entry point is not found, + // search for its mangled names. + if (Config->Entry) + Symtab.mangleMaybe(Config->Entry); + + // Windows specific -- Make sure we resolve all dllexported symbols. + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) + continue; + E.Sym = addUndefined(E.Name); + if (!E.Directives) + Symtab.mangleMaybe(E.Sym); + } + + // Add weak aliases. Weak aliases is a mechanism to give remaining + // undefined symbols final chance to be resolved successfully. + for (auto Pair : Config->AlternateNames) { + StringRef From = Pair.first; + StringRef To = Pair.second; + Symbol *Sym = Symtab.find(From); + if (!Sym) + continue; + if (auto *U = dyn_cast(Sym->body())) + if (!U->WeakAlias) + U->WeakAlias = Symtab.addUndefined(To); + } + + // Windows specific -- if __load_config_used can be resolved, resolve it. + if (Symtab.findUnderscore("_load_config_used")) + addUndefined(mangle("_load_config_used")); + } while (run()); + + if (ErrorCount) + return; + + // If /msvclto is given, we use the MSVC linker to link LTO output files. + // This is useful because MSVC link.exe can generate complete PDBs. + if (Args.hasArg(OPT_msvclto)) { + invokeMSVC(Args); + exit(0); + } + + // Do LTO by compiling bitcode input files to a set of native COFF files then + // link those files. + Symtab.addCombinedLTOObjects(); + run(); + + // Make sure we have resolved all symbols. + Symtab.reportRemainingUndefines(); + + // Windows specific -- if no /subsystem is given, we need to infer + // that from entry point name. + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { + Config->Subsystem = inferSubsystem(); + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) + fatal("subsystem must be defined"); + } + + // Handle /safeseh. + if (Args.hasArg(OPT_safeseh)) { + for (ObjectFile *File : Symtab.ObjectFiles) + if (!File->SEHCompat) + error("/safeseh: " + File->getName() + " is not compatible with SEH"); + if (ErrorCount) + return; + } + + // Windows specific -- when we are creating a .dll file, we also + // need to create a .lib file. + if (!Config->Exports.empty() || Config->DLL) { + fixupExports(); + createImportLibrary(/*AsLib=*/false); + assignExportOrdinals(); + } + + // Windows specific -- Create a side-by-side manifest file. + if (Config->Manifest == Configuration::SideBySide) + createSideBySideManifest(); + + // Identify unreferenced COMDAT sections. + if (Config->DoGC) + markLive(Symtab.getChunks()); + + // Identify identical COMDAT sections to merge them. + if (Config->DoICF) + doICF(Symtab.getChunks()); + + // Write the result. + writeResult(&Symtab); + + // Call exit to avoid calling destructors. + exit(0); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Driver.h b/COFF/Driver.h new file mode 100644 index 000000000..6879be2eb --- /dev/null +++ b/COFF/Driver.h @@ -0,0 +1,188 @@ +//===- Driver.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DRIVER_H +#define LLD_COFF_DRIVER_H + +#include "Config.h" +#include "SymbolTable.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Reproduce.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/TarWriter.h" +#include +#include +#include + +namespace lld { +namespace coff { + +class LinkerDriver; +extern LinkerDriver *Driver; + +using llvm::COFF::MachineTypes; +using llvm::COFF::WindowsSubsystem; +using llvm::Optional; + +// Implemented in MarkLive.cpp. +void markLive(const std::vector &Chunks); + +// Implemented in ICF.cpp. +void doICF(const std::vector &Chunks); + +class ArgParser { +public: + // Parses command line options. + llvm::opt::InputArgList parse(llvm::ArrayRef Args); + + // Concatenate LINK environment varirable and given arguments and parse them. + llvm::opt::InputArgList parseLINK(std::vector Args); + + // Tokenizes a given string and then parses as command line options. + llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } + +private: + std::vector tokenize(StringRef S); + + std::vector replaceResponseFiles(std::vector); +}; + +class LinkerDriver { +public: + LinkerDriver() { coff::Symtab = &Symtab; } + void link(llvm::ArrayRef Args); + + // Used by the resolver to parse .drectve section contents. + void parseDirectives(StringRef S); + + // Used by ArchiveFile to enqueue members. + void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, + StringRef ParentName); + +private: + ArgParser Parser; + SymbolTable Symtab; + + std::unique_ptr Tar; // for /linkrepro + + // Opens a file. Path has to be resolved already. + MemoryBufferRef openFile(StringRef Path); + + // Searches a file from search paths. + Optional findFile(StringRef Filename); + Optional findLib(StringRef Filename); + StringRef doFindFile(StringRef Filename); + StringRef doFindLib(StringRef Filename); + + // Parses LIB environment which contains a list of search paths. + void addLibSearchPaths(); + + // Library search path. The first element is always "" (current directory). + std::vector SearchPaths; + std::set VisitedFiles; + std::set VisitedLibs; + + SymbolBody *addUndefined(StringRef Sym); + StringRef mangle(StringRef Sym); + + // Windows specific -- "main" is not the only main function in Windows. + // You can choose one from these four -- {w,}{WinMain,main}. + // There are four different entry point functions for them, + // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to + // choose the right one depending on which "main" function is defined. + // This function looks up the symbol table and resolve corresponding + // entry point name. + StringRef findDefaultEntry(); + WindowsSubsystem inferSubsystem(); + + void invokeMSVC(llvm::opt::InputArgList &Args); + + MemoryBufferRef takeBuffer(std::unique_ptr MB); + void addBuffer(std::unique_ptr MB); + void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, + StringRef ParentName); + + void enqueuePath(StringRef Path); + + void enqueueTask(std::function Task); + bool run(); + + std::list> TaskQueue; + std::vector FilePaths; + std::vector Resources; +}; + +// Functions below this line are defined in DriverUtils.cpp. + +void printHelp(const char *Argv0); + +// For /machine option. +MachineTypes getMachineType(StringRef Arg); +StringRef machineToStr(MachineTypes MT); + +// Parses a string in the form of "[,]". +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); + +// Parses a string in the form of "[.]". +// Minor's default value is 0. +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); + +// Parses a string in the form of "[,[.]]". +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor); + +void parseAlternateName(StringRef); +void parseMerge(StringRef); +void parseSection(StringRef); + +// Parses a string in the form of "EMBED[,=]|NO". +void parseManifest(StringRef Arg); + +// Parses a string in the form of "level=|uiAccess=" +void parseManifestUAC(StringRef Arg); + +// Create a resource file containing a manifest XML. +std::unique_ptr createManifestRes(); +void createSideBySideManifest(); + +// Used for dllexported symbols. +Export parseExport(StringRef Arg); +void fixupExports(); +void assignExportOrdinals(); + +// Parses a string in the form of "key=value" and check +// if value matches previous values for the key. +// This feature used in the directive section to reject +// incompatible objects. +void checkFailIfMismatch(StringRef Arg); + +// Convert Windows resource files (.res files) to a .obj file +// using cvtres.exe. +std::unique_ptr +convertResToCOFF(const std::vector &MBs); + +void runMSVCLinker(std::string Rsp, ArrayRef Objects); + +// Create enum with OPT_xxx values for each option in Options.td +enum { + OPT_INVALID = 0, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp new file mode 100644 index 000000000..39d582469 --- /dev/null +++ b/COFF/DriverUtils.cpp @@ -0,0 +1,730 @@ +//===- DriverUtils.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains utility functions for the driver. Because there +// are so many small functions, we created this separate file to make +// Driver.cpp less cluttered. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "Memory.h" +#include "Symbols.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/WindowsResource.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm::COFF; +using namespace llvm; +using llvm::cl::ExpandResponseFiles; +using llvm::cl::TokenizeWindowsCommandLine; +using llvm::sys::Process; + +namespace lld { +namespace coff { +namespace { + +const uint16_t SUBLANG_ENGLISH_US = 0x0409; +const uint16_t RT_MANIFEST = 24; + +class Executor { +public: + explicit Executor(StringRef S) : Prog(Saver.save(S)) {} + void add(StringRef S) { Args.push_back(Saver.save(S)); } + void add(std::string &S) { Args.push_back(Saver.save(S)); } + void add(Twine S) { Args.push_back(Saver.save(S)); } + void add(const char *S) { Args.push_back(Saver.save(S)); } + + void run() { + ErrorOr ExeOrErr = sys::findProgramByName(Prog); + if (auto EC = ExeOrErr.getError()) + fatal(EC, "unable to find " + Prog + " in PATH: "); + StringRef Exe = Saver.save(*ExeOrErr); + Args.insert(Args.begin(), Exe); + + std::vector Vec; + for (StringRef S : Args) + Vec.push_back(S.data()); + Vec.push_back(nullptr); + + if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0) + fatal("ExecuteAndWait failed: " + + llvm::join(Args.begin(), Args.end(), " ")); + } + +private: + StringRef Prog; + std::vector Args; +}; + +} // anonymous namespace + +// Returns /machine's value. +MachineTypes getMachineType(StringRef S) { + MachineTypes MT = StringSwitch(S.lower()) + .Cases("x64", "amd64", AMD64) + .Cases("x86", "i386", I386) + .Case("arm", ARMNT) + .Case("arm64", ARM64) + .Default(IMAGE_FILE_MACHINE_UNKNOWN); + if (MT != IMAGE_FILE_MACHINE_UNKNOWN) + return MT; + fatal("unknown /machine argument: " + S); +} + +StringRef machineToStr(MachineTypes MT) { + switch (MT) { + case ARMNT: + return "arm"; + case ARM64: + return "arm64"; + case AMD64: + return "x64"; + case I386: + return "x86"; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Parses a string in the form of "[,]". +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split(','); + if (S1.getAsInteger(0, *Addr)) + fatal("invalid number: " + S1); + if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) + fatal("invalid number: " + S2); +} + +// Parses a string in the form of "[.]". +// If second number is not present, Minor is set to 0. +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split('.'); + if (S1.getAsInteger(0, *Major)) + fatal("invalid number: " + S1); + *Minor = 0; + if (!S2.empty() && S2.getAsInteger(0, *Minor)) + fatal("invalid number: " + S2); +} + +// Parses a string in the form of "[,[.]]". +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor) { + StringRef SysStr, Ver; + std::tie(SysStr, Ver) = Arg.split(','); + *Sys = StringSwitch(SysStr.lower()) + .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) + .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) + .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) + .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) + .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) + .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) + .Case("native", IMAGE_SUBSYSTEM_NATIVE) + .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) + .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) + .Default(IMAGE_SUBSYSTEM_UNKNOWN); + if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) + fatal("unknown subsystem: " + SysStr); + if (!Ver.empty()) + parseVersion(Ver, Major, Minor); +} + +// Parse a string of the form of "=". +// Results are directly written to Config. +void parseAlternateName(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + fatal("/alternatename: invalid argument: " + S); + auto It = Config->AlternateNames.find(From); + if (It != Config->AlternateNames.end() && It->second != To) + fatal("/alternatename: conflicts: " + S); + Config->AlternateNames.insert(It, std::make_pair(From, To)); +} + +// Parse a string of the form of "=". +// Results are directly written to Config. +void parseMerge(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + fatal("/merge: invalid argument: " + S); + auto Pair = Config->Merge.insert(std::make_pair(From, To)); + bool Inserted = Pair.second; + if (!Inserted) { + StringRef Existing = Pair.first->second; + if (Existing != To) + warn(S + ": already merged into " + Existing); + } +} + +static uint32_t parseSectionAttributes(StringRef S) { + uint32_t Ret = 0; + for (char C : S.lower()) { + switch (C) { + case 'd': + Ret |= IMAGE_SCN_MEM_DISCARDABLE; + break; + case 'e': + Ret |= IMAGE_SCN_MEM_EXECUTE; + break; + case 'k': + Ret |= IMAGE_SCN_MEM_NOT_CACHED; + break; + case 'p': + Ret |= IMAGE_SCN_MEM_NOT_PAGED; + break; + case 'r': + Ret |= IMAGE_SCN_MEM_READ; + break; + case 's': + Ret |= IMAGE_SCN_MEM_SHARED; + break; + case 'w': + Ret |= IMAGE_SCN_MEM_WRITE; + break; + default: + fatal("/section: invalid argument: " + S); + } + } + return Ret; +} + +// Parses /section option argument. +void parseSection(StringRef S) { + StringRef Name, Attrs; + std::tie(Name, Attrs) = S.split(','); + if (Name.empty() || Attrs.empty()) + fatal("/section: invalid argument: " + S); + Config->Section[Name] = parseSectionAttributes(Attrs); +} + +// Parses a string in the form of "EMBED[,=]|NO". +// Results are directly written to Config. +void parseManifest(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->Manifest = Configuration::No; + return; + } + if (!Arg.startswith_lower("embed")) + fatal("invalid option " + Arg); + Config->Manifest = Configuration::Embed; + Arg = Arg.substr(strlen("embed")); + if (Arg.empty()) + return; + if (!Arg.startswith_lower(",id=")) + fatal("invalid option " + Arg); + Arg = Arg.substr(strlen(",id=")); + if (Arg.getAsInteger(0, Config->ManifestID)) + fatal("invalid option " + Arg); +} + +// Parses a string in the form of "level=|uiAccess=|NO". +// Results are directly written to Config. +void parseManifestUAC(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->ManifestUAC = false; + return; + } + for (;;) { + Arg = Arg.ltrim(); + if (Arg.empty()) + return; + if (Arg.startswith_lower("level=")) { + Arg = Arg.substr(strlen("level=")); + std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); + continue; + } + if (Arg.startswith_lower("uiaccess=")) { + Arg = Arg.substr(strlen("uiaccess=")); + std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); + continue; + } + fatal("invalid option " + Arg); + } +} + +// An RAII temporary file class that automatically removes a temporary file. +namespace { +class TemporaryFile { +public: + TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { + SmallString<128> S; + if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) + fatal(EC, "cannot create a temporary file"); + Path = S.str(); + + if (!Contents.empty()) { + std::error_code EC; + raw_fd_ostream OS(Path, EC, sys::fs::F_None); + if (EC) + fatal(EC, "failed to open " + Path); + OS << Contents; + } + } + + TemporaryFile(TemporaryFile &&Obj) { + std::swap(Path, Obj.Path); + } + + ~TemporaryFile() { + if (Path.empty()) + return; + if (sys::fs::remove(Path)) + fatal("failed to remove " + Path); + } + + // Returns a memory buffer of this temporary file. + // Note that this function does not leave the file open, + // so it is safe to remove the file immediately after this function + // is called (you cannot remove an opened file on Windows.) + std::unique_ptr getMemoryBuffer() { + // IsVolatileSize=true forces MemoryBuffer to not use mmap(). + return check(MemoryBuffer::getFile(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false, + /*IsVolatileSize=*/true), + "could not open " + Path); + } + + std::string Path; +}; +} + +// Create the default manifest file as a temporary file. +TemporaryFile createDefaultXml() { + // Create a temporary file. + TemporaryFile File("defaultxml", "manifest"); + + // Open the temporary file for writing. + std::error_code EC; + raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text); + if (EC) + fatal(EC, "failed to open " + File.Path); + + // Emit the XML. Note that we do *not* verify that the XML attributes are + // syntactically correct. This is intentional for link.exe compatibility. + OS << "\n" + << "\n"; + if (Config->ManifestUAC) { + OS << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n"; + if (!Config->ManifestDependency.empty()) { + OS << " \n" + << " \n" + << " ManifestDependency << " />\n" + << " \n" + << " \n"; + } + } + OS << "\n"; + OS.close(); + return File; +} + +static std::string readFile(StringRef Path) { + std::unique_ptr MB = + check(MemoryBuffer::getFile(Path), "could not open " + Path); + return MB->getBuffer(); +} + +static std::string createManifestXml() { + // Create the default manifest file. + TemporaryFile File1 = createDefaultXml(); + if (Config->ManifestInput.empty()) + return readFile(File1.Path); + + // If manifest files are supplied by the user using /MANIFESTINPUT + // option, we need to merge them with the default manifest. + TemporaryFile File2("user", "manifest"); + + Executor E("mt.exe"); + E.add("/manifest"); + E.add(File1.Path); + for (StringRef Filename : Config->ManifestInput) { + E.add("/manifest"); + E.add(Filename); + } + E.add("/nologo"); + E.add("/out:" + StringRef(File2.Path)); + E.run(); + return readFile(File2.Path); +} + +static std::unique_ptr +createMemoryBufferForManifestRes(size_t ManifestSize) { + size_t ResSize = alignTo( + object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + + sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix) + ManifestSize, + object::WIN_RES_DATA_ALIGNMENT); + return MemoryBuffer::getNewMemBuffer(ResSize); +} + +static void writeResFileHeader(char *&Buf) { + memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); + Buf += sizeof(COFF::WinResMagic); + memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); + Buf += object::WIN_RES_NULL_ENTRY_SIZE; +} + +static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { + // Write the prefix. + auto *Prefix = reinterpret_cast(Buf); + Prefix->DataSize = ManifestSize; + Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix); + Buf += sizeof(object::WinResHeaderPrefix); + + // Write the Type/Name IDs. + auto *IDs = reinterpret_cast(Buf); + IDs->setType(RT_MANIFEST); + IDs->setName(Config->ManifestID); + Buf += sizeof(object::WinResIDs); + + // Write the suffix. + auto *Suffix = reinterpret_cast(Buf); + Suffix->DataVersion = 0; + Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; + Suffix->Language = SUBLANG_ENGLISH_US; + Suffix->Version = 0; + Suffix->Characteristics = 0; + Buf += sizeof(object::WinResHeaderSuffix); +} + +// Create a resource file containing a manifest XML. +std::unique_ptr createManifestRes() { + std::string Manifest = createManifestXml(); + + std::unique_ptr Res = + createMemoryBufferForManifestRes(Manifest.size()); + + char *Buf = const_cast(Res->getBufferStart()); + writeResFileHeader(Buf); + writeResEntryHeader(Buf, Manifest.size()); + + // Copy the manifest data into the .res file. + std::copy(Manifest.begin(), Manifest.end(), Buf); + return Res; +} + +void createSideBySideManifest() { + std::string Path = Config->ManifestFile; + if (Path == "") + Path = Config->OutputFile + ".manifest"; + std::error_code EC; + raw_fd_ostream Out(Path, EC, sys::fs::F_Text); + if (EC) + fatal(EC, "failed to create manifest"); + Out << createManifestXml(); +} + +// Parse a string in the form of +// "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]" +// or "=.". +// Used for parsing /export arguments. +Export parseExport(StringRef Arg) { + Export E; + StringRef Rest; + std::tie(E.Name, Rest) = Arg.split(","); + if (E.Name.empty()) + goto err; + + if (E.Name.find('=') != StringRef::npos) { + StringRef X, Y; + std::tie(X, Y) = E.Name.split("="); + + // If "=.". + if (Y.find(".") != StringRef::npos) { + E.Name = X; + E.ForwardTo = Y; + return E; + } + + E.ExtName = X; + E.Name = Y; + if (E.Name.empty()) + goto err; + } + + // If "=[,@ordinal[,NONAME]][,DATA][,PRIVATE]" + while (!Rest.empty()) { + StringRef Tok; + std::tie(Tok, Rest) = Rest.split(","); + if (Tok.equals_lower("noname")) { + if (E.Ordinal == 0) + goto err; + E.Noname = true; + continue; + } + if (Tok.equals_lower("data")) { + E.Data = true; + continue; + } + if (Tok.equals_lower("constant")) { + E.Constant = true; + continue; + } + if (Tok.equals_lower("private")) { + E.Private = true; + continue; + } + if (Tok.startswith("@")) { + int32_t Ord; + if (Tok.substr(1).getAsInteger(0, Ord)) + goto err; + if (Ord <= 0 || 65535 < Ord) + goto err; + E.Ordinal = Ord; + continue; + } + goto err; + } + return E; + +err: + fatal("invalid /export: " + Arg); +} + +static StringRef undecorate(StringRef Sym) { + if (Config->Machine != I386) + return Sym; + return Sym.startswith("_") ? Sym.substr(1) : Sym; +} + +// Performs error checking on all /export arguments. +// It also sets ordinals. +void fixupExports() { + // Symbol ordinals must be unique. + std::set Ords; + for (Export &E : Config->Exports) { + if (E.Ordinal == 0) + continue; + if (!Ords.insert(E.Ordinal).second) + fatal("duplicate export ordinal: " + E.Name); + } + + for (Export &E : Config->Exports) { + SymbolBody *Sym = E.Sym; + if (!E.ForwardTo.empty() || !Sym) { + E.SymbolName = E.Name; + } else { + if (auto *U = dyn_cast(Sym)) + if (U->WeakAlias) + Sym = U->WeakAlias; + E.SymbolName = Sym->getName(); + } + } + + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) { + E.ExportName = undecorate(E.Name); + } else { + E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); + } + } + + // Uniquefy by name. + std::map Map; + std::vector V; + for (Export &E : Config->Exports) { + auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); + bool Inserted = Pair.second; + if (Inserted) { + V.push_back(E); + continue; + } + Export *Existing = Pair.first->second; + if (E == *Existing || E.Name != Existing->Name) + continue; + warn("duplicate /export option: " + E.Name); + } + Config->Exports = std::move(V); + + // Sort by name. + std::sort(Config->Exports.begin(), Config->Exports.end(), + [](const Export &A, const Export &B) { + return A.ExportName < B.ExportName; + }); +} + +void assignExportOrdinals() { + // Assign unique ordinals if default (= 0). + uint16_t Max = 0; + for (Export &E : Config->Exports) + Max = std::max(Max, E.Ordinal); + for (Export &E : Config->Exports) + if (E.Ordinal == 0) + E.Ordinal = ++Max; +} + +// Parses a string in the form of "key=value" and check +// if value matches previous values for the same key. +void checkFailIfMismatch(StringRef Arg) { + StringRef K, V; + std::tie(K, V) = Arg.split('='); + if (K.empty() || V.empty()) + fatal("/failifmismatch: invalid argument: " + Arg); + StringRef Existing = Config->MustMatch[K]; + if (!Existing.empty() && V != Existing) + fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V + + " for key " + K); + Config->MustMatch[K] = V; +} + +// Convert Windows resource files (.res files) to a .obj file +// using cvtres.exe. +std::unique_ptr +convertResToCOFF(const std::vector &MBs) { + object::WindowsResourceParser Parser; + + for (MemoryBufferRef MB : MBs) { + std::unique_ptr Bin = check(object::createBinary(MB)); + object::WindowsResource *RF = dyn_cast(Bin.get()); + if (!RF) + fatal("cannot compile non-resource file as resource"); + if (auto EC = Parser.parse(RF)) + fatal(EC, "failed to parse .res file"); + } + + Expected> E = + llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); + if (!E) + fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF"); + return std::move(E.get()); +} + +// Run MSVC link.exe for given in-memory object files. +// Command line options are copied from those given to LLD. +// This is for the /msvclto option. +void runMSVCLinker(std::string Rsp, ArrayRef Objects) { + // Write the in-memory object files to disk. + std::vector Temps; + for (StringRef S : Objects) { + Temps.emplace_back("lto", "obj", S); + Rsp += quote(Temps.back().Path) + "\n"; + } + + log("link.exe " + Rsp); + + // Run MSVC link.exe. + Temps.emplace_back("lto", "rsp", Rsp); + Executor E("link.exe"); + E.add(Twine("@" + Temps.back().Path)); + E.run(); +} + +// Create OptTable + +// Create prefix string literals used in Options.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +// Create table mapping all options defined in Options.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ + {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +#include "Options.inc" +#undef OPTION +}; + +class COFFOptTable : public llvm::opt::OptTable { +public: + COFFOptTable() : OptTable(infoTable, true) {} +}; + +// Parses a given list of options. +opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { + // First, replace respnose files (@-style options). + std::vector Argv = replaceResponseFiles(ArgsArr); + + // Make InputArgList from string vectors. + COFFOptTable Table; + unsigned MissingIndex; + unsigned MissingCount; + opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); + + // Print the real command line if response files are expanded. + if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) { + std::string Msg = "Command line:"; + for (const char *S : Argv) + Msg += " " + std::string(S); + message(Msg); + } + + if (MissingCount) + fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) + warn("ignoring unknown argument: " + Arg->getSpelling()); + return Args; +} + +// link.exe has an interesting feature. If LINK or _LINK_ environment +// variables exist, their contents are handled as command line strings. +// So you can pass extra arguments using them. +opt::InputArgList ArgParser::parseLINK(std::vector Args) { + // Concatenate LINK env and command line arguments, and then parse them. + if (Optional S = Process::GetEnv("LINK")) { + std::vector V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + if (Optional S = Process::GetEnv("_LINK_")) { + std::vector V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + return parse(Args); +} + +std::vector ArgParser::tokenize(StringRef S) { + SmallVector Tokens; + cl::TokenizeWindowsCommandLine(S, Saver, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +// Creates a new command line by replacing options starting with '@' +// character. '@' is replaced by the file's contents. +std::vector +ArgParser::replaceResponseFiles(std::vector Argv) { + SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); + ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +void printHelp(const char *Argv0) { + COFFOptTable Table; + Table.PrintHelp(outs(), Argv0, "LLVM Linker", false); +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Error.cpp b/COFF/Error.cpp new file mode 100644 index 000000000..34abc280f --- /dev/null +++ b/COFF/Error.cpp @@ -0,0 +1,114 @@ +//===- Error.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "Config.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/raw_ostream.h" +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#endif + +using namespace llvm; + +namespace lld { +// The functions defined in this file can be called from multiple threads, +// but outs() or errs() are not thread-safe. We protect them using a mutex. +static std::mutex Mu; + +namespace coff { +uint64_t ErrorCount; +raw_ostream *ErrorOS; + +static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { + // Dealloc/destroy ManagedStatic variables before calling + // _exit(). In a non-LTO build, this is a nop. In an LTO + // build allows us to get the output of -time-passes. + llvm_shutdown(); + + outs().flush(); + errs().flush(); + _exit(Val); +} + +static void print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << Config->Argv[0] << ": "; + if (Config->ColorDiagnostics) { + ErrorOS->changeColor(C, true); + *ErrorOS << S; + ErrorOS->resetColor(); + } else { + *ErrorOS << S; + } +} + +void log(const Twine &Msg) { + if (Config->Verbose) { + std::lock_guard Lock(Mu); + outs() << Config->Argv[0] << ": " << Msg << "\n"; + outs().flush(); + } +} + +void message(const Twine &Msg) { + std::lock_guard Lock(Mu); + outs() << Msg << "\n"; + outs().flush(); +} + +void error(const Twine &Msg) { + std::lock_guard Lock(Mu); + + if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << Msg << "\n"; + } else if (ErrorCount == Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << "too many errors emitted, stopping now" + << " (use /ERRORLIMIT:0 to see all errors)\n"; + exitLld(1); + } + + ++ErrorCount; +} + +void fatal(const Twine &Msg) { + if (Config->ColorDiagnostics) { + errs().changeColor(raw_ostream::RED, /*bold=*/true); + errs() << "error: "; + errs().resetColor(); + } else { + errs() << "error: "; + } + errs() << Msg << "\n"; + exitLld(1); +} + +void fatal(std::error_code EC, const Twine &Msg) { + fatal(Msg + ": " + EC.message()); +} + +void fatal(llvm::Error &Err, const Twine &Msg) { + fatal(errorToErrorCode(std::move(Err)), Msg); +} + +void warn(const Twine &Msg) { + std::lock_guard Lock(Mu); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; +} + +} // namespace coff +} // namespace lld diff --git a/COFF/Error.h b/COFF/Error.h new file mode 100644 index 000000000..e1e4c1e52 --- /dev/null +++ b/COFF/Error.h @@ -0,0 +1,62 @@ +//===- Error.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_ERROR_H +#define LLD_COFF_ERROR_H + +#include "lld/Core/LLVM.h" +#include "llvm/Support/Error.h" + +namespace lld { +namespace coff { + +extern uint64_t ErrorCount; +extern llvm::raw_ostream *ErrorOS; + +void log(const Twine &Msg); +void message(const Twine &Msg); +void warn(const Twine &Msg); +void error(const Twine &Msg); +LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); +LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); +LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); + +template T check(ErrorOr V, const Twine &Prefix) { + if (auto EC = V.getError()) + fatal(EC, Prefix); + return std::move(*V); +} + +template T check(Expected E, const Twine &Prefix) { + if (llvm::Error Err = E.takeError()) + fatal(Err, Prefix); + return std::move(*E); +} + +template T check(ErrorOr EO) { + if (!EO) + fatal(EO.getError().message()); + return std::move(*EO); +} + +template T check(Expected E) { + if (!E) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(E.takeError(), OS, ""); + OS.flush(); + fatal(Buf); + } + return std::move(*E); +} + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp new file mode 100644 index 000000000..da8ca3605 --- /dev/null +++ b/COFF/ICF.cpp @@ -0,0 +1,258 @@ +//===- ICF.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ICF is short for Identical Code Folding. That is a size optimization to +// identify and merge two or more read-only sections (typically functions) +// that happened to have the same contents. It usually reduces output size +// by a few percent. +// +// On Windows, ICF is enabled by default. +// +// See ELF/ICF.cpp for the details about the algortihm. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Error.h" +#include "Symbols.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Parallel.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; + +namespace lld { +namespace coff { + +class ICF { +public: + void run(const std::vector &V); + +private: + void segregate(size_t Begin, size_t End, bool Constant); + + bool equalsConstant(const SectionChunk *A, const SectionChunk *B); + bool equalsVariable(const SectionChunk *A, const SectionChunk *B); + + uint32_t getHash(SectionChunk *C); + bool isEligible(SectionChunk *C); + + size_t findBoundary(size_t Begin, size_t End); + + void forEachClassRange(size_t Begin, size_t End, + std::function Fn); + + void forEachClass(std::function Fn); + + std::vector Chunks; + int Cnt = 0; + std::atomic Repeat = {false}; +}; + +// Returns a hash value for S. +uint32_t ICF::getHash(SectionChunk *C) { + return hash_combine(C->getPermissions(), + hash_value(C->SectionName), + C->NumRelocs, + C->getAlign(), + uint32_t(C->Header->SizeOfRawData), + C->Checksum); +} + +// Returns true if section S is subject of ICF. +// +// Microsoft's documentation +// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April +// 2017) says that /opt:icf folds both functions and read-only data. +// Despite that, the MSVC linker folds only functions. We found +// a few instances of programs that are not safe for data merging. +// Therefore, we merge only functions just like the MSVC tool. +bool ICF::isEligible(SectionChunk *C) { + bool Global = C->Sym && C->Sym->isExternal(); + bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE; + bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable; +} + +// Split an equivalence class into smaller classes. +void ICF::segregate(size_t Begin, size_t End, bool Constant) { + while (Begin < End) { + // Divide [Begin, End) into two. Let Mid be the start index of the + // second group. + auto Bound = std::stable_partition( + Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { + if (Constant) + return equalsConstant(Chunks[Begin], S); + return equalsVariable(Chunks[Begin], S); + }); + size_t Mid = Bound - Chunks.begin(); + + // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an + // equivalence class ID because every group ends with a unique index. + for (size_t I = Begin; I < Mid; ++I) + Chunks[I]->Class[(Cnt + 1) % 2] = Mid; + + // If we created a group, we need to iterate the main loop again. + if (Mid != End) + Repeat = true; + + Begin = Mid; + } +} + +// Compare "non-moving" part of two sections, namely everything +// except relocation targets. +bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { + if (A->NumRelocs != B->NumRelocs) + return false; + + // Compare relocations. + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + if (R1.Type != R2.Type || + R1.VirtualAddress != R2.VirtualAddress) { + return false; + } + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); + if (B1 == B2) + return true; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getValue() == D2->getValue() && + D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; + return false; + }; + if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) + return false; + + // Compare section attributes and contents. + return A->getPermissions() == B->getPermissions() && + A->SectionName == B->SectionName && + A->getAlign() == B->getAlign() && + A->Header->SizeOfRawData == B->Header->SizeOfRawData && + A->Checksum == B->Checksum && + A->getContents() == B->getContents(); +} + +// Compare "moving" part of two sections, namely relocation targets. +bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { + // Compare relocations. + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); + if (B1 == B2) + return true; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; + return false; + }; + return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); +} + +size_t ICF::findBoundary(size_t Begin, size_t End) { + for (size_t I = Begin + 1; I < End; ++I) + if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) + return I; + return End; +} + +void ICF::forEachClassRange(size_t Begin, size_t End, + std::function Fn) { + if (Begin > 0) + Begin = findBoundary(Begin - 1, End); + + while (Begin < End) { + size_t Mid = findBoundary(Begin, Chunks.size()); + Fn(Begin, Mid); + Begin = Mid; + } +} + +// Call Fn on each class group. +void ICF::forEachClass(std::function Fn) { + // If the number of sections are too small to use threading, + // call Fn sequentially. + if (Chunks.size() < 1024) { + forEachClassRange(0, Chunks.size(), Fn); + ++Cnt; + return; + } + + // Split sections into 256 shards and call Fn in parallel. + size_t NumShards = 256; + size_t Step = Chunks.size() / NumShards; + for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { + size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; + forEachClassRange(I * Step, End, Fn); + }); + ++Cnt; +} + +// Merge identical COMDAT sections. +// Two sections are considered the same if their section headers, +// contents and relocations are all the same. +void ICF::run(const std::vector &Vec) { + // Collect only mergeable sections and group by hash value. + uint32_t NextId = 1; + for (Chunk *C : Vec) { + if (auto *SC = dyn_cast(C)) { + if (isEligible(SC)) + Chunks.push_back(SC); + else + SC->Class[0] = NextId++; + } + } + + // Initially, we use hash values to partition sections. + for (SectionChunk *SC : Chunks) + // Set MSB to 1 to avoid collisions with non-hash classs. + SC->Class[0] = getHash(SC) | (1 << 31); + + // From now on, sections in Chunks are ordered so that sections in + // the same group are consecutive in the vector. + std::stable_sort(Chunks.begin(), Chunks.end(), + [](SectionChunk *A, SectionChunk *B) { + return A->Class[0] < B->Class[0]; + }); + + // Compare static contents and assign unique IDs for each static content. + forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); + + // Split groups by comparing relocations until convergence is obtained. + do { + Repeat = false; + forEachClass( + [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); + } while (Repeat); + + log("ICF needed " + Twine(Cnt) + " iterations"); + + // Merge sections in the same classs. + forEachClass([&](size_t Begin, size_t End) { + if (End - Begin == 1) + return; + + log("Selected " + Chunks[Begin]->getDebugName()); + for (size_t I = Begin + 1; I < End; ++I) { + log(" Removed " + Chunks[I]->getDebugName()); + Chunks[Begin]->replace(Chunks[I]); + } + }); +} + +// Entry point to ICF. +void doICF(const std::vector &Chunks) { ICF().run(Chunks); } + +} // namespace coff +} // namespace lld diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp new file mode 100644 index 000000000..7d41caebb --- /dev/null +++ b/COFF/InputFiles.cpp @@ -0,0 +1,411 @@ +//===- InputFiles.cpp -----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Chunks.h" +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "Memory.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "llvm-c/lto.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Target/TargetOptions.h" +#include +#include +#include + +using namespace llvm; +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm::support::endian; + +using llvm::Triple; +using llvm::support::ulittle32_t; + +namespace lld { +namespace coff { + +/// Checks that Source is compatible with being a weak alias to Target. +/// If Source is Undefined and has no weak alias set, makes it a weak +/// alias to Target. +static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, + SymbolBody *Source, SymbolBody *Target) { + if (auto *U = dyn_cast(Source)) { + if (U->WeakAlias && U->WeakAlias != Target) + Symtab->reportDuplicate(Source->symbol(), F); + U->WeakAlias = Target; + } +} + +ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} + +void ArchiveFile::parse() { + // Parse a MemoryBufferRef as an archive file. + File = check(Archive::create(MB), toString(this)); + + // Read the symbol table to construct Lazy objects. + for (const Archive::Symbol &Sym : File->symbols()) + Symtab->addLazy(this, Sym); +} + +// Returns a buffer pointing to a member file containing a given symbol. +void ArchiveFile::addMember(const Archive::Symbol *Sym) { + const Archive::Child &C = + check(Sym->getMember(), + "could not get the member for symbol " + Sym->getName()); + + // Return an empty buffer if we have already returned the same buffer. + if (!Seen.insert(C.getChildOffset()).second) + return; + + Driver->enqueueArchiveMember(C, Sym->getName(), getName()); +} + +void ObjectFile::parse() { + // Parse a memory buffer as a COFF file. + std::unique_ptr Bin = check(createBinary(MB), toString(this)); + + if (auto *Obj = dyn_cast(Bin.get())) { + Bin.release(); + COFFObj.reset(Obj); + } else { + fatal(toString(this) + " is not a COFF file"); + } + + // Read section and symbol tables. + initializeChunks(); + initializeSymbols(); + initializeSEH(); +} + +void ObjectFile::initializeChunks() { + uint32_t NumSections = COFFObj->getNumberOfSections(); + Chunks.reserve(NumSections); + SparseChunks.resize(NumSections + 1); + for (uint32_t I = 1; I < NumSections + 1; ++I) { + const coff_section *Sec; + StringRef Name; + if (auto EC = COFFObj->getSection(I, Sec)) + fatal(EC, "getSection failed: #" + Twine(I)); + if (auto EC = COFFObj->getSectionName(Sec, Name)) + fatal(EC, "getSectionName failed: #" + Twine(I)); + if (Name == ".sxdata") { + SXData = Sec; + continue; + } + if (Name == ".drectve") { + ArrayRef Data; + COFFObj->getSectionContents(Sec, Data); + Directives = std::string((const char *)Data.data(), Data.size()); + continue; + } + + // Object files may have DWARF debug info or MS CodeView debug info + // (or both). + // + // DWARF sections don't need any special handling from the perspective + // of the linker; they are just a data section containing relocations. + // We can just link them to complete debug info. + // + // CodeView needs a linker support. We need to interpret and debug + // info, and then write it to a separate .pdb file. + + // Ignore debug info unless /debug is given. + if (!Config->Debug && Name.startswith(".debug")) + continue; + + if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) + continue; + auto *C = make(this, Sec); + + // CodeView sections are stored to a different vector because they are not + // linked in the regular manner. + if (C->isCodeView()) + DebugChunks.push_back(C); + else + Chunks.push_back(C); + + SparseChunks[I] = C; + } +} + +void ObjectFile::initializeSymbols() { + uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); + SymbolBodies.reserve(NumSymbols); + SparseSymbolBodies.resize(NumSymbols); + + SmallVector, 8> WeakAliases; + int32_t LastSectionNumber = 0; + + for (uint32_t I = 0; I < NumSymbols; ++I) { + // Get a COFFSymbolRef object. + ErrorOr SymOrErr = COFFObj->getSymbol(I); + if (!SymOrErr) + fatal(SymOrErr.getError(), "broken object file: " + toString(this)); + COFFSymbolRef Sym = *SymOrErr; + + const void *AuxP = nullptr; + if (Sym.getNumberOfAuxSymbols()) + AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); + bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); + + SymbolBody *Body = nullptr; + if (Sym.isUndefined()) { + Body = createUndefined(Sym); + } else if (Sym.isWeakExternal()) { + Body = createUndefined(Sym); + uint32_t TagIndex = + static_cast(AuxP)->TagIndex; + WeakAliases.emplace_back(Body, TagIndex); + } else { + Body = createDefined(Sym, AuxP, IsFirst); + } + if (Body) { + SymbolBodies.push_back(Body); + SparseSymbolBodies[I] = Body; + } + I += Sym.getNumberOfAuxSymbols(); + LastSectionNumber = Sym.getSectionNumber(); + } + + for (auto &KV : WeakAliases) { + SymbolBody *Sym = KV.first; + uint32_t Idx = KV.second; + checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); + } +} + +SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body(); +} + +SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, + bool IsFirst) { + StringRef Name; + if (Sym.isCommon()) { + auto *C = make(Sym); + Chunks.push_back(C); + COFFObj->getSymbolName(Sym, Name); + Symbol *S = + Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); + return S->body(); + } + if (Sym.isAbsolute()) { + COFFObj->getSymbolName(Sym, Name); + // Skip special symbols. + if (Name == "@comp.id") + return nullptr; + // COFF spec 5.10.1. The .sxdata section. + if (Name == "@feat.00") { + if (Sym.getValue() & 1) + SEHCompat = true; + return nullptr; + } + if (Sym.isExternal()) + return Symtab->addAbsolute(Name, Sym)->body(); + else + return make(Name, Sym); + } + int32_t SectionNumber = Sym.getSectionNumber(); + if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) + return nullptr; + + // Reserved sections numbers don't have contents. + if (llvm::COFF::isReservedSectionNumber(SectionNumber)) + fatal("broken object file: " + toString(this)); + + // This symbol references a section which is not present in the section + // header. + if ((uint32_t)SectionNumber >= SparseChunks.size()) + fatal("broken object file: " + toString(this)); + + // Nothing else to do without a section chunk. + auto *SC = cast_or_null(SparseChunks[SectionNumber]); + if (!SC) + return nullptr; + + // Handle section definitions + if (IsFirst && AuxP) { + auto *Aux = reinterpret_cast(AuxP); + if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) + if (auto *ParentSC = cast_or_null( + SparseChunks[Aux->getNumber(Sym.isBigObj())])) { + ParentSC->addAssociative(SC); + // If we already discarded the parent, discard the child. + if (ParentSC->isDiscarded()) + SC->markDiscarded(); + } + SC->Checksum = Aux->CheckSum; + } + + DefinedRegular *B; + if (Sym.isExternal()) { + COFFObj->getSymbolName(Sym, Name); + Symbol *S = + Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); + B = cast(S->body()); + } else + B = make(this, /*Name*/ "", SC->isCOMDAT(), + /*IsExternal*/ false, Sym.getGeneric(), SC); + if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) + SC->setSymbol(B); + + return B; +} + +void ObjectFile::initializeSEH() { + if (!SEHCompat || !SXData) + return; + ArrayRef A; + COFFObj->getSectionContents(SXData, A); + if (A.size() % 4 != 0) + fatal(".sxdata must be an array of symbol table indices"); + auto *I = reinterpret_cast(A.data()); + auto *E = reinterpret_cast(A.data() + A.size()); + for (; I != E; ++I) + SEHandlers.insert(SparseSymbolBodies[*I]); +} + +MachineTypes ObjectFile::getMachineType() { + if (COFFObj) + return static_cast(COFFObj->getMachine()); + return IMAGE_FILE_MACHINE_UNKNOWN; +} + +StringRef ltrim1(StringRef S, const char *Chars) { + if (!S.empty() && strchr(Chars, S[0])) + return S.substr(1); + return S; +} + +void ImportFile::parse() { + const char *Buf = MB.getBufferStart(); + const char *End = MB.getBufferEnd(); + const auto *Hdr = reinterpret_cast(Buf); + + // Check if the total size is valid. + if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) + fatal("broken import library"); + + // Read names and create an __imp_ symbol. + StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); + StringRef ImpName = Saver.save("__imp_" + Name); + const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; + DLLName = StringRef(NameStart); + StringRef ExtName; + switch (Hdr->getNameType()) { + case IMPORT_ORDINAL: + ExtName = ""; + break; + case IMPORT_NAME: + ExtName = Name; + break; + case IMPORT_NAME_NOPREFIX: + ExtName = ltrim1(Name, "?@_"); + break; + case IMPORT_NAME_UNDECORATE: + ExtName = ltrim1(Name, "?@_"); + ExtName = ExtName.substr(0, ExtName.find('@')); + break; + } + + this->Hdr = Hdr; + ExternalName = ExtName; + + ImpSym = cast( + Symtab->addImportData(ImpName, this)->body()); + if (Hdr->getType() == llvm::COFF::IMPORT_CONST) + ConstSym = + cast(Symtab->addImportData(Name, this)->body()); + + // If type is function, we need to create a thunk which jump to an + // address pointed by the __imp_ symbol. (This allows you to call + // DLL functions just like regular non-DLL functions.) + if (Hdr->getType() != llvm::COFF::IMPORT_CODE) + return; + ThunkSym = cast( + Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body()); +} + +void BitcodeFile::parse() { + Obj = check(lto::InputFile::create(MemoryBufferRef( + MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { + StringRef SymName = Saver.save(ObjSym.getName()); + Symbol *Sym; + if (ObjSym.isUndefined()) { + Sym = Symtab->addUndefined(SymName, this, false); + } else if (ObjSym.isCommon()) { + Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); + } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { + // Weak external. + Sym = Symtab->addUndefined(SymName, this, true); + std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); + SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback)); + checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias); + } else { + bool IsCOMDAT = ObjSym.getComdatIndex() != -1; + Sym = Symtab->addRegular(this, SymName, IsCOMDAT); + } + SymbolBodies.push_back(Sym->body()); + } + Directives = Obj->getCOFFLinkerOpts(); +} + +MachineTypes BitcodeFile::getMachineType() { + switch (Triple(Obj->getTargetTriple()).getArch()) { + case Triple::x86_64: + return AMD64; + case Triple::x86: + return I386; + case Triple::arm: + return ARMNT; + case Triple::aarch64: + return ARM64; + default: + return IMAGE_FILE_MACHINE_UNKNOWN; + } +} +} // namespace coff +} // namespace lld + +// Returns the last element of a path, which is supposed to be a filename. +static StringRef getBasename(StringRef Path) { + size_t Pos = Path.find_last_of("\\/"); + if (Pos == StringRef::npos) + return Path; + return Path.substr(Pos + 1); +} + +// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". +std::string lld::toString(coff::InputFile *File) { + if (!File) + return "(internal)"; + if (File->ParentName.empty()) + return File->getName().lower(); + + std::string Res = + (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") + .str(); + return StringRef(Res).lower(); +} diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h new file mode 100644 index 000000000..99868d999 --- /dev/null +++ b/COFF/InputFiles.h @@ -0,0 +1,223 @@ +//===- InputFiles.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_INPUT_FILES_H +#define LLD_COFF_INPUT_FILES_H + +#include "Config.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/LTO/LTO.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/StringSaver.h" +#include +#include +#include + +namespace llvm { +namespace pdb { +class DbiModuleDescriptorBuilder; +} +} + +namespace lld { +namespace coff { + +using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; +using llvm::COFF::MachineTypes; +using llvm::object::Archive; +using llvm::object::COFFObjectFile; +using llvm::object::COFFSymbolRef; +using llvm::object::coff_import_header; +using llvm::object::coff_section; + +class Chunk; +class Defined; +class DefinedImportData; +class DefinedImportThunk; +class Lazy; +class SectionChunk; +struct Symbol; +class SymbolBody; +class Undefined; + +// The root class of input files. +class InputFile { +public: + enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; + Kind kind() const { return FileKind; } + virtual ~InputFile() {} + + // Returns the filename. + StringRef getName() { return MB.getBufferIdentifier(); } + + // Reads a file (the constructor doesn't do that). + virtual void parse() = 0; + + // Returns the CPU type this file was compiled to. + virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + + MemoryBufferRef MB; + + // An archive file name if this file is created from an archive. + StringRef ParentName; + + // Returns .drectve section contents if exist. + StringRef getDirectives() { return StringRef(Directives).trim(); } + +protected: + InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} + + std::string Directives; + +private: + const Kind FileKind; +}; + +// .lib or .a file. +class ArchiveFile : public InputFile { +public: + explicit ArchiveFile(MemoryBufferRef M); + static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } + void parse() override; + + // Enqueues an archive member load for the given symbol. If we've already + // enqueued a load for the same archive member, this function does nothing, + // which ensures that we don't load the same member more than once. + void addMember(const Archive::Symbol *Sym); + +private: + std::unique_ptr File; + std::string Filename; + llvm::DenseSet Seen; +}; + +// .obj or .o file. This may be a member of an archive file. +class ObjectFile : public InputFile { +public: + explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } + void parse() override; + MachineTypes getMachineType() override; + std::vector &getChunks() { return Chunks; } + std::vector &getDebugChunks() { return DebugChunks; } + std::vector &getSymbols() { return SymbolBodies; } + + // Returns a SymbolBody object for the SymbolIndex'th symbol in the + // underlying object file. + SymbolBody *getSymbolBody(uint32_t SymbolIndex) { + return SparseSymbolBodies[SymbolIndex]; + } + + // Returns the underying COFF file. + COFFObjectFile *getCOFFObj() { return COFFObj.get(); } + + // True if this object file is compatible with SEH. + // COFF-specific and x86-only. + bool SEHCompat = false; + + // The list of safe exception handlers listed in .sxdata section. + // COFF-specific and x86-only. + std::set SEHandlers; + + // Pointer to the PDB module descriptor builder. Various debug info records + // will reference object files by "module index", which is here. Things like + // source files and section contributions are also recorded here. Will be null + // if we are not producing a PDB. + llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr; + +private: + void initializeChunks(); + void initializeSymbols(); + void initializeSEH(); + + SymbolBody *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst); + SymbolBody *createUndefined(COFFSymbolRef Sym); + + std::unique_ptr COFFObj; + const coff_section *SXData = nullptr; + + // List of all chunks defined by this file. This includes both section + // chunks and non-section chunks for common symbols. + std::vector Chunks; + + // CodeView debug info sections. + std::vector DebugChunks; + + // This vector contains the same chunks as Chunks, but they are + // indexed such that you can get a SectionChunk by section index. + // Nonexistent section indices are filled with null pointers. + // (Because section number is 1-based, the first slot is always a + // null pointer.) + std::vector SparseChunks; + + // List of all symbols referenced or defined by this file. + std::vector SymbolBodies; + + // This vector contains the same symbols as SymbolBodies, but they + // are indexed such that you can get a SymbolBody by symbol + // index. Nonexistent indices (which are occupied by auxiliary + // symbols in the real symbol table) are filled with null pointers. + std::vector SparseSymbolBodies; +}; + +// This type represents import library members that contain DLL names +// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7 +// for details about the format. +class ImportFile : public InputFile { +public: + explicit ImportFile(MemoryBufferRef M) + : InputFile(ImportKind, M), Live(!Config->DoGC) {} + + static bool classof(const InputFile *F) { return F->kind() == ImportKind; } + + DefinedImportData *ImpSym = nullptr; + DefinedImportData *ConstSym = nullptr; + DefinedImportThunk *ThunkSym = nullptr; + std::string DLLName; + +private: + void parse() override; + +public: + StringRef ExternalName; + const coff_import_header *Hdr; + Chunk *Location = nullptr; + + // We want to eliminate dllimported symbols if no one actually refers them. + // This "Live" bit is used to keep track of which import library members + // are actually in use. + // + // If the Live bit is turned off by MarkLive, Writer will ignore dllimported + // symbols provided by this import library member. + bool Live; +}; + +// Used for LTO. +class BitcodeFile : public InputFile { +public: + explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } + std::vector &getSymbols() { return SymbolBodies; } + MachineTypes getMachineType() override; + std::unique_ptr Obj; + +private: + void parse() override; + + std::vector SymbolBodies; +}; +} // namespace coff + +std::string toString(coff::InputFile *File); +} // namespace lld + +#endif diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp new file mode 100644 index 000000000..6883b3b4c --- /dev/null +++ b/COFF/LTO.cpp @@ -0,0 +1,140 @@ +//===- LTO.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTO.h" +#include "Config.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "lld/Core/TargetOptionsCommandFlags.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/LTO/Config.h" +#include "llvm/LTO/LTO.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::object; + +using namespace lld; +using namespace lld::coff; + +static void diagnosticHandler(const DiagnosticInfo &DI) { + SmallString<128> ErrStorage; + raw_svector_ostream OS(ErrStorage); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + warn(ErrStorage); +} + +static void checkError(Error E) { + handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error { + error(EIB.message()); + return Error::success(); + }); +} + +static void saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error("cannot create " + Path + ": " + EC.message()); + OS << Buffer; +} + +static std::unique_ptr createLTO() { + lto::Config Conf; + Conf.Options = InitTargetOptionsFromCodeGenFlags(); + Conf.RelocModel = Reloc::PIC_; + Conf.DisableVerify = true; + Conf.DiagHandler = diagnosticHandler; + Conf.OptLevel = Config->LTOOptLevel; + if (Config->SaveTemps) + checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", + /*UseInputModulePath*/ true)); + lto::ThinBackend Backend; + if (Config->LTOJobs != 0) + Backend = lto::createInProcessThinBackend(Config->LTOJobs); + return llvm::make_unique(std::move(Conf), Backend, + Config->LTOPartitions); +} + +BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} + +BitcodeCompiler::~BitcodeCompiler() = default; + +static void undefine(Symbol *S) { + replaceBody(S, S->body()->getName()); +} + +void BitcodeCompiler::add(BitcodeFile &F) { + lto::InputFile &Obj = *F.Obj; + unsigned SymNum = 0; + std::vector SymBodies = F.getSymbols(); + std::vector Resols(SymBodies.size()); + + // Provide a resolution to the LTO API for each symbol. + for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { + SymbolBody *B = SymBodies[SymNum]; + Symbol *Sym = B->symbol(); + lto::SymbolResolution &R = Resols[SymNum]; + ++SymNum; + + // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile + // reports two symbols for module ASM defined. Without this check, lld + // flags an undefined in IR with a definition in ASM as prevailing. + // Once IRObjectFile is fixed to report only one symbol this hack can + // be removed. + R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F; + R.VisibleToRegularObj = Sym->IsUsedInRegularObj; + if (R.Prevailing) + undefine(Sym); + } + checkError(LTOObj->add(std::move(F.Obj), Resols)); +} + +// Merge all the bitcode files we have seen, codegen the result +// and return the resulting objects. +std::vector BitcodeCompiler::compile() { + unsigned MaxTasks = LTOObj->getMaxTasks(); + Buff.resize(MaxTasks); + + checkError(LTOObj->run([&](size_t Task) { + return llvm::make_unique( + llvm::make_unique(Buff[Task])); + })); + + std::vector Ret; + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buff[I].empty()) + continue; + if (Config->SaveTemps) { + if (I == 0) + saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); + else + saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); + } + Ret.emplace_back(Buff[I].data(), Buff[I].size()); + } + return Ret; +} diff --git a/COFF/LTO.h b/COFF/LTO.h new file mode 100644 index 000000000..194a4cce8 --- /dev/null +++ b/COFF/LTO.h @@ -0,0 +1,56 @@ +//===- LTO.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a way to combine bitcode files into one COFF +// file by compiling them using LLVM. +// +// If LTO is in use, your input files are not in regular COFF files +// but instead LLVM bitcode files. In that case, the linker has to +// convert bitcode files into the native format so that we can create +// a COFF file that contains native code. This file provides that +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_LTO_H +#define LLD_COFF_LTO_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include +#include + +namespace llvm { +namespace lto { +class LTO; +} +} + +namespace lld { +namespace coff { + +class BitcodeFile; +class InputFile; + +class BitcodeCompiler { +public: + BitcodeCompiler(); + ~BitcodeCompiler(); + + void add(BitcodeFile &F); + std::vector compile(); + +private: + std::unique_ptr LTOObj; + std::vector> Buff; +}; +} +} + +#endif diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp new file mode 100644 index 000000000..b63d4672c --- /dev/null +++ b/COFF/MapFile.cpp @@ -0,0 +1,125 @@ +//===- MapFile.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the /lldmap option. It shows lists in order and +// hierarchically the output sections, input sections, input files and +// symbol: +// +// Address Size Align Out File Symbol +// 00201000 00000015 4 .text +// 00201000 0000000e 4 test.o:(.text) +// 0020100e 00000000 0 local +// 00201005 00000000 0 f(int) +// +//===----------------------------------------------------------------------===// + +#include "MapFile.h" +#include "Error.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "Writer.h" + +#include "llvm/Support/Parallel.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; + +using namespace lld; +using namespace lld::coff; + +typedef DenseMap> + SymbolMapTy; + +// Print out the first three columns of a line. +static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, + uint64_t Align) { + OS << format("%08llx %08llx %5lld ", Addr, Size, Align); +} + +static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } + +// Returns a list of all symbols that we want to print out. +static std::vector getSymbols() { + std::vector V; + for (coff::ObjectFile *File : Symtab->ObjectFiles) + for (SymbolBody *B : File->getSymbols()) + if (auto *Sym = dyn_cast(B)) + if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) + V.push_back(Sym); + return V; +} + +// Returns a map from sections to their symbols. +static SymbolMapTy getSectionSyms(ArrayRef Syms) { + SymbolMapTy Ret; + for (DefinedRegular *S : Syms) + Ret[S->getChunk()].push_back(S); + + // Sort symbols by address. + for (auto &It : Ret) { + SmallVectorImpl &V = It.second; + std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { + return A->getRVA() < B->getRVA(); + }); + } + return Ret; +} + +// Construct a map from symbols to their stringified representations. +static DenseMap +getSymbolStrings(ArrayRef Syms) { + std::vector Str(Syms.size()); + for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Str[I]); + writeHeader(OS, Syms[I]->getRVA(), 0, 0); + OS << indent(2) << toString(*Syms[I]); + }); + + DenseMap Ret; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Ret[Syms[I]] = std::move(Str[I]); + return Ret; +} + +void coff::writeMapFile(ArrayRef OutputSections) { + if (Config->MapFile.empty()) + return; + + std::error_code EC; + raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); + if (EC) + fatal("cannot open " + Config->MapFile + ": " + EC.message()); + + // Collect symbol info that we want to print out. + std::vector Syms = getSymbols(); + SymbolMapTy SectionSyms = getSectionSyms(Syms); + DenseMap SymStr = getSymbolStrings(Syms); + + // Print out the header line. + OS << "Address Size Align Out In Symbol\n"; + + // Print out file contents. + for (OutputSection *Sec : OutputSections) { + writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); + OS << Sec->getName() << '\n'; + + for (Chunk *C : Sec->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC) + continue; + + writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlign()); + OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName() + << ")\n"; + for (DefinedRegular *Sym : SectionSyms[SC]) + OS << SymStr[Sym] << '\n'; + } + } +} diff --git a/COFF/MapFile.h b/COFF/MapFile.h new file mode 100644 index 000000000..0d0d68ce3 --- /dev/null +++ b/COFF/MapFile.h @@ -0,0 +1,22 @@ +//===- MapFile.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_MAPFILE_H +#define LLD_COFF_MAPFILE_H + +#include "llvm/ADT/ArrayRef.h" + +namespace lld { +namespace coff { +class OutputSection; +void writeMapFile(llvm::ArrayRef OutputSections); +} +} + +#endif diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp new file mode 100644 index 000000000..a2756e5c8 --- /dev/null +++ b/COFF/MarkLive.cpp @@ -0,0 +1,75 @@ +//===- MarkLive.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include + +namespace lld { +namespace coff { + +// Set live bit on for each reachable chunk. Unmarked (unreachable) +// COMDAT chunks will be ignored by Writer, so they will be excluded +// from the final output. +void markLive(const std::vector &Chunks) { + // We build up a worklist of sections which have been marked as live. We only + // push into the worklist when we discover an unmarked section, and we mark + // as we push, so sections never appear twice in the list. + SmallVector Worklist; + + // COMDAT section chunks are dead by default. Add non-COMDAT chunks. + for (Chunk *C : Chunks) + if (auto *SC = dyn_cast(C)) + if (SC->isLive()) + Worklist.push_back(SC); + + auto Enqueue = [&](SectionChunk *C) { + if (C->isLive()) + return; + C->markLive(); + Worklist.push_back(C); + }; + + auto AddSym = [&](SymbolBody *B) { + if (auto *Sym = dyn_cast(B)) + Enqueue(Sym->getChunk()); + else if (auto *Sym = dyn_cast(B)) + Sym->File->Live = true; + else if (auto *Sym = dyn_cast(B)) + Sym->WrappedSym->File->Live = true; + }; + + // Add GC root chunks. + for (SymbolBody *B : Config->GCRoot) + AddSym(B); + + while (!Worklist.empty()) { + SectionChunk *SC = Worklist.pop_back_val(); + + // If this section was discarded, there are relocations referring to + // discarded sections. Ignore these sections to avoid crashing. They will be + // diagnosed during relocation processing. + if (SC->isDiscarded()) + continue; + + assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); + + // Mark all symbols listed in the relocation table for this section. + for (SymbolBody *B : SC->symbols()) + AddSym(B); + + // Mark associative sections if any. + for (SectionChunk *C : SC->children()) + Enqueue(C); + } +} + +} +} diff --git a/COFF/Memory.h b/COFF/Memory.h new file mode 100644 index 000000000..526f11344 --- /dev/null +++ b/COFF/Memory.h @@ -0,0 +1,52 @@ +//===- Memory.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See ELF/Memory.h +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_MEMORY_H +#define LLD_COFF_MEMORY_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/StringSaver.h" +#include + +namespace lld { +namespace coff { + +extern llvm::BumpPtrAllocator BAlloc; +extern llvm::StringSaver Saver; + +struct SpecificAllocBase { + SpecificAllocBase() { Instances.push_back(this); } + virtual ~SpecificAllocBase() = default; + virtual void reset() = 0; + static std::vector Instances; +}; + +template struct SpecificAlloc : public SpecificAllocBase { + void reset() override { Alloc.DestroyAll(); } + llvm::SpecificBumpPtrAllocator Alloc; +}; + +template T *make(U &&... Args) { + static SpecificAlloc Alloc; + return new (Alloc.Alloc.Allocate()) T(std::forward(Args)...); +} + +inline void freeArena() { + for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances) + Alloc->reset(); + BAlloc.Reset(); +} +} +} + +#endif diff --git a/COFF/Options.td b/COFF/Options.td new file mode 100644 index 000000000..61523c4f2 --- /dev/null +++ b/COFF/Options.td @@ -0,0 +1,139 @@ +include "llvm/Option/OptParser.td" + +// link.exe accepts options starting with either a dash or a slash. + +// Flag that takes no arguments. +class F : Flag<["/", "-", "-?"], name>; + +// Flag that takes one argument after ":". +class P : + Joined<["/", "-", "-?"], name#":">, HelpText; + +// Boolean flag suffixed by ":no". +multiclass B { + def "" : F; + def _no : F, HelpText; +} + +def align : P<"align", "Section alignment">; +def alternatename : P<"alternatename", "Define weak alias">; +def base : P<"base", "Base address of the program">; +def defaultlib : P<"defaultlib", "Add the library to the list of input files">; +def delayload : P<"delayload", "Delay loaded DLL name">; +def entry : P<"entry", "Name of entry point symbol">; +def errorlimit : P<"errorlimit", + "Maximum number of errors to emit before stopping (0 = no limit)">; +def export : P<"export", "Export a function">; +// No help text because /failifmismatch is not intended to be used by the user. +def failifmismatch : P<"failifmismatch", "">; +def heap : P<"heap", "Size of the heap">; +def implib : P<"implib", "Import library name">; +def libpath : P<"libpath", "Additional library search path">; +def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; +def lldsavetemps : F<"lldsavetemps">, + HelpText<"Save temporary files instead of deleting them">; +def machine : P<"machine", "Specify target platform">; +def merge : P<"merge", "Combine sections">; +def mllvm : P<"mllvm", "Options to pass to LLVM">; +def nodefaultlib : P<"nodefaultlib", "Remove a default library">; +def opt : P<"opt", "Control optimizations">; +def out : P<"out", "Path to file to write output">; +def pdb : P<"pdb", "PDB file path">; +def section : P<"section", "Specify section attributes">; +def stack : P<"stack", "Size of the stack">; +def stub : P<"stub", "Specify DOS stub file">; +def subsystem : P<"subsystem", "Specify subsystem">; +def version : P<"version", "Specify a version number in the PE header">; + +def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; + +def manifest : F<"manifest">; +def manifest_colon : P<"manifest", "Create manifest file">; +def manifestuac : P<"manifestuac", "User access control">; +def manifestfile : P<"manifestfile", "Manifest file path">; +def manifestdependency : P<"manifestdependency", + "Attributes for in manifest file">; +def manifestinput : P<"manifestinput", "Specify manifest file">; + +// We cannot use multiclass P because class name "incl" is different +// from its command line option name. We do this because "include" is +// a reserved keyword in tablegen. +def incl : Joined<["/", "-"], "include:">, + HelpText<"Force symbol to be added to symbol table as undefined one">; + +// "def" is also a keyword. +def deffile : Joined<["/", "-"], "def:">, + HelpText<"Use module-definition file">; + +def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; +def debugtype : P<"debugtype", "Debug Info Options">; +def dll : F<"dll">, HelpText<"Create a DLL">; +def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; +def nodefaultlib_all : F<"nodefaultlib">; +def noentry : F<"noentry">; +def profile : F<"profile">; +def swaprun_cd : F<"swaprun:cd">; +def swaprun_net : F<"swaprun:net">; +def verbose : F<"verbose">; + +def force : F<"force">, + HelpText<"Allow undefined symbols when creating executables">; +def force_unresolved : F<"force:unresolved">; + +defm allowbind: B<"allowbind", "Disable DLL binding">; +defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">; +defm appcontainer : B<"appcontainer", + "Image can only be run in an app container">; +defm dynamicbase : B<"dynamicbase", + "Disable address space layout randomization">; +defm fixed : B<"fixed", "Enable base relocations">; +defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">; +defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">; +defm nxcompat : B<"nxcompat", "Disable data execution provention">; +defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">; +defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">; + +def help : F<"help">; +def help_q : Flag<["/?", "-?"], "">, Alias; + +// LLD extensions +def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">; +def nosymtab : F<"nosymtab">; +def msvclto : F<"msvclto">; + +// Flags for debugging +def lldmap : F<"lldmap">; +def lldmap_file : Joined<["/", "-"], "lldmap:">; + +//============================================================================== +// The flags below do nothing. They are defined only for link.exe compatibility. +//============================================================================== + +class QF : Joined<["/", "-", "-?"], name#":">; + +multiclass QB { + def "" : F; + def _no : F; +} + +def functionpadmin : F<"functionpadmin">; +def ignoreidl : F<"ignoreidl">; +def incremental : F<"incremental">; +def no_incremental : F<"incremental:no">; +def nologo : F<"nologo">; +def throwingnew : F<"throwingnew">; +def editandcontinue : F<"editandcontinue">; +def fastfail : F<"fastfail">; + +def delay : QF<"delay">; +def errorreport : QF<"errorreport">; +def idlout : QF<"idlout">; +def ignore : QF<"ignore">; +def maxilksize : QF<"maxilksize">; +def pdbaltpath : QF<"pdbaltpath">; +def tlbid : QF<"tlbid">; +def tlbout : QF<"tlbout">; +def verbose_all : QF<"verbose">; +def guardsym : QF<"guardsym">; + +defm wx : QB<"wx">; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp new file mode 100644 index 000000000..89462da93 --- /dev/null +++ b/COFF/PDB.cpp @@ -0,0 +1,672 @@ +//===- PDB.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PDB.h" +#include "Chunks.h" +#include "Config.h" +#include "Error.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "llvm/DebugInfo/CodeView/CVDebugRecord.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include + +using namespace lld; +using namespace lld::coff; +using namespace llvm; +using namespace llvm::codeview; + +using llvm::object::coff_section; + +static ExitOnError ExitOnErr; + +namespace { +/// Map from type index and item index in a type server PDB to the +/// corresponding index in the destination PDB. +struct CVIndexMap { + SmallVector TPIMap; + SmallVector IPIMap; + bool IsTypeServerMap = false; +}; + +class PDBLinker { +public: + PDBLinker(SymbolTable *Symtab) + : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), + IDTable(Alloc) {} + + /// Emit the basic PDB structure: initial streams, headers, etc. + void initialize(const llvm::codeview::DebugInfo *DI); + + /// Link CodeView from each object file in the symbol table into the PDB. + void addObjectsToPDB(); + + /// Link CodeView from a single object file into the PDB. + void addObjectFile(ObjectFile *File); + + /// Produce a mapping from the type and item indices used in the object + /// file to those in the destination PDB. + /// + /// If the object file uses a type server PDB (compiled with /Zi), merge TPI + /// and IPI from the type server PDB and return a map for it. Each unique type + /// server PDB is merged at most once, so this may return an existing index + /// mapping. + /// + /// If the object does not use a type server PDB (compiled with /Z7), we merge + /// all the type and item records from the .debug$S stream and fill in the + /// caller-provided ObjectIndexMap. + const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap); + + const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS); + + /// Add the section map and section contributions to the PDB. + void addSections(ArrayRef SectionTable); + + /// Write the PDB to disk. + void commit(); + +private: + BumpPtrAllocator Alloc; + + SymbolTable *Symtab; + + pdb::PDBFileBuilder Builder; + + /// Type records that will go into the PDB TPI stream. + TypeTableBuilder TypeTable; + + /// Item records that will go into the PDB IPI stream. + TypeTableBuilder IDTable; + + /// PDBs use a single global string table for filenames in the file checksum + /// table. + DebugStringTableSubsection PDBStrTab; + + llvm::SmallString<128> NativePath; + + std::vector SectionMap; + + /// Type index mappings of type server PDBs that we've loaded so far. + std::map TypeServerIndexMappings; +}; +} + +// Returns a list of all SectionChunks. +static void addSectionContribs(SymbolTable *Symtab, + pdb::DbiStreamBuilder &DbiBuilder) { + for (Chunk *C : Symtab->getChunks()) + if (auto *SC = dyn_cast(C)) + DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header); +} + +static SectionChunk *findByName(std::vector &Sections, + StringRef Name) { + for (SectionChunk *C : Sections) + if (C->getSectionName() == Name) + return C; + return nullptr; +} + +static ArrayRef consumeDebugMagic(ArrayRef Data, + StringRef SecName) { + // First 4 bytes are section magic. + if (Data.size() < 4) + fatal(SecName + " too short"); + if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) + fatal(SecName + " has an invalid magic"); + return Data.slice(4); +} + +static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { + if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) + return consumeDebugMagic(Sec->getContents(), SecName); + return {}; +} + +static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, + TypeTableBuilder &TypeTable) { + // Start the TPI or IPI stream header. + TpiBuilder.setVersionHeader(pdb::PdbTpiV80); + + // Flatten the in memory type table. + TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef Rec) { + // FIXME: Hash types. + TpiBuilder.addTypeRecord(Rec, None); + }); +} + +static Optional +maybeReadTypeServerRecord(CVTypeArray &Types) { + auto I = Types.begin(); + if (I == Types.end()) + return None; + const CVType &Type = *I; + if (Type.kind() != LF_TYPESERVER2) + return None; + TypeServer2Record TS; + if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) + fatal(EC, "error reading type server record"); + return std::move(TS); +} + +const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File, + CVIndexMap &ObjectIndexMap) { + ArrayRef Data = getDebugSection(File, ".debug$T"); + if (Data.empty()) + return ObjectIndexMap; + + BinaryByteStream Stream(Data, support::little); + CVTypeArray Types; + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readArray(Types, Reader.getLength())) + fatal(EC, "Reader::readArray failed"); + + // Look through type servers. If we've already seen this type server, don't + // merge any type information. + if (Optional TS = maybeReadTypeServerRecord(Types)) + return maybeMergeTypeServerPDB(File, *TS); + + // This is a /Z7 object. Fill in the temporary, caller-provided + // ObjectIndexMap. + if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, + ObjectIndexMap.TPIMap, Types)) + fatal(Err, "codeview::mergeTypeAndIdRecords failed"); + return ObjectIndexMap; +} + +static Expected> +tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { + std::unique_ptr ThisSession; + if (auto EC = + pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession)) + return std::move(EC); + + std::unique_ptr NS( + static_cast(ThisSession.release())); + pdb::PDBFile &File = NS->getPDBFile(); + auto ExpectedInfo = File.getPDBInfoStream(); + // All PDB Files should have an Info stream. + if (!ExpectedInfo) + return ExpectedInfo.takeError(); + + // Just because a file with a matching name was found and it was an actual + // PDB file doesn't mean it matches. For it to match the InfoStream's GUID + // must match the GUID specified in the TypeServer2 record. + if (ExpectedInfo->getGuid() != GuidFromObj) + return make_error( + pdb::generic_error_code::type_server_not_found, TSPath); + + return std::move(NS); +} + +const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS) { + // First, check if we already loaded a PDB with this GUID. Return the type + // index mapping if we have it. + auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()}); + CVIndexMap &IndexMap = Insertion.first->second; + if (!Insertion.second) + return IndexMap; + + // Mark this map as a type server map. + IndexMap.IsTypeServerMap = true; + + // Check for a PDB at: + // 1. The given file path + // 2. Next to the object file or archive file + auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName()); + if (!ExpectedSession) { + consumeError(ExpectedSession.takeError()); + StringRef LocalPath = + !File->ParentName.empty() ? File->ParentName : File->getName(); + SmallString<128> Path = sys::path::parent_path(LocalPath); + sys::path::append( + Path, sys::path::filename(TS.getName(), sys::path::Style::windows)); + ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); + } + if (auto E = ExpectedSession.takeError()) + fatal(E, "Type server PDB was not found"); + + // Merge TPI first, because the IPI stream will reference type indices. + auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); + if (auto E = ExpectedTpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, + ExpectedTpi->typeArray())) + fatal(Err, "codeview::mergeTypeRecords failed"); + + // Merge IPI. + auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); + if (auto E = ExpectedIpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, + ExpectedIpi->typeArray())) + fatal(Err, "codeview::mergeIdRecords failed"); + + return IndexMap; +} + +static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { + if (TI.isSimple()) + return true; + if (TI.toArrayIndex() >= TypeIndexMap.size()) + return false; + TI = TypeIndexMap[TI.toArrayIndex()]; + return true; +} + +static void remapTypesInSymbolRecord(ObjectFile *File, + MutableArrayRef Contents, + const CVIndexMap &IndexMap, + ArrayRef TypeRefs) { + for (const TiReference &Ref : TypeRefs) { + unsigned ByteSize = Ref.Count * sizeof(TypeIndex); + if (Contents.size() < Ref.Offset + ByteSize) + fatal("symbol record too short"); + + // This can be an item index or a type index. Choose the appropriate map. + ArrayRef TypeOrItemMap = IndexMap.TPIMap; + if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap) + TypeOrItemMap = IndexMap.IPIMap; + + MutableArrayRef TIs( + reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); + for (TypeIndex &TI : TIs) { + if (!remapTypeIndex(TI, TypeOrItemMap)) { + TI = TypeIndex(SimpleTypeKind::NotTranslated); + log("ignoring symbol record in " + File->getName() + + " with bad type index 0x" + utohexstr(TI.getIndex())); + continue; + } + } + } +} + +/// MSVC translates S_PROC_ID_END to S_END. +uint16_t canonicalizeSymbolKind(SymbolKind Kind) { + if (Kind == SymbolKind::S_PROC_ID_END) + return SymbolKind::S_END; + return Kind; +} + +/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. +/// The object file may not be aligned. +static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, + BumpPtrAllocator &Alloc) { + size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + assert(Size >= 4 && "record too short"); + assert(Size <= MaxRecordLength && "record too long"); + void *Mem = Alloc.Allocate(Size, 4); + + // Copy the symbol record and zero out any padding bytes. + MutableArrayRef NewData(reinterpret_cast(Mem), Size); + memcpy(NewData.data(), Sym.data().data(), Sym.length()); + memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); + + // Update the record prefix length. It should point to the beginning of the + // next record. MSVC does some canonicalization of the record kind, so we do + // that as well. + auto *Prefix = reinterpret_cast(Mem); + Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind()); + Prefix->RecordLen = Size - 2; + return NewData; +} + +/// Return true if this symbol opens a scope. This implies that the symbol has +/// "parent" and "end" fields, which contain the offset of the S_END or +/// S_INLINESITE_END record. +static bool symbolOpensScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_BLOCK32: + case SymbolKind::S_SEPCODE: + case SymbolKind::S_THUNK32: + case SymbolKind::S_INLINESITE: + case SymbolKind::S_INLINESITE2: + return true; + default: + break; + } + return false; +} + +static bool symbolEndsScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_END: + case SymbolKind::S_PROC_ID_END: + case SymbolKind::S_INLINESITE_END: + return true; + default: + break; + } + return false; +} + +struct ScopeRecord { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; +}; + +struct SymbolScope { + ScopeRecord *OpeningRecord; + uint32_t ScopeOffset; +}; + +static void scopeStackOpen(SmallVectorImpl &Stack, + uint32_t CurOffset, CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + SymbolScope S; + S.ScopeOffset = CurOffset; + S.OpeningRecord = const_cast( + reinterpret_cast(Sym.content().data())); + S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; + Stack.push_back(S); +} + +static void scopeStackClose(SmallVectorImpl &Stack, + uint32_t CurOffset, ObjectFile *File) { + if (Stack.empty()) { + warn("symbol scopes are not balanced in " + File->getName()); + return; + } + SymbolScope S = Stack.pop_back_val(); + S.OpeningRecord->PtrEnd = CurOffset; +} + +static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, + const CVIndexMap &IndexMap, + BinaryStreamRef SymData) { + // FIXME: Improve error recovery by warning and skipping records when + // possible. + CVSymbolArray Syms; + BinaryStreamReader Reader(SymData); + ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + SmallVector Scopes; + for (const CVSymbol &Sym : Syms) { + // Discover type index references in the record. Skip it if we don't know + // where they are. + SmallVector TypeRefs; + if (!discoverTypeIndices(Sym, TypeRefs)) { + log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); + continue; + } + + // Copy the symbol record so we can mutate it. + MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); + + // Re-map all the type index references. + MutableArrayRef Contents = + NewData.drop_front(sizeof(RecordPrefix)); + remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs); + + // Fill in "Parent" and "End" fields by maintaining a stack of scopes. + CVSymbol NewSym(Sym.kind(), NewData); + if (symbolOpensScope(Sym.kind())) + scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); + else if (symbolEndsScope(Sym.kind())) + scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); + + // Add the symbol to the module. + File->ModuleDBI->addSymbol(NewSym); + } +} + +// Allocate memory for a .debug$S section and relocate it. +static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, + SectionChunk *DebugChunk) { + uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); + assert(DebugChunk->OutputSectionOff == 0 && + "debug sections should not be in output sections"); + DebugChunk->writeTo(Buffer); + return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), + ".debug$S"); +} + +void PDBLinker::addObjectFile(ObjectFile *File) { + // Add a module descriptor for every object file. We need to put an absolute + // path to the object into the PDB. If this is a plain object, we make its + // path absolute. If it's an object in an archive, we make the archive path + // absolute. + bool InArchive = !File->ParentName.empty(); + SmallString<128> Path = InArchive ? File->ParentName : File->getName(); + sys::fs::make_absolute(Path); + sys::path::native(Path, sys::path::Style::windows); + StringRef Name = InArchive ? File->getName() : StringRef(Path); + + File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); + File->ModuleDBI->setObjFileName(Path); + + // Before we can process symbol substreams from .debug$S, we need to process + // type information, file checksums, and the string table. Add type info to + // the PDB first, so that we can get the map from object file type and item + // indices to PDB type and item indices. + CVIndexMap ObjectIndexMap; + const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap); + + // Now do all live .debug$S sections. + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + continue; + + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, DebugChunk); + if (RelocatedDebugContents.empty()) + continue; + + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::FileChecksums: + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: + // We can add the relocated line table directly to the PDB without + // modification because the file checksum offsets will stay the same. + File->ModuleDBI->addDebugSubsection(SS); + break; + case DebugSubsectionKind::Symbols: + mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData()); + break; + default: + // FIXME: Process the rest of the subsections. + break; + } + } + + if (Checksums.valid()) { + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + if (!CVStrTab.valid()) + fatal(".debug$S sections must have both a string table subsection " + "and a checksum subsection table or neither"); + auto NewChecksums = make_unique(PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, + FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + } + } +} + +// Add all object files to the PDB. Merge .debug$T sections into IpiData and +// TpiData. +void PDBLinker::addObjectsToPDB() { + for (ObjectFile *File : Symtab->ObjectFiles) + addObjectFile(File); + + Builder.getStringTableBuilder().setStrings(PDBStrTab); + + // Construct TPI stream contents. + addTypeInfo(Builder.getTpiBuilder(), TypeTable); + + // Construct IPI stream contents. + addTypeInfo(Builder.getIpiBuilder(), IDTable); + + // Add public and symbol records stream. + + // For now we don't actually write any thing useful to the publics stream, but + // the act of "getting" it also creates it lazily so that we write an empty + // stream. + (void)Builder.getPublicsBuilder(); +} + +static void addLinkerModuleSymbols(StringRef Path, + pdb::DbiModuleDescriptorBuilder &Mod, + BumpPtrAllocator &Allocator) { + codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb); + codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym); + codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); + + ONS.Name = "* Linker *"; + ONS.Signature = 0; + + CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; + CS.Flags = CompileSym3Flags::None; + CS.VersionBackendBuild = 0; + CS.VersionBackendMajor = 0; + CS.VersionBackendMinor = 0; + CS.VersionBackendQFE = 0; + CS.VersionFrontendBuild = 0; + CS.VersionFrontendMajor = 0; + CS.VersionFrontendMinor = 0; + CS.VersionFrontendQFE = 0; + CS.Version = "LLVM Linker"; + CS.setLanguage(SourceLanguage::Link); + + ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); + std::string ArgStr = llvm::join(Args, " "); + EBS.Fields.push_back("cwd"); + SmallString<64> cwd; + sys::fs::current_path(cwd); + EBS.Fields.push_back(cwd); + EBS.Fields.push_back("exe"); + EBS.Fields.push_back(Config->Argv[0]); + EBS.Fields.push_back("pdb"); + EBS.Fields.push_back(Path); + EBS.Fields.push_back("cmd"); + EBS.Fields.push_back(ArgStr); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + EBS, Allocator, CodeViewContainer::Pdb)); +} + +// Creates a PDB file. +void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, + const llvm::codeview::DebugInfo *DI) { + PDBLinker PDB(Symtab); + PDB.initialize(DI); + PDB.addObjectsToPDB(); + PDB.addSections(SectionTable); + PDB.commit(); +} + +void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) { + ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize + + // Create streams in MSF for predefined streams, namely + // PDB, TPI, DBI and IPI. + for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); + + // Add an Info stream. + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); + + GUID uuid{}; + if (DI) + memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); + InfoBuilder.setGuid(uuid); + InfoBuilder.setSignature(time(nullptr)); + InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); + + // Add an empty DBI stream. + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setVersionHeader(pdb::PdbDbiV70); + ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); +} + +void PDBLinker::addSections(ArrayRef SectionTable) { + // Add Section Contributions. + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + addSectionContribs(Symtab, DbiBuilder); + + // Add Section Map stream. + ArrayRef Sections = { + (const object::coff_section *)SectionTable.data(), + SectionTable.size() / sizeof(object::coff_section)}; + SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); + DbiBuilder.setSectionMap(SectionMap); + + // It's not entirely clear what this is, but the * Linker * module uses it. + NativePath = Config->PDBPath; + sys::fs::make_absolute(NativePath); + sys::path::native(NativePath, sys::path::Style::windows); + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); + auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + LinkerModule.setPdbFilePathNI(PdbFilePathNI); + addLinkerModuleSymbols(NativePath, LinkerModule, Alloc); + + // Add COFF section header stream. + ExitOnErr( + DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); +} + +void PDBLinker::commit() { + // Write to a file. + ExitOnErr(Builder.commit(Config->PDBPath)); +} diff --git a/COFF/PDB.h b/COFF/PDB.h new file mode 100644 index 000000000..9aaa3178d --- /dev/null +++ b/COFF/PDB.h @@ -0,0 +1,31 @@ +//===- PDB.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_PDB_H +#define LLD_COFF_PDB_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +namespace codeview { +union DebugInfo; +} +} + +namespace lld { +namespace coff { +class SymbolTable; + +void createPDB(SymbolTable *Symtab, llvm::ArrayRef SectionTable, + const llvm::codeview::DebugInfo *DI); +} +} + +#endif diff --git a/COFF/README.md b/COFF/README.md new file mode 100644 index 000000000..f1bfc9c15 --- /dev/null +++ b/COFF/README.md @@ -0,0 +1 @@ +See docs/NewLLD.rst diff --git a/COFF/Strings.cpp b/COFF/Strings.cpp new file mode 100644 index 000000000..84f9b9a55 --- /dev/null +++ b/COFF/Strings.cpp @@ -0,0 +1,35 @@ +//===- Strings.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Strings.h" +#include + +#if defined(_MSC_VER) +#include +#include +#pragma comment(lib, "dbghelp.lib") +#endif + +using namespace lld; +using namespace lld::coff; +using namespace llvm; + +Optional coff::demangle(StringRef S) { +#if defined(_MSC_VER) + // UnDecorateSymbolName is not thread-safe, so we need a mutex. + static std::mutex Mu; + std::lock_guard Lock(Mu); + + char Buf[4096]; + if (S.startswith("?")) + if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) + return std::string(Buf, Len); +#endif + return None; +} diff --git a/COFF/Strings.h b/COFF/Strings.h new file mode 100644 index 000000000..1f85f3e2d --- /dev/null +++ b/COFF/Strings.h @@ -0,0 +1,23 @@ +//===- Strings.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_STRINGS_H +#define LLD_COFF_STRINGS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace lld { +namespace coff { +llvm::Optional demangle(llvm::StringRef S); +} +} + +#endif diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp new file mode 100644 index 000000000..c06e42bb1 --- /dev/null +++ b/COFF/SymbolTable.cpp @@ -0,0 +1,375 @@ +//===- SymbolTable.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolTable.h" +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "LTO.h" +#include "Memory.h" +#include "Symbols.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +namespace lld { +namespace coff { + +enum SymbolPreference { + SP_EXISTING = -1, + SP_CONFLICT = 0, + SP_NEW = 1, +}; + +/// Checks if an existing symbol S should be kept or replaced by a new symbol. +/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol +/// should be kept, and SP_CONFLICT if no valid resolution exists. +static SymbolPreference compareDefined(Symbol *S, bool WasInserted, + bool NewIsCOMDAT) { + // If the symbol wasn't previously known, the new symbol wins by default. + if (WasInserted || !isa(S->body())) + return SP_NEW; + + // If the existing symbol is a DefinedRegular, both it and the new symbol + // must be comdats. In that case, we have no reason to prefer one symbol + // over the other, and we keep the existing one. If one of the symbols + // is not a comdat, we report a conflict. + if (auto *R = dyn_cast(S->body())) { + if (NewIsCOMDAT && R->isCOMDAT()) + return SP_EXISTING; + else + return SP_CONFLICT; + } + + // Existing symbol is not a DefinedRegular; new symbol wins. + return SP_NEW; +} + +SymbolTable *Symtab; + +void SymbolTable::addFile(InputFile *File) { + log("Reading " + toString(File)); + File->parse(); + + MachineTypes MT = File->getMachineType(); + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + Config->Machine = MT; + } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { + fatal(toString(File) + ": machine type " + machineToStr(MT) + + " conflicts with " + machineToStr(Config->Machine)); + } + + if (auto *F = dyn_cast(File)) { + ObjectFiles.push_back(F); + } else if (auto *F = dyn_cast(File)) { + BitcodeFiles.push_back(F); + } else if (auto *F = dyn_cast(File)) { + ImportFiles.push_back(F); + } + + StringRef S = File->getDirectives(); + if (S.empty()) + return; + + log("Directives: " + toString(File) + ": " + S); + Driver->parseDirectives(S); +} + +void SymbolTable::reportRemainingUndefines() { + SmallPtrSet Undefs; + for (auto &I : Symtab) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym->body()); + if (!Undef) + continue; + if (!Sym->IsUsedInRegularObj) + continue; + StringRef Name = Undef->getName(); + // A weak alias may have been resolved, so check for that. + if (Defined *D = Undef->getWeakAlias()) { + // We resolve weak aliases by replacing the alias's SymbolBody with the + // target's SymbolBody. This causes all SymbolBody pointers referring to + // the old symbol to instead refer to the new symbol. However, we can't + // just blindly copy sizeof(Symbol::Body) bytes from D to Sym->Body + // because D may be an internal symbol, and internal symbols are stored as + // "unparented" SymbolBodies. For that reason we need to check which type + // of symbol we are dealing with and copy the correct number of bytes. + if (isa(D)) + memcpy(Sym->Body.buffer, D, sizeof(DefinedRegular)); + else if (isa(D)) + memcpy(Sym->Body.buffer, D, sizeof(DefinedAbsolute)); + else + // No other internal symbols are possible. + Sym->Body = D->symbol()->Body; + continue; + } + // If we can resolve a symbol by removing __imp_ prefix, do that. + // This odd rule is for compatibility with MSVC linker. + if (Name.startswith("__imp_")) { + Symbol *Imp = find(Name.substr(strlen("__imp_"))); + if (Imp && isa(Imp->body())) { + auto *D = cast(Imp->body()); + replaceBody(Sym, Name, D); + LocalImportChunks.push_back( + cast(Sym->body())->getChunk()); + continue; + } + } + // Remaining undefined symbols are not fatal if /force is specified. + // They are replaced with dummy defined symbols. + if (Config->Force) + replaceBody(Sym, Name, 0); + Undefs.insert(Sym->body()); + } + if (Undefs.empty()) + return; + for (SymbolBody *B : Config->GCRoot) + if (Undefs.count(B)) + warn(": undefined symbol: " + B->getName()); + for (ObjectFile *File : ObjectFiles) + for (SymbolBody *Sym : File->getSymbols()) + if (Undefs.count(Sym)) + warn(toString(File) + ": undefined symbol: " + Sym->getName()); + if (!Config->Force) + fatal("link failed"); +} + +std::pair SymbolTable::insert(StringRef Name) { + Symbol *&Sym = Symtab[CachedHashStringRef(Name)]; + if (Sym) + return {Sym, false}; + Sym = make(); + Sym->IsUsedInRegularObj = false; + Sym->PendingArchiveLoad = false; + return {Sym, true}; +} + +Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, + bool IsWeakAlias) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (!F || !isa(F)) + S->IsUsedInRegularObj = true; + if (WasInserted || (isa(S->body()) && IsWeakAlias)) { + replaceBody(S, Name); + return S; + } + if (auto *L = dyn_cast(S->body())) { + if (!S->PendingArchiveLoad) { + S->PendingArchiveLoad = true; + L->File->addMember(&L->Sym); + } + } + return S; +} + +void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { + StringRef Name = Sym.getName(); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { + replaceBody(S, F, Sym); + return; + } + auto *U = dyn_cast(S->body()); + if (!U || U->WeakAlias || S->PendingArchiveLoad) + return; + S->PendingArchiveLoad = true; + F->addMember(&Sym); +} + +void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { + error("duplicate symbol: " + toString(*Existing->body()) + " in " + + toString(Existing->body()->getFile()) + " and in " + + (NewFile ? toString(NewFile) : "(internal)")); +} + +Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S->body()) || isa(S->body())) + replaceBody(S, N, Sym); + else if (!isa(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S->body()) || isa(S->body())) + replaceBody(S, N, VA); + else if (!isa(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S->body()) || isa(S->body())) + replaceBody(S, N, C); + else if (!isa(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT, + const coff_symbol_generic *Sym, + SectionChunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + if (!isa(F)) + S->IsUsedInRegularObj = true; + SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT); + if (SP == SP_CONFLICT) { + reportDuplicate(S, F); + } else if (SP == SP_NEW) { + replaceBody(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C); + } else if (SP == SP_EXISTING && IsCOMDAT && C) { + C->markDiscarded(); + // Discard associative chunks that we've parsed so far. No need to recurse + // because an associative section cannot have children. + for (SectionChunk *Child : C->children()) + Child->markDiscarded(); + } + return S; +} + +Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *Sym, CommonChunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + if (!isa(F)) + S->IsUsedInRegularObj = true; + if (WasInserted || !isa(S->body())) + replaceBody(S, F, N, Size, Sym, C); + else if (auto *DC = dyn_cast(S->body())) + if (Size > DC->getSize()) + replaceBody(S, F, N, Size, Sym, C); + return S; +} + +Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S->body()) || isa(S->body())) + replaceBody(S, N, F); + else if (!isa(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, + uint16_t Machine) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S->body()) || isa(S->body())) + replaceBody(S, Name, ID, Machine); + else if (!isa(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +std::vector SymbolTable::getChunks() { + std::vector Res; + for (ObjectFile *File : ObjectFiles) { + std::vector &V = File->getChunks(); + Res.insert(Res.end(), V.begin(), V.end()); + } + return Res; +} + +Symbol *SymbolTable::find(StringRef Name) { + auto It = Symtab.find(CachedHashStringRef(Name)); + if (It == Symtab.end()) + return nullptr; + return It->second; +} + +Symbol *SymbolTable::findUnderscore(StringRef Name) { + if (Config->Machine == I386) + return find(("_" + Name).str()); + return find(Name); +} + +StringRef SymbolTable::findByPrefix(StringRef Prefix) { + for (auto Pair : Symtab) { + StringRef Name = Pair.first.val(); + if (Name.startswith(Prefix)) + return Name; + } + return ""; +} + +StringRef SymbolTable::findMangle(StringRef Name) { + if (Symbol *Sym = find(Name)) + if (!isa(Sym->body())) + return Name; + if (Config->Machine != I386) + return findByPrefix(("?" + Name + "@@Y").str()); + if (!Name.startswith("_")) + return ""; + // Search for x86 C function. + StringRef S = findByPrefix((Name + "@").str()); + if (!S.empty()) + return S; + // Search for x86 C++ non-member function. + return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); +} + +void SymbolTable::mangleMaybe(SymbolBody *B) { + auto *U = dyn_cast(B); + if (!U || U->WeakAlias) + return; + StringRef Alias = findMangle(U->getName()); + if (!Alias.empty()) + U->WeakAlias = addUndefined(Alias); +} + +SymbolBody *SymbolTable::addUndefined(StringRef Name) { + return addUndefined(Name, nullptr, false)->body(); +} + +std::vector SymbolTable::compileBitcodeFiles() { + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFiles) + LTO->add(*F); + return LTO->compile(); +} + +void SymbolTable::addCombinedLTOObjects() { + if (BitcodeFiles.empty()) + return; + for (StringRef Object : compileBitcodeFiles()) { + auto *Obj = make(MemoryBufferRef(Object, "lto.tmp")); + Obj->parse(); + ObjectFiles.push_back(Obj); + } +} + +} // namespace coff +} // namespace lld diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h new file mode 100644 index 000000000..ea74678c2 --- /dev/null +++ b/COFF/SymbolTable.h @@ -0,0 +1,124 @@ +//===- SymbolTable.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_SYMBOL_TABLE_H +#define LLD_COFF_SYMBOL_TABLE_H + +#include "InputFiles.h" +#include "LTO.h" +#include "llvm/ADT/CachedHashString.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +struct LTOCodeGenerator; +} + +namespace lld { +namespace coff { + +class Chunk; +class CommonChunk; +class Defined; +class DefinedAbsolute; +class DefinedRelative; +class Lazy; +class SectionChunk; +class SymbolBody; +struct Symbol; + +// SymbolTable is a bucket of all known symbols, including defined, +// undefined, or lazy symbols (the last one is symbols in archive +// files whose archive members are not yet loaded). +// +// We put all symbols of all files to a SymbolTable, and the +// SymbolTable selects the "best" symbols if there are name +// conflicts. For example, obviously, a defined symbol is better than +// an undefined symbol. Or, if there's a conflict between a lazy and a +// undefined, it'll read an archive member to read a real definition +// to replace the lazy symbol. The logic is implemented in the +// add*() functions, which are called by input files as they are parsed. +// There is one add* function per symbol type. +class SymbolTable { +public: + void addFile(InputFile *File); + + // Try to resolve any undefined symbols and update the symbol table + // accordingly, then print an error message for any remaining undefined + // symbols. + void reportRemainingUndefines(); + + // Returns a list of chunks of selected symbols. + std::vector getChunks(); + + // Returns a symbol for a given name. Returns a nullptr if not found. + Symbol *find(StringRef Name); + Symbol *findUnderscore(StringRef Name); + + // Occasionally we have to resolve an undefined symbol to its + // mangled symbol. This function tries to find a mangled name + // for U from the symbol table, and if found, set the symbol as + // a weak alias for U. + void mangleMaybe(SymbolBody *B); + StringRef findMangle(StringRef Name); + + // Build a set of COFF objects representing the combined contents of + // BitcodeFiles and add them to the symbol table. Called after all files are + // added and before the writer writes results to a file. + void addCombinedLTOObjects(); + std::vector compileBitcodeFiles(); + + // The writer needs to handle DLL import libraries specially in + // order to create the import descriptor table. + std::vector ImportFiles; + + // The writer needs to infer the machine type from the object files. + std::vector ObjectFiles; + + // Creates an Undefined symbol for a given name. + SymbolBody *addUndefined(StringRef Name); + + Symbol *addSynthetic(StringRef N, Chunk *C); + Symbol *addAbsolute(StringRef N, uint64_t VA); + + Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); + void addLazy(ArchiveFile *F, const Archive::Symbol Sym); + Symbol *addAbsolute(StringRef N, COFFSymbolRef S); + Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT, + const llvm::object::coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr); + Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, + const llvm::object::coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr); + Symbol *addImportData(StringRef N, ImportFile *F); + Symbol *addImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine); + + void reportDuplicate(Symbol *Existing, InputFile *NewFile); + + // A list of chunks which to be added to .rdata. + std::vector LocalImportChunks; + +private: + std::pair insert(StringRef Name); + StringRef findByPrefix(StringRef Prefix); + + llvm::DenseMap Symtab; + + std::vector BitcodeFiles; + std::unique_ptr LTO; +}; + +extern SymbolTable *Symtab; + +} // namespace coff +} // namespace lld + +#endif diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp new file mode 100644 index 000000000..9b5907907 --- /dev/null +++ b/COFF/Symbols.cpp @@ -0,0 +1,90 @@ +//===- Symbols.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Symbols.h" +#include "Error.h" +#include "InputFiles.h" +#include "Memory.h" +#include "Strings.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; + +// Returns a symbol name for an error message. +std::string lld::toString(coff::SymbolBody &B) { + if (Optional S = coff::demangle(B.getName())) + return ("\"" + *S + "\" (" + B.getName() + ")").str(); + return B.getName(); +} + +namespace lld { +namespace coff { + +StringRef SymbolBody::getName() { + // COFF symbol names are read lazily for a performance reason. + // Non-external symbol names are never used by the linker except for logging + // or debugging. Their internal references are resolved not by name but by + // symbol index. And because they are not external, no one can refer them by + // name. Object files contain lots of non-external symbols, and creating + // StringRefs for them (which involves lots of strlen() on the string table) + // is a waste of time. + if (Name.empty()) { + auto *D = cast(this); + cast(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name); + } + return Name; +} + +InputFile *SymbolBody::getFile() { + if (auto *Sym = dyn_cast(this)) + return Sym->File; + if (auto *Sym = dyn_cast(this)) + return Sym->File; + return nullptr; +} + +COFFSymbolRef DefinedCOFF::getCOFFSymbol() { + size_t SymSize = + cast(File)->getCOFFObj()->getSymbolTableEntrySize(); + if (SymSize == sizeof(coff_symbol16)) + return COFFSymbolRef(reinterpret_cast(Sym)); + assert(SymSize == sizeof(coff_symbol32)); + return COFFSymbolRef(reinterpret_cast(Sym)); +} + +uint16_t DefinedAbsolute::OutputSectionIndex = 0; + +static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { + if (Machine == AMD64) + return make(S); + if (Machine == I386) + return make(S); + if (Machine == ARM64) + return make(S); + assert(Machine == ARMNT); + return make(S); +} + +DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine) + : Defined(DefinedImportThunkKind, Name), WrappedSym(S), + Data(makeImportThunk(S, Machine)) {} + +Defined *Undefined::getWeakAlias() { + // A weak alias may be a weak alias to another symbol, so check recursively. + for (SymbolBody *A = WeakAlias; A; A = cast(A)->WeakAlias) + if (auto *D = dyn_cast(A)) + return D; + return nullptr; +} +} // namespace coff +} // namespace lld diff --git a/COFF/Symbols.h b/COFF/Symbols.h new file mode 100644 index 000000000..a12ae1c01 --- /dev/null +++ b/COFF/Symbols.h @@ -0,0 +1,443 @@ +//===- Symbols.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_SYMBOLS_H +#define LLD_COFF_SYMBOLS_H + +#include "Chunks.h" +#include "Config.h" +#include "Memory.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include +#include +#include + +namespace lld { +namespace coff { + +using llvm::object::Archive; +using llvm::object::COFFSymbolRef; +using llvm::object::coff_import_header; +using llvm::object::coff_symbol_generic; + +class ArchiveFile; +class InputFile; +class ObjectFile; +struct Symbol; +class SymbolTable; + +// The base class for real symbol classes. +class SymbolBody { +public: + enum Kind { + // The order of these is significant. We start with the regular defined + // symbols as those are the most prevelant and the zero tag is the cheapest + // to set. Among the defined kinds, the lower the kind is preferred over + // the higher kind when testing wether one symbol should take precedence + // over another. + DefinedRegularKind = 0, + DefinedCommonKind, + DefinedLocalImportKind, + DefinedImportThunkKind, + DefinedImportDataKind, + DefinedAbsoluteKind, + DefinedSyntheticKind, + + UndefinedKind, + LazyKind, + + LastDefinedCOFFKind = DefinedCommonKind, + LastDefinedKind = DefinedSyntheticKind, + }; + + Kind kind() const { return static_cast(SymbolKind); } + + // Returns true if this is an external symbol. + bool isExternal() { return IsExternal; } + + // Returns the symbol name. + StringRef getName(); + + // Returns the file from which this symbol was created. + InputFile *getFile(); + + Symbol *symbol(); + const Symbol *symbol() const { + return const_cast(this)->symbol(); + } + +protected: + friend SymbolTable; + explicit SymbolBody(Kind K, StringRef N = "") + : SymbolKind(K), IsExternal(true), IsCOMDAT(false), + WrittenToSymtab(false), Name(N) {} + + const unsigned SymbolKind : 8; + unsigned IsExternal : 1; + + // This bit is used by the \c DefinedRegular subclass. + unsigned IsCOMDAT : 1; + +public: + // This bit is used by Writer::createSymbolAndStringTable() to prevent + // symbols from being written to the symbol table more than once. + unsigned WrittenToSymtab : 1; + +protected: + StringRef Name; +}; + +// The base class for any defined symbols, including absolute symbols, +// etc. +class Defined : public SymbolBody { +public: + Defined(Kind K, StringRef N) : SymbolBody(K, N) {} + + static bool classof(const SymbolBody *S) { + return S->kind() <= LastDefinedKind; + } + + // Returns the RVA (relative virtual address) of this symbol. The + // writer sets and uses RVAs. + uint64_t getRVA(); + + // Returns the chunk containing this symbol. Absolute symbols and __ImageBase + // do not have chunks, so this may return null. + Chunk *getChunk(); +}; + +// Symbols defined via a COFF object file or bitcode file. For COFF files, this +// stores a coff_symbol_generic*, and names of internal symbols are lazily +// loaded through that. For bitcode files, Sym is nullptr and the name is stored +// as a StringRef. +class DefinedCOFF : public Defined { + friend SymbolBody; +public: + DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) + : Defined(K, N), File(F), Sym(S) {} + + static bool classof(const SymbolBody *S) { + return S->kind() <= LastDefinedCOFFKind; + } + + InputFile *getFile() { return File; } + + COFFSymbolRef getCOFFSymbol(); + + InputFile *File; + +protected: + const coff_symbol_generic *Sym; +}; + +// Regular defined symbols read from object file symbol tables. +class DefinedRegular : public DefinedCOFF { +public: + DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, + bool IsExternal = false, + const coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr) + : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) { + this->IsExternal = IsExternal; + this->IsCOMDAT = IsCOMDAT; + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedRegularKind; + } + + uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; } + bool isCOMDAT() { return IsCOMDAT; } + SectionChunk *getChunk() { return *Data; } + uint32_t getValue() { return Sym->Value; } + +private: + SectionChunk **Data; +}; + +class DefinedCommon : public DefinedCOFF { +public: + DefinedCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr) + : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { + this->IsExternal = true; + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedCommonKind; + } + + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data; } + +private: + friend SymbolTable; + uint64_t getSize() const { return Size; } + CommonChunk *Data; + uint64_t Size; +}; + +// Absolute symbols. +class DefinedAbsolute : public Defined { +public: + DefinedAbsolute(StringRef N, COFFSymbolRef S) + : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { + IsExternal = S.isExternal(); + } + + DefinedAbsolute(StringRef N, uint64_t V) + : Defined(DefinedAbsoluteKind, N), VA(V) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedAbsoluteKind; + } + + uint64_t getRVA() { return VA - Config->ImageBase; } + void setVA(uint64_t V) { VA = V; } + + // The sentinel absolute symbol section index. Section index relocations + // against absolute symbols resolve to this 16 bit number, and it is the + // largest valid section index plus one. This is written by the Writer. + static uint16_t OutputSectionIndex; + uint16_t getSecIdx() { return OutputSectionIndex; } + +private: + uint64_t VA; +}; + +// This symbol is used for linker-synthesized symbols like __ImageBase and +// __safe_se_handler_table. +class DefinedSynthetic : public Defined { +public: + explicit DefinedSynthetic(StringRef Name, Chunk *C) + : Defined(DefinedSyntheticKind, Name), C(C) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedSyntheticKind; + } + + // A null chunk indicates that this is __ImageBase. Otherwise, this is some + // other synthesized chunk, like SEHTableChunk. + uint32_t getRVA() { return C ? C->getRVA() : 0; } + Chunk *getChunk() { return C; } + +private: + Chunk *C; +}; + +// This class represents a symbol defined in an archive file. It is +// created from an archive file header, and it knows how to load an +// object file from an archive to replace itself with a defined +// symbol. If the resolver finds both Undefined and Lazy for +// the same name, it will ask the Lazy to load a file. +class Lazy : public SymbolBody { +public: + Lazy(ArchiveFile *F, const Archive::Symbol S) + : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {} + + static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } + + ArchiveFile *File; + +private: + friend SymbolTable; + +private: + const Archive::Symbol Sym; +}; + +// Undefined symbols. +class Undefined : public SymbolBody { +public: + explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == UndefinedKind; + } + + // An undefined symbol can have a fallback symbol which gives an + // undefined symbol a second chance if it would remain undefined. + // If it remains undefined, it'll be replaced with whatever the + // Alias pointer points to. + SymbolBody *WeakAlias = nullptr; + + // If this symbol is external weak, try to resolve it to a defined + // symbol by searching the chain of fallback symbols. Returns the symbol if + // successful, otherwise returns null. + Defined *getWeakAlias(); +}; + +// Windows-specific classes. + +// This class represents a symbol imported from a DLL. This has two +// names for internal use and external use. The former is used for +// name resolution, and the latter is used for the import descriptor +// table in an output. The former has "__imp_" prefix. +class DefinedImportData : public Defined { +public: + DefinedImportData(StringRef N, ImportFile *F) + : Defined(DefinedImportDataKind, N), File(F) { + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedImportDataKind; + } + + uint64_t getRVA() { return File->Location->getRVA(); } + Chunk *getChunk() { return File->Location; } + void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } + + StringRef getDLLName() { return File->DLLName; } + StringRef getExternalName() { return File->ExternalName; } + uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } + + ImportFile *File; +}; + +// This class represents a symbol for a jump table entry which jumps +// to a function in a DLL. Linker are supposed to create such symbols +// without "__imp_" prefix for all function symbols exported from +// DLLs, so that you can call DLL functions as regular functions with +// a regular name. A function pointer is given as a DefinedImportData. +class DefinedImportThunk : public Defined { +public: + DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedImportThunkKind; + } + + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data; } + + DefinedImportData *WrappedSym; + +private: + Chunk *Data; +}; + +// If you have a symbol "__imp_foo" in your object file, a symbol name +// "foo" becomes automatically available as a pointer to "__imp_foo". +// This class is for such automatically-created symbols. +// Yes, this is an odd feature. We didn't intend to implement that. +// This is here just for compatibility with MSVC. +class DefinedLocalImport : public Defined { +public: + DefinedLocalImport(StringRef N, Defined *S) + : Defined(DefinedLocalImportKind, N), Data(make(S)) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedLocalImportKind; + } + + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data; } + +private: + LocalImportChunk *Data; +}; + +inline uint64_t Defined::getRVA() { + switch (kind()) { + case DefinedAbsoluteKind: + return cast(this)->getRVA(); + case DefinedSyntheticKind: + return cast(this)->getRVA(); + case DefinedImportDataKind: + return cast(this)->getRVA(); + case DefinedImportThunkKind: + return cast(this)->getRVA(); + case DefinedLocalImportKind: + return cast(this)->getRVA(); + case DefinedCommonKind: + return cast(this)->getRVA(); + case DefinedRegularKind: + return cast(this)->getRVA(); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get the address for an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + +inline Chunk *Defined::getChunk() { + switch (kind()) { + case DefinedRegularKind: + return cast(this)->getChunk(); + case DefinedAbsoluteKind: + return nullptr; + case DefinedSyntheticKind: + return cast(this)->getChunk(); + case DefinedImportDataKind: + return cast(this)->getChunk(); + case DefinedImportThunkKind: + return cast(this)->getChunk(); + case DefinedLocalImportKind: + return cast(this)->getChunk(); + case DefinedCommonKind: + return cast(this)->getChunk(); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get the chunk of an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + +// A real symbol object, SymbolBody, is usually stored within a Symbol. There's +// always one Symbol for each symbol name. The resolver updates the SymbolBody +// stored in the Body field of this object as it resolves symbols. Symbol also +// holds computed properties of symbol names. +struct Symbol { + // True if this symbol was referenced by a regular (non-bitcode) object. + unsigned IsUsedInRegularObj : 1; + + // True if we've seen both a lazy and an undefined symbol with this symbol + // name, which means that we have enqueued an archive member load and should + // not load any more archive members to resolve the same symbol. + unsigned PendingArchiveLoad : 1; + + // This field is used to store the Symbol's SymbolBody. This instantiation of + // AlignedCharArrayUnion gives us a struct with a char array field that is + // large and aligned enough to store any derived class of SymbolBody. + llvm::AlignedCharArrayUnion< + DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy, + Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport> + Body; + + SymbolBody *body() { + return reinterpret_cast(Body.buffer); + } + const SymbolBody *body() const { return const_cast(this)->body(); } +}; + +template +void replaceBody(Symbol *S, ArgT &&... Arg) { + static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); + static_assert(alignof(T) <= alignof(decltype(S->Body)), + "Body not aligned enough"); + assert(static_cast(static_cast(nullptr)) == nullptr && + "Not a SymbolBody"); + new (S->Body.buffer) T(std::forward(Arg)...); +} + +inline Symbol *SymbolBody::symbol() { + assert(isExternal()); + return reinterpret_cast(reinterpret_cast(this) - + offsetof(Symbol, Body)); +} +} // namespace coff + +std::string toString(coff::SymbolBody &B); +} // namespace lld + +#endif diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp new file mode 100644 index 000000000..a6a5e2784 --- /dev/null +++ b/COFF/Writer.cpp @@ -0,0 +1,900 @@ +//===- Writer.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Writer.h" +#include "Config.h" +#include "DLL.h" +#include "Error.h" +#include "InputFiles.h" +#include "MapFile.h" +#include "Memory.h" +#include "PDB.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Parallel.h" +#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm::support; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::coff; + +static const int SectorSize = 512; +static const int DOSStubSize = 64; +static const int NumberfOfDataDirectory = 16; + +namespace { + +class DebugDirectoryChunk : public Chunk { +public: + DebugDirectoryChunk(const std::vector &R) : Records(R) {} + + size_t getSize() const override { + return Records.size() * sizeof(debug_directory); + } + + void writeTo(uint8_t *B) const override { + auto *D = reinterpret_cast(B + OutputSectionOff); + + for (const Chunk *Record : Records) { + D->Characteristics = 0; + D->TimeDateStamp = 0; + D->MajorVersion = 0; + D->MinorVersion = 0; + D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW; + D->SizeOfData = Record->getSize(); + D->AddressOfRawData = Record->getRVA(); + // TODO(compnerd) get the file offset + D->PointerToRawData = 0; + + ++D; + } + } + +private: + const std::vector &Records; +}; + +class CVDebugRecordChunk : public Chunk { + size_t getSize() const override { + return sizeof(codeview::DebugInfo) + Config->PDBPath.size() + 1; + } + + void writeTo(uint8_t *B) const override { + // Save off the DebugInfo entry to backfill the file signature (build id) + // in Writer::writeBuildId + DI = reinterpret_cast(B + OutputSectionOff); + + DI->Signature.CVSignature = OMF::Signature::PDB70; + + // variable sized field (PDB Path) + auto *P = reinterpret_cast(B + OutputSectionOff + sizeof(*DI)); + if (!Config->PDBPath.empty()) + memcpy(P, Config->PDBPath.data(), Config->PDBPath.size()); + P[Config->PDBPath.size()] = '\0'; + } + +public: + mutable codeview::DebugInfo *DI = nullptr; +}; + +// The writer writes a SymbolTable result to a file. +class Writer { +public: + Writer(SymbolTable *T) : Symtab(T) {} + void run(); + +private: + void createSections(); + void createMiscChunks(); + void createImportTables(); + void createExportTable(); + void assignAddresses(); + void removeEmptySections(); + void createSymbolAndStringTable(); + void openFile(StringRef OutputPath); + template void writeHeader(); + void fixSafeSEHSymbols(); + void setSectionPermissions(); + void writeSections(); + void sortExceptionTable(); + void writeBuildId(); + + llvm::Optional createSymbol(Defined *D); + size_t addEntryToStringTable(StringRef Str); + + OutputSection *findSection(StringRef Name); + OutputSection *createSection(StringRef Name); + void addBaserels(OutputSection *Dest); + void addBaserelBlocks(OutputSection *Dest, std::vector &V); + + uint32_t getSizeOfInitializedData(); + std::map> binImports(); + + SymbolTable *Symtab; + std::unique_ptr Buffer; + std::vector OutputSections; + std::vector Strtab; + std::vector OutputSymtab; + IdataContents Idata; + DelayLoadContents DelayIdata; + EdataContents Edata; + SEHTableChunk *SEHTable = nullptr; + + Chunk *DebugDirectory = nullptr; + std::vector DebugRecords; + CVDebugRecordChunk *BuildId = nullptr; + ArrayRef SectionTable; + + uint64_t FileSize; + uint32_t PointerToSymbolTable = 0; + uint64_t SizeOfImage; + uint64_t SizeOfHeaders; +}; +} // anonymous namespace + +namespace lld { +namespace coff { + +void writeResult(SymbolTable *T) { Writer(T).run(); } + +void OutputSection::setRVA(uint64_t RVA) { + Header.VirtualAddress = RVA; + for (Chunk *C : Chunks) + C->setRVA(C->getRVA() + RVA); +} + +void OutputSection::setFileOffset(uint64_t Off) { + // If a section has no actual data (i.e. BSS section), we want to + // set 0 to its PointerToRawData. Otherwise the output is rejected + // by the loader. + if (Header.SizeOfRawData == 0) + return; + Header.PointerToRawData = Off; +} + +void OutputSection::addChunk(Chunk *C) { + Chunks.push_back(C); + C->setOutputSection(this); + uint64_t Off = Header.VirtualSize; + Off = alignTo(Off, C->getAlign()); + C->setRVA(Off); + C->OutputSectionOff = Off; + Off += C->getSize(); + Header.VirtualSize = Off; + if (C->hasData()) + Header.SizeOfRawData = alignTo(Off, SectorSize); +} + +void OutputSection::addPermissions(uint32_t C) { + Header.Characteristics |= C & PermMask; +} + +void OutputSection::setPermissions(uint32_t C) { + Header.Characteristics = C & PermMask; +} + +// Write the section header to a given buffer. +void OutputSection::writeHeaderTo(uint8_t *Buf) { + auto *Hdr = reinterpret_cast(Buf); + *Hdr = Header; + if (StringTableOff) { + // If name is too long, write offset into the string table as a name. + sprintf(Hdr->Name, "/%d", StringTableOff); + } else { + assert(!Config->Debug || Name.size() <= COFF::NameSize); + strncpy(Hdr->Name, Name.data(), + std::min(Name.size(), (size_t)COFF::NameSize)); + } +} + +} // namespace coff +} // namespace lld + +// The main function of the writer. +void Writer::run() { + createSections(); + createMiscChunks(); + createImportTables(); + createExportTable(); + if (Config->Relocatable) + createSection(".reloc"); + assignAddresses(); + removeEmptySections(); + setSectionPermissions(); + createSymbolAndStringTable(); + openFile(Config->OutputFile); + if (Config->is64()) { + writeHeader(); + } else { + writeHeader(); + } + fixSafeSEHSymbols(); + writeSections(); + sortExceptionTable(); + writeBuildId(); + + if (!Config->PDBPath.empty() && Config->Debug) { + const llvm::codeview::DebugInfo *DI = nullptr; + if (Config->DebugTypes & static_cast(coff::DebugType::CV)) + DI = BuildId->DI; + createPDB(Symtab, SectionTable, DI); + } + + writeMapFile(OutputSections); + + if (auto EC = Buffer->commit()) + fatal(EC, "failed to write the output file"); +} + +static StringRef getOutputSection(StringRef Name) { + StringRef S = Name.split('$').first; + auto It = Config->Merge.find(S); + if (It == Config->Merge.end()) + return S; + return It->second; +} + +// Create output section objects and add them to OutputSections. +void Writer::createSections() { + // First, bin chunks by name. + std::map> Map; + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (SC && !SC->isLive()) { + if (Config->Verbose) + SC->printDiscardedMessage(); + continue; + } + Map[C->getSectionName()].push_back(C); + } + + // Then create an OutputSection for each section. + // '$' and all following characters in input section names are + // discarded when determining output section. So, .text$foo + // contributes to .text, for example. See PE/COFF spec 3.2. + SmallDenseMap Sections; + for (auto Pair : Map) { + StringRef Name = getOutputSection(Pair.first); + OutputSection *&Sec = Sections[Name]; + if (!Sec) { + Sec = make(Name); + OutputSections.push_back(Sec); + } + std::vector &Chunks = Pair.second; + for (Chunk *C : Chunks) { + Sec->addChunk(C); + Sec->addPermissions(C->getPermissions()); + } + } +} + +void Writer::createMiscChunks() { + OutputSection *RData = createSection(".rdata"); + + // Create thunks for locally-dllimported symbols. + if (!Symtab->LocalImportChunks.empty()) { + for (Chunk *C : Symtab->LocalImportChunks) + RData->addChunk(C); + } + + // Create Debug Information Chunks + if (Config->Debug) { + DebugDirectory = make(DebugRecords); + + // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled + if (Config->DebugTypes & static_cast(coff::DebugType::CV)) { + auto *Chunk = make(); + + BuildId = Chunk; + DebugRecords.push_back(Chunk); + } + + RData->addChunk(DebugDirectory); + for (Chunk *C : DebugRecords) + RData->addChunk(C); + } + + // Create SEH table. x86-only. + if (Config->Machine != I386) + return; + + std::set Handlers; + + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { + if (!File->SEHCompat) + return; + for (SymbolBody *B : File->SEHandlers) { + // Make sure the handler is still live. Assume all handlers are regular + // symbols. + auto *D = dyn_cast(B); + if (D && D->getChunk()->isLive()) + Handlers.insert(D); + } + } + + if (!Handlers.empty()) { + SEHTable = make(Handlers); + RData->addChunk(SEHTable); + } +} + +// Create .idata section for the DLL-imported symbol table. +// The format of this section is inherently Windows-specific. +// IdataContents class abstracted away the details for us, +// so we just let it create chunks and add them to the section. +void Writer::createImportTables() { + if (Symtab->ImportFiles.empty()) + return; + + // Initialize DLLOrder so that import entries are ordered in + // the same order as in the command line. (That affects DLL + // initialization order, and this ordering is MSVC-compatible.) + for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + + std::string DLL = StringRef(File->DLLName).lower(); + if (Config->DLLOrder.count(DLL) == 0) + Config->DLLOrder[DLL] = Config->DLLOrder.size(); + } + + OutputSection *Text = createSection(".text"); + for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + + if (DefinedImportThunk *Thunk = File->ThunkSym) + Text->addChunk(Thunk->getChunk()); + + if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { + if (!File->ThunkSym) + fatal("cannot delay-load " + toString(File) + + " due to import of data: " + toString(*File->ImpSym)); + DelayIdata.add(File->ImpSym); + } else { + Idata.add(File->ImpSym); + } + } + + if (!Idata.empty()) { + OutputSection *Sec = createSection(".idata"); + for (Chunk *C : Idata.getChunks()) + Sec->addChunk(C); + } + + if (!DelayIdata.empty()) { + Defined *Helper = cast(Config->DelayLoadHelper); + DelayIdata.create(Helper); + OutputSection *Sec = createSection(".didat"); + for (Chunk *C : DelayIdata.getChunks()) + Sec->addChunk(C); + Sec = createSection(".data"); + for (Chunk *C : DelayIdata.getDataChunks()) + Sec->addChunk(C); + Sec = createSection(".text"); + for (Chunk *C : DelayIdata.getCodeChunks()) + Sec->addChunk(C); + } +} + +void Writer::createExportTable() { + if (Config->Exports.empty()) + return; + OutputSection *Sec = createSection(".edata"); + for (Chunk *C : Edata.Chunks) + Sec->addChunk(C); +} + +// The Windows loader doesn't seem to like empty sections, +// so we remove them if any. +void Writer::removeEmptySections() { + auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; + OutputSections.erase( + std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), + OutputSections.end()); + uint32_t Idx = 1; + for (OutputSection *Sec : OutputSections) + Sec->SectionIndex = Idx++; +} + +size_t Writer::addEntryToStringTable(StringRef Str) { + assert(Str.size() > COFF::NameSize); + size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field + Strtab.insert(Strtab.end(), Str.begin(), Str.end()); + Strtab.push_back('\0'); + return OffsetOfEntry; +} + +Optional Writer::createSymbol(Defined *Def) { + // Relative symbols are unrepresentable in a COFF symbol table. + if (isa(Def)) + return None; + + if (auto *D = dyn_cast(Def)) { + // Don't write dead symbols or symbols in codeview sections to the symbol + // table. + if (!D->getChunk()->isLive() || D->getChunk()->isCodeView()) + return None; + } + + if (auto *Sym = dyn_cast(Def)) + if (!Sym->File->Live) + return None; + + if (auto *Sym = dyn_cast(Def)) + if (!Sym->WrappedSym->File->Live) + return None; + + coff_symbol16 Sym; + StringRef Name = Def->getName(); + if (Name.size() > COFF::NameSize) { + Sym.Name.Offset.Zeroes = 0; + Sym.Name.Offset.Offset = addEntryToStringTable(Name); + } else { + memset(Sym.Name.ShortName, 0, COFF::NameSize); + memcpy(Sym.Name.ShortName, Name.data(), Name.size()); + } + + if (auto *D = dyn_cast(Def)) { + COFFSymbolRef Ref = D->getCOFFSymbol(); + Sym.Type = Ref.getType(); + Sym.StorageClass = Ref.getStorageClass(); + } else { + Sym.Type = IMAGE_SYM_TYPE_NULL; + Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; + } + Sym.NumberOfAuxSymbols = 0; + + switch (Def->kind()) { + case SymbolBody::DefinedAbsoluteKind: + Sym.Value = Def->getRVA(); + Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + break; + default: { + uint64_t RVA = Def->getRVA(); + OutputSection *Sec = nullptr; + for (OutputSection *S : OutputSections) { + if (S->getRVA() > RVA) + break; + Sec = S; + } + Sym.Value = RVA - Sec->getRVA(); + Sym.SectionNumber = Sec->SectionIndex; + break; + } + } + return Sym; +} + +void Writer::createSymbolAndStringTable() { + if (!Config->Debug || !Config->WriteSymtab) + return; + + // Name field in the section table is 8 byte long. Longer names need + // to be written to the string table. First, construct string table. + for (OutputSection *Sec : OutputSections) { + StringRef Name = Sec->getName(); + if (Name.size() <= COFF::NameSize) + continue; + Sec->setStringTableOff(addEntryToStringTable(Name)); + } + + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { + for (SymbolBody *B : File->getSymbols()) { + auto *D = dyn_cast(B); + if (!D || D->WrittenToSymtab) + continue; + D->WrittenToSymtab = true; + + if (Optional Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); + } + } + + OutputSection *LastSection = OutputSections.back(); + // We position the symbol table to be adjacent to the end of the last section. + uint64_t FileOff = LastSection->getFileOff() + + alignTo(LastSection->getRawSize(), SectorSize); + if (!OutputSymtab.empty()) { + PointerToSymbolTable = FileOff; + FileOff += OutputSymtab.size() * sizeof(coff_symbol16); + } + if (!Strtab.empty()) + FileOff += Strtab.size() + 4; + FileSize = alignTo(FileOff, SectorSize); +} + +// Visits all sections to assign incremental, non-overlapping RVAs and +// file offsets. +void Writer::assignAddresses() { + SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + + sizeof(data_directory) * NumberfOfDataDirectory + + sizeof(coff_section) * OutputSections.size(); + SizeOfHeaders += + Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); + SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); + uint64_t RVA = 0x1000; // The first page is kept unmapped. + FileSize = SizeOfHeaders; + // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because + // the loader cannot handle holes. + std::stable_partition( + OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { + return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; + }); + for (OutputSection *Sec : OutputSections) { + if (Sec->getName() == ".reloc") + addBaserels(Sec); + Sec->setRVA(RVA); + Sec->setFileOffset(FileSize); + RVA += alignTo(Sec->getVirtualSize(), PageSize); + FileSize += alignTo(Sec->getRawSize(), SectorSize); + } + SizeOfImage = SizeOfHeaders + alignTo(RVA - 0x1000, PageSize); +} + +template void Writer::writeHeader() { + // Write DOS stub + uint8_t *Buf = Buffer->getBufferStart(); + auto *DOS = reinterpret_cast(Buf); + Buf += DOSStubSize; + DOS->Magic[0] = 'M'; + DOS->Magic[1] = 'Z'; + DOS->AddressOfRelocationTable = sizeof(dos_header); + DOS->AddressOfNewExeHeader = DOSStubSize; + + // Write PE magic + memcpy(Buf, PEMagic, sizeof(PEMagic)); + Buf += sizeof(PEMagic); + + // Write COFF header + auto *COFF = reinterpret_cast(Buf); + Buf += sizeof(*COFF); + COFF->Machine = Config->Machine; + COFF->NumberOfSections = OutputSections.size(); + COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; + if (Config->LargeAddressAware) + COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (!Config->is64()) + COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; + if (Config->DLL) + COFF->Characteristics |= IMAGE_FILE_DLL; + if (!Config->Relocatable) + COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; + COFF->SizeOfOptionalHeader = + sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; + + // Write PE header + auto *PE = reinterpret_cast(Buf); + Buf += sizeof(*PE); + PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + + // If {Major,Minor}LinkerVersion is left at 0.0, then for some + // reason signing the resulting PE file with Authenticode produces a + // signature that fails to validate on Windows 7 (but is OK on 10). + // Set it to 14.0, which is what VS2015 outputs, and which avoids + // that problem. + PE->MajorLinkerVersion = 14; + PE->MinorLinkerVersion = 0; + + PE->ImageBase = Config->ImageBase; + PE->SectionAlignment = PageSize; + PE->FileAlignment = SectorSize; + PE->MajorImageVersion = Config->MajorImageVersion; + PE->MinorImageVersion = Config->MinorImageVersion; + PE->MajorOperatingSystemVersion = Config->MajorOSVersion; + PE->MinorOperatingSystemVersion = Config->MinorOSVersion; + PE->MajorSubsystemVersion = Config->MajorOSVersion; + PE->MinorSubsystemVersion = Config->MinorOSVersion; + PE->Subsystem = Config->Subsystem; + PE->SizeOfImage = SizeOfImage; + PE->SizeOfHeaders = SizeOfHeaders; + if (!Config->NoEntry) { + Defined *Entry = cast(Config->Entry); + PE->AddressOfEntryPoint = Entry->getRVA(); + // Pointer to thumb code must have the LSB set, so adjust it. + if (Config->Machine == ARMNT) + PE->AddressOfEntryPoint |= 1; + } + PE->SizeOfStackReserve = Config->StackReserve; + PE->SizeOfStackCommit = Config->StackCommit; + PE->SizeOfHeapReserve = Config->HeapReserve; + PE->SizeOfHeapCommit = Config->HeapCommit; + + // Import Descriptor Tables and Import Address Tables are merged + // in our output. That's not compatible with the Binding feature + // that is sort of prelinking. Setting this flag to make it clear + // that our outputs are not for the Binding. + PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND; + + if (Config->AppContainer) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; + if (Config->DynamicBase) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + if (Config->HighEntropyVA) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; + if (Config->NxCompat) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + if (!Config->AllowIsolation) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; + if (Config->TerminalServerAware) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; + PE->NumberOfRvaAndSize = NumberfOfDataDirectory; + if (OutputSection *Text = findSection(".text")) { + PE->BaseOfCode = Text->getRVA(); + PE->SizeOfCode = Text->getRawSize(); + } + PE->SizeOfInitializedData = getSizeOfInitializedData(); + + // Write data directory + auto *Dir = reinterpret_cast(Buf); + Buf += sizeof(*Dir) * NumberfOfDataDirectory; + if (OutputSection *Sec = findSection(".edata")) { + Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); + } + if (!Idata.empty()) { + Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); + Dir[IMPORT_TABLE].Size = Idata.getDirSize(); + Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); + Dir[IAT].Size = Idata.getIATSize(); + } + if (OutputSection *Sec = findSection(".rsrc")) { + Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); + } + if (OutputSection *Sec = findSection(".pdata")) { + Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); + } + if (OutputSection *Sec = findSection(".reloc")) { + Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); + Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); + } + if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { + if (Defined *B = dyn_cast(Sym->body())) { + Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[TLS_TABLE].Size = Config->is64() + ? sizeof(object::coff_tls_directory64) + : sizeof(object::coff_tls_directory32); + } + } + if (Config->Debug) { + Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); + Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); + } + if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { + if (auto *B = dyn_cast(Sym->body())) { + SectionChunk *SC = B->getChunk(); + assert(B->getRVA() >= SC->getRVA()); + uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); + if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize()) + fatal("_load_config_used is malformed"); + + ArrayRef SecContents = SC->getContents(); + uint32_t LoadConfigSize = + *reinterpret_cast(&SecContents[OffsetInChunk]); + if (OffsetInChunk + LoadConfigSize > SC->getSize()) + fatal("_load_config_used is too large"); + Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; + } + } + if (!DelayIdata.empty()) { + Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = + DelayIdata.getDirRVA(); + Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); + } + + // Write section table + for (OutputSection *Sec : OutputSections) { + Sec->writeHeaderTo(Buf); + Buf += sizeof(coff_section); + } + SectionTable = ArrayRef( + Buf - OutputSections.size() * sizeof(coff_section), Buf); + + if (OutputSymtab.empty()) + return; + + COFF->PointerToSymbolTable = PointerToSymbolTable; + uint32_t NumberOfSymbols = OutputSymtab.size(); + COFF->NumberOfSymbols = NumberOfSymbols; + auto *SymbolTable = reinterpret_cast( + Buffer->getBufferStart() + COFF->PointerToSymbolTable); + for (size_t I = 0; I != NumberOfSymbols; ++I) + SymbolTable[I] = OutputSymtab[I]; + // Create the string table, it follows immediately after the symbol table. + // The first 4 bytes is length including itself. + Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); + write32le(Buf, Strtab.size() + 4); + if (!Strtab.empty()) + memcpy(Buf + 4, Strtab.data(), Strtab.size()); +} + +void Writer::openFile(StringRef Path) { + Buffer = check( + FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), + "failed to open " + Path); +} + +void Writer::fixSafeSEHSymbols() { + if (!SEHTable) + return; + // Replace the absolute table symbol with a synthetic symbol pointing to the + // SEHTable chunk so that we can emit base relocations for it and resolve + // section relative relocations. + Symbol *T = Symtab->find("___safe_se_handler_table"); + Symbol *C = Symtab->find("___safe_se_handler_count"); + replaceBody(T, T->body()->getName(), SEHTable); + cast(C->body())->setVA(SEHTable->getSize() / 4); +} + +// Handles /section options to allow users to overwrite +// section attributes. +void Writer::setSectionPermissions() { + for (auto &P : Config->Section) { + StringRef Name = P.first; + uint32_t Perm = P.second; + if (auto *Sec = findSection(Name)) + Sec->setPermissions(Perm); + } +} + +// Write section contents to a mmap'ed file. +void Writer::writeSections() { + // Record the section index that should be used when resolving a section + // relocation against an absolute symbol. + DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; + + uint8_t *Buf = Buffer->getBufferStart(); + for (OutputSection *Sec : OutputSections) { + uint8_t *SecBuf = Buf + Sec->getFileOff(); + // Fill gaps between functions in .text with INT3 instructions + // instead of leaving as NUL bytes (which can be interpreted as + // ADD instructions). + if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) + memset(SecBuf, 0xCC, Sec->getRawSize()); + for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), + [&](Chunk *C) { C->writeTo(SecBuf); }); + } +} + +// Sort .pdata section contents according to PE/COFF spec 5.5. +void Writer::sortExceptionTable() { + OutputSection *Sec = findSection(".pdata"); + if (!Sec) + return; + // We assume .pdata contains function table entries only. + uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); + uint8_t *End = Begin + Sec->getVirtualSize(); + if (Config->Machine == AMD64) { + struct Entry { ulittle32_t Begin, End, Unwind; }; + sort(parallel::par, (Entry *)Begin, (Entry *)End, + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + return; + } + if (Config->Machine == ARMNT) { + struct Entry { ulittle32_t Begin, Unwind; }; + sort(parallel::par, (Entry *)Begin, (Entry *)End, + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + return; + } + errs() << "warning: don't know how to handle .pdata.\n"; +} + +// Backfill the CVSignature in a PDB70 Debug Record. This backfilling allows us +// to get reproducible builds. +void Writer::writeBuildId() { + // There is nothing to backfill if BuildId was not setup. + if (BuildId == nullptr) + return; + + assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 && + "only PDB 7.0 is supported"); + assert(sizeof(BuildId->DI->PDB70.Signature) == 16 && + "signature size mismatch"); + + // Compute an MD5 hash. + ArrayRef Buf(Buffer->getBufferStart(), Buffer->getBufferEnd()); + memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16); + + // TODO(compnerd) track the Age + BuildId->DI->PDB70.Age = 1; +} + +OutputSection *Writer::findSection(StringRef Name) { + for (OutputSection *Sec : OutputSections) + if (Sec->getName() == Name) + return Sec; + return nullptr; +} + +uint32_t Writer::getSizeOfInitializedData() { + uint32_t Res = 0; + for (OutputSection *S : OutputSections) + if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) + Res += S->getRawSize(); + return Res; +} + +// Returns an existing section or create a new one if not found. +OutputSection *Writer::createSection(StringRef Name) { + if (auto *Sec = findSection(Name)) + return Sec; + const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; + const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const auto CODE = IMAGE_SCN_CNT_CODE; + const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; + const auto R = IMAGE_SCN_MEM_READ; + const auto W = IMAGE_SCN_MEM_WRITE; + const auto X = IMAGE_SCN_MEM_EXECUTE; + uint32_t Perms = StringSwitch(Name) + .Case(".bss", BSS | R | W) + .Case(".data", DATA | R | W) + .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R) + .Case(".reloc", DATA | DISCARDABLE | R) + .Case(".text", CODE | R | X) + .Default(0); + if (!Perms) + llvm_unreachable("unknown section name"); + auto Sec = make(Name); + Sec->addPermissions(Perms); + OutputSections.push_back(Sec); + return Sec; +} + +// Dest is .reloc section. Add contents to that section. +void Writer::addBaserels(OutputSection *Dest) { + std::vector V; + for (OutputSection *Sec : OutputSections) { + if (Sec == Dest) + continue; + // Collect all locations for base relocations. + for (Chunk *C : Sec->getChunks()) + C->getBaserels(&V); + // Add the addresses to .reloc section. + if (!V.empty()) + addBaserelBlocks(Dest, V); + V.clear(); + } +} + +// Add addresses to .reloc section. Note that addresses are grouped by page. +void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { + const uint32_t Mask = ~uint32_t(PageSize - 1); + uint32_t Page = V[0].RVA & Mask; + size_t I = 0, J = 1; + for (size_t E = V.size(); J < E; ++J) { + uint32_t P = V[J].RVA & Mask; + if (P == Page) + continue; + Dest->addChunk(make(Page, &V[I], &V[0] + J)); + I = J; + Page = P; + } + if (I == J) + return; + Dest->addChunk(make(Page, &V[I], &V[0] + J)); +} diff --git a/COFF/Writer.h b/COFF/Writer.h new file mode 100644 index 000000000..fef575423 --- /dev/null +++ b/COFF/Writer.h @@ -0,0 +1,75 @@ +//===- Writer.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_WRITER_H +#define LLD_COFF_WRITER_H + +#include "Chunks.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFF.h" +#include +#include + +namespace lld { +namespace coff { +class SymbolTable; + +static const int PageSize = 4096; + +void writeResult(SymbolTable *T); + +// OutputSection represents a section in an output file. It's a +// container of chunks. OutputSection and Chunk are 1:N relationship. +// Chunks cannot belong to more than one OutputSections. The writer +// creates multiple OutputSections and assign them unique, +// non-overlapping file offsets and RVAs. +class OutputSection { +public: + OutputSection(llvm::StringRef N) : Name(N), Header({}) {} + void setRVA(uint64_t); + void setFileOffset(uint64_t); + void addChunk(Chunk *C); + llvm::StringRef getName() { return Name; } + std::vector &getChunks() { return Chunks; } + void addPermissions(uint32_t C); + void setPermissions(uint32_t C); + uint32_t getPermissions() { return Header.Characteristics & PermMask; } + uint32_t getCharacteristics() { return Header.Characteristics; } + uint64_t getRVA() { return Header.VirtualAddress; } + uint64_t getFileOff() { return Header.PointerToRawData; } + void writeHeaderTo(uint8_t *Buf); + + // Returns the size of this section in an executable memory image. + // This may be smaller than the raw size (the raw size is multiple + // of disk sector size, so there may be padding at end), or may be + // larger (if that's the case, the loader reserves spaces after end + // of raw data). + uint64_t getVirtualSize() { return Header.VirtualSize; } + + // Returns the size of the section in the output file. + uint64_t getRawSize() { return Header.SizeOfRawData; } + + // Set offset into the string table storing this section name. + // Used only when the name is longer than 8 bytes. + void setStringTableOff(uint32_t V) { StringTableOff = V; } + + // N.B. The section index is one based. + uint32_t SectionIndex = 0; + +private: + llvm::StringRef Name; + llvm::object::coff_section Header; + uint32_t StringTableOff = 0; + std::vector Chunks; +}; + +} +} + +#endif diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp new file mode 100644 index 000000000..b26cf0815 --- /dev/null +++ b/ELF/Arch/AArch64.cpp @@ -0,0 +1,376 @@ +//===- AArch64.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "Thunks.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +// Page(Expr) is the page address of the expression Expr, defined +// as (Expr & ~0xFFF). (This applies even if the machine page size +// supported by the platform has a different value.) +uint64_t elf::getAArch64Page(uint64_t Expr) { + return Expr & ~static_cast(0xFFF); +} + +namespace { +class AArch64 final : public TargetInfo { +public: + AArch64(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + bool isPicRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + bool usesOnlyLowPageBits(uint32_t Type) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +AArch64::AArch64() { + CopyRel = R_AARCH64_COPY; + RelativeRel = R_AARCH64_RELATIVE; + IRelativeRel = R_AARCH64_IRELATIVE; + GotRel = R_AARCH64_GLOB_DAT; + PltRel = R_AARCH64_JUMP_SLOT; + TlsDescRel = R_AARCH64_TLSDESC; + TlsGotRel = R_AARCH64_TLS_TPREL64; + GotEntrySize = 8; + GotPltEntrySize = 8; + PltEntrySize = 16; + PltHeaderSize = 32; + DefaultMaxPageSize = 65536; + + // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant + // 1 of the tls structures and the tcb size is 16. + TcbSize = 16; +} + +RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + default: + return R_ABS; + case R_AARCH64_TLSDESC_ADR_PAGE21: + return R_TLSDESC_PAGE; + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_TLSDESC_ADD_LO12: + return R_TLSDESC; + case R_AARCH64_TLSDESC_CALL: + return R_TLSDESC_CALL; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + return R_TLS; + case R_AARCH64_CALL26: + case R_AARCH64_CONDBR19: + case R_AARCH64_JUMP26: + case R_AARCH64_TSTBR14: + return R_PLT_PC; + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_ADR_PREL_LO21: + return R_PC; + case R_AARCH64_ADR_PREL_PG_HI21: + return R_PAGE_PC; + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + return R_GOT; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + return R_GOT_PAGE_PC; + case R_AARCH64_NONE: + return R_NONE; + } +} + +RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) { + if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) + return R_RELAX_TLS_GD_TO_IE_PAGE_PC; + return R_RELAX_TLS_GD_TO_IE_ABS; + } + return Expr; +} + +bool AArch64::usesOnlyLowPageBits(uint32_t Type) const { + switch (Type) { + default: + return false; + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + return true; + } +} + +bool AArch64::isPicRel(uint32_t Type) const { + return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; +} + +void AArch64::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { + write64le(Buf, InX::Plt->getVA()); +} + +void AArch64::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! + 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) + 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] + 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) + 0x20, 0x02, 0x1f, 0xd6, // br x17 + 0x1f, 0x20, 0x03, 0xd5, // nop + 0x1f, 0x20, 0x03, 0xd5, // nop + 0x1f, 0x20, 0x03, 0xd5 // nop + }; + memcpy(Buf, PltData, sizeof(PltData)); + + uint64_t Got = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); + relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); + relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); +} + +void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) + 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] + 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) + 0x20, 0x02, 0x1f, 0xd6 // br x17 + }; + memcpy(Buf, Inst, sizeof(Inst)); + + relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); + relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); + relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); +} + +static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); +} + +// Return the bits [Start, End] from Val shifted Start bits. +// For instance, getBits(0xF0, 4, 8) returns 0xF. +static uint64_t getBits(uint64_t Val, int Start, int End) { + uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; + return (Val >> Start) & Mask; +} + +static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } + +// Update the immediate field in a AARCH64 ldr, str, and add instruction. +static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { + or32le(L, (Imm & 0xFFF) << 10); +} + +void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_AARCH64_ABS16: + case R_AARCH64_PREL16: + checkIntUInt<16>(Loc, Val, Type); + write16le(Loc, Val); + break; + case R_AARCH64_ABS32: + case R_AARCH64_PREL32: + checkIntUInt<32>(Loc, Val, Type); + write32le(Loc, Val); + break; + case R_AARCH64_ABS64: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_PREL64: + write64le(Loc, Val); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + or32AArch64Imm(Loc, Val); + break; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSDESC_ADR_PAGE21: + checkInt<33>(Loc, Val, Type); + write32AArch64Addr(Loc, Val >> 12); + break; + case R_AARCH64_ADR_PREL_LO21: + checkInt<21>(Loc, Val, Type); + write32AArch64Addr(Loc, Val); + break; + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + checkInt<28>(Loc, Val, Type); + or32le(Loc, (Val & 0x0FFFFFFC) >> 2); + break; + case R_AARCH64_CONDBR19: + checkInt<21>(Loc, Val, Type); + or32le(Loc, (Val & 0x1FFFFC) << 3); + break; + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + checkAlignment<8>(Loc, Val, Type); + or32le(Loc, (Val & 0xFF8) << 7); + break; + case R_AARCH64_LDST8_ABS_LO12_NC: + or32AArch64Imm(Loc, getBits(Val, 0, 11)); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + or32AArch64Imm(Loc, getBits(Val, 1, 11)); + break; + case R_AARCH64_LDST32_ABS_LO12_NC: + or32AArch64Imm(Loc, getBits(Val, 2, 11)); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + or32AArch64Imm(Loc, getBits(Val, 3, 11)); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + or32AArch64Imm(Loc, getBits(Val, 4, 11)); + break; + case R_AARCH64_MOVW_UABS_G0_NC: + or32le(Loc, (Val & 0xFFFF) << 5); + break; + case R_AARCH64_MOVW_UABS_G1_NC: + or32le(Loc, (Val & 0xFFFF0000) >> 11); + break; + case R_AARCH64_MOVW_UABS_G2_NC: + or32le(Loc, (Val & 0xFFFF00000000) >> 27); + break; + case R_AARCH64_MOVW_UABS_G3: + or32le(Loc, (Val & 0xFFFF000000000000) >> 43); + break; + case R_AARCH64_TSTBR14: + checkInt<16>(Loc, Val, Type); + or32le(Loc, (Val & 0xFFFC) << 3); + break; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + checkInt<24>(Loc, Val, Type); + or32AArch64Imm(Loc, Val >> 12); + break; + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: + or32AArch64Imm(Loc, Val); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +void AArch64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // TLSDESC Global-Dynamic relocation are in the form: + // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] + // .tlsdesccall [R_AARCH64_TLSDESC_CALL] + // blr x1 + // And it can optimized to: + // movz x0, #0x0, lsl #16 + // movk x0, #0x10 + // nop + // nop + checkUInt<32>(Loc, Val, Type); + + switch (Type) { + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSDESC_CALL: + write32le(Loc, 0xd503201f); // nop + return; + case R_AARCH64_TLSDESC_ADR_PAGE21: + write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz + return; + case R_AARCH64_TLSDESC_LD64_LO12: + write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} + +void AArch64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // TLSDESC Global-Dynamic relocation are in the form: + // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] + // .tlsdesccall [R_AARCH64_TLSDESC_CALL] + // blr x1 + // And it can optimized to: + // adrp x0, :gottprel:v + // ldr x0, [x0, :gottprel_lo12:v] + // nop + // nop + + switch (Type) { + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSDESC_CALL: + write32le(Loc, 0xd503201f); // nop + break; + case R_AARCH64_TLSDESC_ADR_PAGE21: + write32le(Loc, 0x90000000); // adrp + relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); + break; + case R_AARCH64_TLSDESC_LD64_LO12: + write32le(Loc, 0xf9400000); // ldr + relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); + break; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} + +void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + checkUInt<32>(Loc, Val, Type); + + if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { + // Generate MOVZ. + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); + return; + } + if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { + // Generate MOVK. + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); + return; + } + llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); +} + +TargetInfo *elf::getAArch64TargetInfo() { + static AArch64 Target; + return &Target; +} diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp new file mode 100644 index 000000000..de566c617 --- /dev/null +++ b/ELF/Arch/AMDGPU.cpp @@ -0,0 +1,84 @@ +//===- AMDGPU.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class AMDGPU final : public TargetInfo { +public: + AMDGPU(); + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; +}; +} // namespace + +AMDGPU::AMDGPU() { + RelativeRel = R_AMDGPU_REL64; + GotRel = R_AMDGPU_ABS64; + GotEntrySize = 8; +} + +void AMDGPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_AMDGPU_ABS32: + case R_AMDGPU_GOTPCREL: + case R_AMDGPU_GOTPCREL32_LO: + case R_AMDGPU_REL32: + case R_AMDGPU_REL32_LO: + write32le(Loc, Val); + break; + case R_AMDGPU_ABS64: + write64le(Loc, Val); + break; + case R_AMDGPU_GOTPCREL32_HI: + case R_AMDGPU_REL32_HI: + write32le(Loc, Val >> 32); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_AMDGPU_ABS32: + case R_AMDGPU_ABS64: + return R_ABS; + case R_AMDGPU_REL32: + case R_AMDGPU_REL32_LO: + case R_AMDGPU_REL32_HI: + return R_PC; + case R_AMDGPU_GOTPCREL: + case R_AMDGPU_GOTPCREL32_LO: + case R_AMDGPU_GOTPCREL32_HI: + return R_GOT_PC; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +TargetInfo *elf::getAMDGPUTargetInfo() { + static AMDGPU Target; + return &Target; +} diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp new file mode 100644 index 000000000..106021de7 --- /dev/null +++ b/ELF/Arch/ARM.cpp @@ -0,0 +1,480 @@ +//===- ARM.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "Thunks.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class ARM final : public TargetInfo { +public: + ARM(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + bool isPicRel(uint32_t Type) const override; + uint32_t getDynRel(uint32_t Type) const override; + int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override; + void addPltHeaderSymbols(InputSectionBase *ISD) const override; + bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, + const SymbolBody &S) const override; + bool inBranchRange(uint32_t RelocType, uint64_t Src, + uint64_t Dst) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +ARM::ARM() { + CopyRel = R_ARM_COPY; + RelativeRel = R_ARM_RELATIVE; + IRelativeRel = R_ARM_IRELATIVE; + GotRel = R_ARM_GLOB_DAT; + PltRel = R_ARM_JUMP_SLOT; + TlsGotRel = R_ARM_TLS_TPOFF32; + TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; + TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotEntrySize = 4; + GotPltEntrySize = 4; + PltEntrySize = 16; + PltHeaderSize = 20; + TrapInstr = 0xd4d4d4d4; + // ARM uses Variant 1 TLS + TcbSize = 8; + NeedsThunks = true; +} + +RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + default: + return R_ABS; + case R_ARM_THM_JUMP11: + return R_PC; + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_PREL31: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + return R_PLT_PC; + case R_ARM_GOTOFF32: + // (S + A) - GOT_ORG + return R_GOTREL; + case R_ARM_GOT_BREL: + // GOT(S) + A - GOT_ORG + return R_GOT_OFF; + case R_ARM_GOT_PREL: + case R_ARM_TLS_IE32: + // GOT(S) + A - P + return R_GOT_PC; + case R_ARM_SBREL32: + return R_ARM_SBREL; + case R_ARM_TARGET1: + return Config->Target1Rel ? R_PC : R_ABS; + case R_ARM_TARGET2: + if (Config->Target2 == Target2Policy::Rel) + return R_PC; + if (Config->Target2 == Target2Policy::Abs) + return R_ABS; + return R_GOT_PC; + case R_ARM_TLS_GD32: + return R_TLSGD_PC; + case R_ARM_TLS_LDM32: + return R_TLSLD_PC; + case R_ARM_BASE_PREL: + // B(S) + A - P + // FIXME: currently B(S) assumed to be .got, this may not hold for all + // platforms. + return R_GOTONLY_PC; + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_REL32: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: + return R_PC; + case R_ARM_NONE: + return R_NONE; + case R_ARM_TLS_LE32: + return R_TLS; + } +} + +bool ARM::isPicRel(uint32_t Type) const { + return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || + (Type == R_ARM_ABS32); +} + +uint32_t ARM::getDynRel(uint32_t Type) const { + if (Type == R_ARM_TARGET1 && !Config->Target1Rel) + return R_ARM_ABS32; + if (Type == R_ARM_ABS32) + return Type; + // Keep it going with a dummy value so that we can find more reloc errors. + return R_ARM_ABS32; +} + +void ARM::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { + write32le(Buf, InX::Plt->getVA()); +} + +void ARM::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { + // An ARM entry is the address of the ifunc resolver function. + write32le(Buf, S.getVA()); +} + +void ARM::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! + 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 + 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr + 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] + 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t L1 = InX::Plt->getVA() + 8; + write32le(Buf + 16, GotPlt - L1 - 8); +} + +void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const { + auto *IS = cast(ISD); + addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); +} + +void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + // FIXME: Using simple code sequence with simple relocations. + // There is a more optimal sequence but it requires support for the group + // relocations. See ELF for the ARM Architecture Appendix A.3 + const uint8_t PltData[] = { + 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 + 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc + 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] + 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t L1 = PltEntryAddr + 4; + write32le(Buf + 12, GotPltEntryAddr - L1 - 8); +} + +void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { + auto *IS = cast(ISD); + addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); +} + +bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, + const SymbolBody &S) const { + // If S is an undefined weak symbol in an executable we don't need a Thunk. + // In a DSO calls to undefined symbols, including weak ones get PLT entries + // which may need a thunk. + if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() && + !Config->Shared) + return false; + // A state change from ARM to Thumb and vice versa must go through an + // interworking thunk if the relocation type is not R_ARM_CALL or + // R_ARM_THM_CALL. + switch (RelocType) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + // Source is ARM, all PLT entries are ARM so no interworking required. + // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). + if (Expr == R_PC && ((S.getVA() & 1) == 1)) + return true; + break; + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + // Source is Thumb, all PLT entries are ARM so interworking is required. + // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). + if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) + return true; + break; + } + return false; +} + +bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const { + uint64_t Range; + uint64_t InstrSize; + + switch (RelocType) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + case R_ARM_CALL: + Range = 0x2000000; + InstrSize = 4; + break; + case R_ARM_THM_JUMP19: + Range = 0x100000; + InstrSize = 2; + break; + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + Range = 0x1000000; + InstrSize = 2; + break; + default: + return true; + } + // PC at Src is 2 instructions ahead, immediate of branch is signed + if (Src > Dst) + Range -= 2 * InstrSize; + else + Range += InstrSize; + + if ((Dst & 0x1) == 0) + // Destination is ARM, if ARM caller then Src is already 4-byte aligned. + // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure + // destination will be 4 byte aligned. + Src &= ~0x3; + else + // Bit 0 == 1 denotes Thumb state, it is not part of the range + Dst &= ~0x1; + + uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; + return Distance <= Range; +} + +void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_ARM_ABS32: + case R_ARM_BASE_PREL: + case R_ARM_GLOB_DAT: + case R_ARM_GOTOFF32: + case R_ARM_GOT_BREL: + case R_ARM_GOT_PREL: + case R_ARM_REL32: + case R_ARM_RELATIVE: + case R_ARM_SBREL32: + case R_ARM_TARGET1: + case R_ARM_TARGET2: + case R_ARM_TLS_GD32: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LDM32: + case R_ARM_TLS_LDO32: + case R_ARM_TLS_LE32: + case R_ARM_TLS_TPOFF32: + case R_ARM_TLS_DTPOFF32: + write32le(Loc, Val); + break; + case R_ARM_TLS_DTPMOD32: + write32le(Loc, 1); + break; + case R_ARM_PREL31: + checkInt<31>(Loc, Val, Type); + write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); + break; + case R_ARM_CALL: + // R_ARM_CALL is used for BL and BLX instructions, depending on the + // value of bit 0 of Val, we must select a BL or BLX instruction + if (Val & 1) { + // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. + // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' + checkInt<26>(Loc, Val, Type); + write32le(Loc, 0xfa000000 | // opcode + ((Val & 2) << 23) | // H + ((Val >> 2) & 0x00ffffff)); // imm24 + break; + } + if ((read32le(Loc) & 0xfe000000) == 0xfa000000) + // BLX (always unconditional) instruction to an ARM Target, select an + // unconditional BL. + write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); + // fall through as BL encoding is shared with B + LLVM_FALLTHROUGH; + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + checkInt<26>(Loc, Val, Type); + write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); + break; + case R_ARM_THM_JUMP11: + checkInt<12>(Loc, Val, Type); + write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); + break; + case R_ARM_THM_JUMP19: + // Encoding T3: Val = S:J2:J1:imm6:imm11:0 + checkInt<21>(Loc, Val, Type); + write16le(Loc, + (read16le(Loc) & 0xfbc0) | // opcode cond + ((Val >> 10) & 0x0400) | // S + ((Val >> 12) & 0x003f)); // imm6 + write16le(Loc + 2, + 0x8000 | // opcode + ((Val >> 8) & 0x0800) | // J2 + ((Val >> 5) & 0x2000) | // J1 + ((Val >> 1) & 0x07ff)); // imm11 + break; + case R_ARM_THM_CALL: + // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the + // value of bit 0 of Val, we must select a BL or BLX instruction + if ((Val & 1) == 0) { + // Ensure BLX destination is 4-byte aligned. As BLX instruction may + // only be two byte aligned. This must be done before overflow check + Val = alignTo(Val, 4); + } + // Bit 12 is 0 for BLX, 1 for BL + write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); + // Fall through as rest of encoding is the same as B.W + LLVM_FALLTHROUGH; + case R_ARM_THM_JUMP24: + // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 + // FIXME: Use of I1 and I2 require v6T2ops + checkInt<25>(Loc, Val, Type); + write16le(Loc, + 0xf000 | // opcode + ((Val >> 14) & 0x0400) | // S + ((Val >> 12) & 0x03ff)); // imm10 + write16le(Loc + 2, + (read16le(Loc + 2) & 0xd000) | // opcode + (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 + (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 + ((Val >> 1) & 0x07ff)); // imm11 + break; + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVW_PREL_NC: + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | + (Val & 0x0fff)); + break; + case R_ARM_MOVT_ABS: + case R_ARM_MOVT_PREL: + checkInt<32>(Loc, Val, Type); + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | + (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); + break; + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVT_PREL: + // Encoding T1: A = imm4:i:imm3:imm8 + checkInt<32>(Loc, Val, Type); + write16le(Loc, + 0xf2c0 | // opcode + ((Val >> 17) & 0x0400) | // i + ((Val >> 28) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val >> 12) & 0x7000) | // imm3 + ((Val >> 16) & 0x00ff)); // imm8 + break; + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVW_PREL_NC: + // Encoding T3: A = imm4:i:imm3:imm8 + write16le(Loc, + 0xf240 | // opcode + ((Val >> 1) & 0x0400) | // i + ((Val >> 12) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val << 4) & 0x7000) | // imm3 + (Val & 0x00ff)); // imm8 + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { + switch (Type) { + default: + return 0; + case R_ARM_ABS32: + case R_ARM_BASE_PREL: + case R_ARM_GOTOFF32: + case R_ARM_GOT_BREL: + case R_ARM_GOT_PREL: + case R_ARM_REL32: + case R_ARM_TARGET1: + case R_ARM_TARGET2: + case R_ARM_TLS_GD32: + case R_ARM_TLS_LDM32: + case R_ARM_TLS_LDO32: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LE32: + return SignExtend64<32>(read32le(Buf)); + case R_ARM_PREL31: + return SignExtend64<31>(read32le(Buf)); + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + return SignExtend64<26>(read32le(Buf) << 2); + case R_ARM_THM_JUMP11: + return SignExtend64<12>(read16le(Buf) << 1); + case R_ARM_THM_JUMP19: { + // Encoding T3: A = S:J2:J1:imm10:imm6:0 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<20>(((Hi & 0x0400) << 10) | // S + ((Lo & 0x0800) << 8) | // J2 + ((Lo & 0x2000) << 5) | // J1 + ((Hi & 0x003f) << 12) | // imm6 + ((Lo & 0x07ff) << 1)); // imm11:0 + } + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: { + // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 + // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) + // FIXME: I1 and I2 require v6T2ops + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<24>(((Hi & 0x0400) << 14) | // S + (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 + (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 + ((Hi & 0x003ff) << 12) | // imm0 + ((Lo & 0x007ff) << 1)); // imm11:0 + } + // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and + // MOVT is in the range -32768 <= A < 32768 + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: { + uint64_t Val = read32le(Buf) & 0x000f0fff; + return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); + } + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: { + // Encoding T3: A = imm4:i:imm3:imm8 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 + ((Hi & 0x0400) << 1) | // i + ((Lo & 0x7000) >> 4) | // imm3 + (Lo & 0x00ff)); // imm8 + } + } +} + +TargetInfo *elf::getARMTargetInfo() { + static ARM Target; + return &Target; +} diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp new file mode 100644 index 000000000..3853248f8 --- /dev/null +++ b/ELF/Arch/AVR.cpp @@ -0,0 +1,80 @@ +//===- AVR.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AVR is a Harvard-architecture 8-bit micrcontroller designed for small +// baremetal programs. All AVR-family processors have 32 8-bit registers. +// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest +// one supports up to 2^24 data address space and 2^22 code address space. +// +// Since it is a baremetal programming, there's usually no loader to load +// ELF files on AVRs. You are expected to link your program against address +// 0 and pull out a .text section from the result using objcopy, so that you +// can write the linked code to on-chip flush memory. You can do that with +// the following commands: +// +// ld.lld -Ttext=0 -o foo foo.o +// objcopy -O binary --only-section=.text foo output.bin +// +// Note that the current AVR support is very preliminary so you can't +// link any useful program yet, though. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class AVR final : public TargetInfo { +public: + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_AVR_CALL: + return R_ABS; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_AVR_CALL: { + uint16_t Hi = Val >> 17; + uint16_t Lo = Val >> 1; + write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); + write16le(Loc + 2, Lo); + break; + } + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); + } +} + +TargetInfo *elf::getAVRTargetInfo() { + static AVR Target; + return &Target; +} diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp new file mode 100644 index 000000000..b8d796f58 --- /dev/null +++ b/ELF/Arch/Mips.cpp @@ -0,0 +1,423 @@ +//===- MIPS.cpp -----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "OutputSections.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "Thunks.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +template class MIPS final : public TargetInfo { +public: + MIPS(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + bool isPicRel(uint32_t Type) const override; + uint32_t getDynRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, + const SymbolBody &S) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + bool usesOnlyLowPageBits(uint32_t Type) const override; +}; +} // namespace + +template MIPS::MIPS() { + GotPltHeaderEntriesNum = 2; + DefaultMaxPageSize = 65536; + GotEntrySize = sizeof(typename ELFT::uint); + GotPltEntrySize = sizeof(typename ELFT::uint); + PltEntrySize = 16; + PltHeaderSize = 32; + CopyRel = R_MIPS_COPY; + PltRel = R_MIPS_JUMP_SLOT; + NeedsThunks = true; + TrapInstr = 0xefefefef; + + if (ELFT::Is64Bits) { + RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; + TlsGotRel = R_MIPS_TLS_TPREL64; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; + TlsOffsetRel = R_MIPS_TLS_DTPREL64; + } else { + RelativeRel = R_MIPS_REL32; + TlsGotRel = R_MIPS_TLS_TPREL32; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; + TlsOffsetRel = R_MIPS_TLS_DTPREL32; + } +} + +template +RelExpr MIPS::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + // See comment in the calculateMipsRelChain. + if (ELFT::Is64Bits || Config->MipsN32Abi) + Type &= 0xff; + switch (Type) { + default: + return R_ABS; + case R_MIPS_JALR: + return R_HINT; + case R_MIPS_GPREL16: + case R_MIPS_GPREL32: + return R_MIPS_GOTREL; + case R_MIPS_26: + return R_PLT; + case R_MIPS_HI16: + case R_MIPS_LO16: + // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate + // offset between start of function and 'gp' value which by default + // equal to the start of .got section. In that case we consider these + // relocations as relative. + if (&S == ElfSym::MipsGpDisp) + return R_MIPS_GOT_GP_PC; + if (&S == ElfSym::MipsLocalGp) + return R_MIPS_GOT_GP; + LLVM_FALLTHROUGH; + case R_MIPS_GOT_OFST: + return R_ABS; + case R_MIPS_PC32: + case R_MIPS_PC16: + case R_MIPS_PC19_S2: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: + case R_MIPS_PCHI16: + case R_MIPS_PCLO16: + return R_PC; + case R_MIPS_GOT16: + if (S.isLocal()) + return R_MIPS_GOT_LOCAL_PAGE; + LLVM_FALLTHROUGH; + case R_MIPS_CALL16: + case R_MIPS_GOT_DISP: + case R_MIPS_TLS_GOTTPREL: + return R_MIPS_GOT_OFF; + case R_MIPS_CALL_HI16: + case R_MIPS_CALL_LO16: + case R_MIPS_GOT_HI16: + case R_MIPS_GOT_LO16: + return R_MIPS_GOT_OFF32; + case R_MIPS_GOT_PAGE: + return R_MIPS_GOT_LOCAL_PAGE; + case R_MIPS_TLS_GD: + return R_MIPS_TLSGD; + case R_MIPS_TLS_LDM: + return R_MIPS_TLSLD; + } +} + +template bool MIPS::isPicRel(uint32_t Type) const { + return Type == R_MIPS_32 || Type == R_MIPS_64; +} + +template uint32_t MIPS::getDynRel(uint32_t Type) const { + return RelativeRel; +} + +template +void MIPS::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { + write32(Buf, InX::Plt->getVA()); +} + +template +static int64_t getPcRelocAddend(const uint8_t *Loc) { + uint32_t Instr = read32(Loc); + uint32_t Mask = 0xffffffff >> (32 - BSIZE); + return SignExtend64((Instr & Mask) << SHIFT); +} + +template +static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { + uint32_t Mask = 0xffffffff >> (32 - BSIZE); + uint32_t Instr = read32(Loc); + if (SHIFT > 0) + checkAlignment<(1 << SHIFT)>(Loc, V, Type); + checkInt(Loc, V, Type); + write32(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); +} + +template static void writeMipsHi16(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32(Loc); + uint16_t Res = ((V + 0x8000) >> 16) & 0xffff; + write32(Loc, (Instr & 0xffff0000) | Res); +} + +template static void writeMipsHigher(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32(Loc); + uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff; + write32(Loc, (Instr & 0xffff0000) | Res); +} + +template static void writeMipsHighest(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32(Loc); + uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff; + write32(Loc, (Instr & 0xffff0000) | Res); +} + +template static void writeMipsLo16(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32(Loc); + write32(Loc, (Instr & 0xffff0000) | (V & 0xffff)); +} + +template static bool isMipsR6() { + const auto &FirstObj = cast>(*Config->FirstElf); + uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH; + return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; +} + +template void MIPS::writePltHeader(uint8_t *Buf) const { + const endianness E = ELFT::TargetEndianness; + if (Config->MipsN32Abi) { + write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) + write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) + write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) + write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 + } else { + write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) + write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) + write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) + write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 + } + + write32(Buf + 16, 0x03e07825); // move $15, $31 + write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 + write32(Buf + 24, 0x0320f809); // jalr $25 + write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 + + uint64_t GotPlt = InX::GotPlt->getVA(); + writeMipsHi16(Buf, GotPlt); + writeMipsLo16(Buf + 4, GotPlt); + writeMipsLo16(Buf + 8, GotPlt); +} + +template +void MIPS::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const endianness E = ELFT::TargetEndianness; + write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) + write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) + // jr $25 + write32(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); + write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) + writeMipsHi16(Buf, GotPltEntryAddr); + writeMipsLo16(Buf + 4, GotPltEntryAddr); + writeMipsLo16(Buf + 12, GotPltEntryAddr); +} + +template +bool MIPS::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, + const SymbolBody &S) const { + // Any MIPS PIC code function is invoked with its address in register $t9. + // So if we have a branch instruction from non-PIC code to the PIC one + // we cannot make the jump directly and need to create a small stubs + // to save the target function address. + // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Type != R_MIPS_26) + return false; + auto *F = dyn_cast_or_null>(File); + if (!F) + return false; + // If current file has PIC code, LA25 stub is not required. + if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) + return false; + auto *D = dyn_cast(&S); + // LA25 is required if target file has PIC code + // or target symbol is a PIC symbol. + return D && D->isMipsPIC(); +} + +template +int64_t MIPS::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { + const endianness E = ELFT::TargetEndianness; + switch (Type) { + default: + return 0; + case R_MIPS_32: + case R_MIPS_GPREL32: + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_TPREL32: + return SignExtend64<32>(read32(Buf)); + case R_MIPS_26: + // FIXME (simon): If the relocation target symbol is not a PLT entry + // we should use another expression for calculation: + // ((A << 2) | (P & 0xf0000000)) >> 2 + return SignExtend64<28>((read32(Buf) & 0x3ffffff) << 2); + case R_MIPS_GPREL16: + case R_MIPS_LO16: + case R_MIPS_PCLO16: + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_TPREL_HI16: + case R_MIPS_TLS_TPREL_LO16: + return SignExtend64<16>(read32(Buf)); + case R_MIPS_PC16: + return getPcRelocAddend(Buf); + case R_MIPS_PC19_S2: + return getPcRelocAddend(Buf); + case R_MIPS_PC21_S2: + return getPcRelocAddend(Buf); + case R_MIPS_PC26_S2: + return getPcRelocAddend(Buf); + case R_MIPS_PC32: + return getPcRelocAddend(Buf); + } +} + +static std::pair +calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) { + // MIPS N64 ABI packs multiple relocations into the single relocation + // record. In general, all up to three relocations can have arbitrary + // types. In fact, Clang and GCC uses only a few combinations. For now, + // we support two of them. That is allow to pass at least all LLVM + // test suite cases. + // / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 + // / R_MIPS_64 / R_MIPS_NONE + // The first relocation is a 'real' relocation which is calculated + // using the corresponding symbol's value. The second and the third + // relocations used to modify result of the first one: extend it to + // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation + // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf + uint32_t Type2 = (Type >> 8) & 0xff; + uint32_t Type3 = (Type >> 16) & 0xff; + if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) + return std::make_pair(Type, Val); + if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) + return std::make_pair(Type2, Val); + if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) + return std::make_pair(Type3, -Val); + error(getErrorLocation(Loc) + "unsupported relocations combination " + + Twine(Type)); + return std::make_pair(Type & 0xff, Val); +} + +template +void MIPS::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + const endianness E = ELFT::TargetEndianness; + // Thread pointer and DRP offsets from the start of TLS data area. + // https://www.linux-mips.org/wiki/NPTL + if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || + Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64) + Val -= 0x8000; + else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || + Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64) + Val -= 0x7000; + if (ELFT::Is64Bits || Config->MipsN32Abi) + std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); + switch (Type) { + case R_MIPS_32: + case R_MIPS_GPREL32: + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_TPREL32: + write32(Loc, Val); + break; + case R_MIPS_64: + case R_MIPS_TLS_DTPREL64: + case R_MIPS_TLS_TPREL64: + write64(Loc, Val); + break; + case R_MIPS_26: + write32(Loc, (read32(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff)); + break; + case R_MIPS_GOT16: + // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode + // is updated addend (not a GOT index). In that case write high 16 bits + // to store a correct addend value. + if (Config->Relocatable) + writeMipsHi16(Loc, Val); + else { + checkInt<16>(Loc, Val, Type); + writeMipsLo16(Loc, Val); + } + break; + case R_MIPS_GOT_DISP: + case R_MIPS_GOT_PAGE: + case R_MIPS_GPREL16: + case R_MIPS_TLS_GD: + case R_MIPS_TLS_LDM: + checkInt<16>(Loc, Val, Type); + LLVM_FALLTHROUGH; + case R_MIPS_CALL16: + case R_MIPS_CALL_LO16: + case R_MIPS_GOT_LO16: + case R_MIPS_GOT_OFST: + case R_MIPS_LO16: + case R_MIPS_PCLO16: + case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_GOTTPREL: + case R_MIPS_TLS_TPREL_LO16: + writeMipsLo16(Loc, Val); + break; + case R_MIPS_CALL_HI16: + case R_MIPS_GOT_HI16: + case R_MIPS_HI16: + case R_MIPS_PCHI16: + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_TPREL_HI16: + writeMipsHi16(Loc, Val); + break; + case R_MIPS_HIGHER: + writeMipsHigher(Loc, Val); + break; + case R_MIPS_HIGHEST: + writeMipsHighest(Loc, Val); + break; + case R_MIPS_JALR: + // Ignore this optimization relocation for now + break; + case R_MIPS_PC16: + applyMipsPcReloc(Loc, Type, Val); + break; + case R_MIPS_PC19_S2: + applyMipsPcReloc(Loc, Type, Val); + break; + case R_MIPS_PC21_S2: + applyMipsPcReloc(Loc, Type, Val); + break; + case R_MIPS_PC26_S2: + applyMipsPcReloc(Loc, Type, Val); + break; + case R_MIPS_PC32: + applyMipsPcReloc(Loc, Type, Val); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +template +bool MIPS::usesOnlyLowPageBits(uint32_t Type) const { + return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; +} + +template TargetInfo *elf::getMipsTargetInfo() { + static MIPS Target; + return &Target; +} + +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp new file mode 100644 index 000000000..3d1dc1daf --- /dev/null +++ b/ELF/Arch/MipsArchTree.cpp @@ -0,0 +1,369 @@ +//===- MipsArchTree.cpp --------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file contains a helper function for the Writer. +// +//===---------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "SymbolTable.h" +#include "Writer.h" + +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/MipsABIFlags.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +namespace { +struct ArchTreeEdge { + uint32_t Child; + uint32_t Parent; +}; + +struct FileFlags { + StringRef Filename; + uint32_t Flags; +}; +} // namespace + +static StringRef getAbiName(uint32_t Flags) { + switch (Flags) { + case 0: + return "n64"; + case EF_MIPS_ABI2: + return "n32"; + case EF_MIPS_ABI_O32: + return "o32"; + case EF_MIPS_ABI_O64: + return "o64"; + case EF_MIPS_ABI_EABI32: + return "eabi32"; + case EF_MIPS_ABI_EABI64: + return "eabi64"; + default: + return "unknown"; + } +} + +static StringRef getNanName(bool IsNan2008) { + return IsNan2008 ? "2008" : "legacy"; +} + +static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } + +static void checkFlags(ArrayRef Files) { + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + bool Nan = Files[0].Flags & EF_MIPS_NAN2008; + bool Fp = Files[0].Flags & EF_MIPS_FP64; + + for (const FileFlags &F : Files.slice(1)) { + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + if (ABI != ABI2) + error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + + getAbiName(ABI2) + "': " + F.Filename); + + bool Nan2 = F.Flags & EF_MIPS_NAN2008; + if (Nan != Nan2) + error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + + getNanName(Nan2) + ": " + F.Filename); + + bool Fp2 = F.Flags & EF_MIPS_FP64; + if (Fp != Fp2) + error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + + getFpName(Fp2) + ": " + F.Filename); + } +} + +static uint32_t getMiscFlags(ArrayRef Files) { + uint32_t Ret = 0; + for (const FileFlags &F : Files) + Ret |= F.Flags & + (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | + EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); + return Ret; +} + +static uint32_t getPicFlags(ArrayRef Files) { + // Check PIC/non-PIC compatibility. + bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) { + bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + if (IsPic && !IsPic2) + warn("linking abicalls code with non-abicalls file: " + F.Filename); + if (!IsPic && IsPic2) + warn("linking non-abicalls code with abicalls file: " + F.Filename); + } + + // Compute the result PIC/non-PIC flag. + uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) + Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + + // PIC code is inherently CPIC and may not set CPIC flag explicitly. + if (Ret & EF_MIPS_PIC) + Ret |= EF_MIPS_CPIC; + return Ret; +} + +static ArchTreeEdge ArchTree[] = { + // MIPS32R6 and MIPS64R6 are not compatible with other extensions + // MIPS64R2 extensions. + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, + // MIPS64 extensions. + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, + // MIPS V extensions. + {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, + // R5000 extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, + // MIPS IV extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, + // VR4100 extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + // MIPS III extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, + // MIPS32 extensions. + {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, + // MIPS II extensions. + {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, + {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, + // MIPS I extensions. + {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, + {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, +}; + +static bool isArchMatched(uint32_t New, uint32_t Res) { + if (New == Res) + return true; + if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) + return true; + if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) + return true; + for (const auto &Edge : ArchTree) { + if (Res == Edge.Child) { + Res = Edge.Parent; + if (Res == New) + return true; + } + } + return false; +} + +static StringRef getMachName(uint32_t Flags) { + switch (Flags & EF_MIPS_MACH) { + case EF_MIPS_MACH_NONE: + return ""; + case EF_MIPS_MACH_3900: + return "r3900"; + case EF_MIPS_MACH_4010: + return "r4010"; + case EF_MIPS_MACH_4100: + return "r4100"; + case EF_MIPS_MACH_4650: + return "r4650"; + case EF_MIPS_MACH_4120: + return "r4120"; + case EF_MIPS_MACH_4111: + return "r4111"; + case EF_MIPS_MACH_5400: + return "vr5400"; + case EF_MIPS_MACH_5900: + return "vr5900"; + case EF_MIPS_MACH_5500: + return "vr5500"; + case EF_MIPS_MACH_9000: + return "rm9000"; + case EF_MIPS_MACH_LS2E: + return "loongson2e"; + case EF_MIPS_MACH_LS2F: + return "loongson2f"; + case EF_MIPS_MACH_LS3A: + return "loongson3a"; + case EF_MIPS_MACH_OCTEON: + return "octeon"; + case EF_MIPS_MACH_OCTEON2: + return "octeon2"; + case EF_MIPS_MACH_OCTEON3: + return "octeon3"; + case EF_MIPS_MACH_SB1: + return "sb1"; + case EF_MIPS_MACH_XLR: + return "xlr"; + default: + return "unknown machine"; + } +} + +static StringRef getArchName(uint32_t Flags) { + StringRef S = getMachName(Flags); + if (!S.empty()) + return S; + + switch (Flags & EF_MIPS_ARCH) { + case EF_MIPS_ARCH_1: + return "mips1"; + case EF_MIPS_ARCH_2: + return "mips2"; + case EF_MIPS_ARCH_3: + return "mips3"; + case EF_MIPS_ARCH_4: + return "mips4"; + case EF_MIPS_ARCH_5: + return "mips5"; + case EF_MIPS_ARCH_32: + return "mips32"; + case EF_MIPS_ARCH_64: + return "mips64"; + case EF_MIPS_ARCH_32R2: + return "mips32r2"; + case EF_MIPS_ARCH_64R2: + return "mips64r2"; + case EF_MIPS_ARCH_32R6: + return "mips32r6"; + case EF_MIPS_ARCH_64R6: + return "mips64r6"; + default: + return "unknown arch"; + } +} + +// There are (arguably too) many MIPS ISAs out there. Their relationships +// can be represented as a forest. If all input files have ISAs which +// reachable by repeated proceeding from the single child to the parent, +// these input files are compatible. In that case we need to return "highest" +// ISA. If there are incompatible input files, we show an error. +// For example, mips1 is a "parent" of mips2 and such files are compatible. +// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 +// are incompatible because nor mips3 is a parent for misp32, nor mips32 +// is a parent for mips3. +static uint32_t getArchFlags(ArrayRef Files) { + uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + for (const FileFlags &F : Files.slice(1)) { + uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + // Check ISA compatibility. + if (isArchMatched(New, Ret)) + continue; + if (!isArchMatched(Ret, New)) { + error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + + getArchName(New) + "': " + F.Filename); + return 0; + } + Ret = New; + } + return Ret; +} + +template uint32_t elf::getMipsEFlags() { + std::vector V; + for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) + V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); + if (V.empty()) + return 0; + checkFlags(V); + return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); +} + +static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { + if (FpA == FpB) + return 0; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) + return 1; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && + FpA == Mips::Val_GNU_MIPS_ABI_FP_64) + return 1; + if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) + return -1; + if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) + return 1; + return -1; +} + +static StringRef getMipsFpAbiName(uint8_t FpAbi) { + switch (FpAbi) { + case Mips::Val_GNU_MIPS_ABI_FP_ANY: + return "any"; + case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: + return "-mips32r2 -mfp64 (old)"; + case Mips::Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + case Mips::Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + case Mips::Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + default: + return "unknown"; + } +} + +uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, + StringRef FileName) { + if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) + return NewFlag; + if (compareMipsFpAbi(OldFlag, NewFlag) < 0) + error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + + "' is incompatible with '" + getMipsFpAbiName(NewFlag) + + "': " + FileName); + return OldFlag; +} + +template static bool isN32Abi(const InputFile *F) { + if (auto *EF = dyn_cast>(F)) + return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; + return false; +} + +bool elf::isMipsN32Abi(const InputFile *F) { + switch (Config->EKind) { + case ELF32LEKind: + return isN32Abi(F); + case ELF32BEKind: + return isN32Abi(F); + case ELF64LEKind: + return isN32Abi(F); + case ELF64BEKind: + return isN32Abi(F); + default: + llvm_unreachable("unknown Config->EKind"); + } +} + +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp new file mode 100644 index 000000000..19e10729a --- /dev/null +++ b/ELF/Arch/PPC.cpp @@ -0,0 +1,65 @@ +//===- PPC.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "Symbols.h" +#include "Target.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class PPC final : public TargetInfo { +public: + PPC() { GotBaseSymOff = 0x8000; } + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; +}; +} // namespace + +void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_PPC_ADDR16_HA: + write16be(Loc, (Val + 0x8000) >> 16); + break; + case R_PPC_ADDR16_LO: + write16be(Loc, Val); + break; + case R_PPC_ADDR32: + case R_PPC_REL32: + write32be(Loc, Val); + break; + case R_PPC_REL24: + write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_PPC_REL24: + case R_PPC_REL32: + return R_PC; + default: + return R_ABS; + } +} + +TargetInfo *elf::getPPCTargetInfo() { + static PPC Target; + return &Target; +} diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp new file mode 100644 index 000000000..bf414d75b --- /dev/null +++ b/ELF/Arch/PPC64.cpp @@ -0,0 +1,217 @@ +//===- PPC64.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +static uint64_t PPC64TocOffset = 0x8000; + +uint64_t elf::getPPC64TocBase() { + // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The + // TOC starts where the first of these sections starts. We always create a + // .got when we see a relocation that uses it, so for us the start is always + // the .got. + uint64_t TocVA = InX::Got->getVA(); + + // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 + // thus permitting a full 64 Kbytes segment. Note that the glibc startup + // code (crt1.o) assumes that you can get from the TOC base to the + // start of the .toc section with only a single (signed) 16-bit relocation. + return TocVA + PPC64TocOffset; +} + +namespace { +class PPC64 final : public TargetInfo { +public: + PPC64(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +// Relocation masks following the #lo(value), #hi(value), #ha(value), +// #higher(value), #highera(value), #highest(value), and #highesta(value) +// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi +// document. +static uint16_t applyPPCLo(uint64_t V) { return V; } +static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } +static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } +static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } +static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } +static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } +static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } + +PPC64::PPC64() { + PltRel = GotRel = R_PPC64_GLOB_DAT; + RelativeRel = R_PPC64_RELATIVE; + GotEntrySize = 8; + GotPltEntrySize = 8; + PltEntrySize = 32; + PltHeaderSize = 0; + + // We need 64K pages (at least under glibc/Linux, the loader won't + // set different permissions on a finer granularity than that). + DefaultMaxPageSize = 65536; + + // The PPC64 ELF ABI v1 spec, says: + // + // It is normally desirable to put segments with different characteristics + // in separate 256 Mbyte portions of the address space, to give the + // operating system full paging flexibility in the 64-bit address space. + // + // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers + // use 0x10000000 as the starting address. + DefaultImageBase = 0x10000000; +} + +RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + default: + return R_ABS; + case R_PPC64_TOC16: + case R_PPC64_TOC16_DS: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_HI: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + return R_GOTREL; + case R_PPC64_TOC: + return R_PPC_TOC; + case R_PPC64_REL24: + return R_PPC_PLT_OPD; + } +} + +void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); + + // FIXME: What we should do, in theory, is get the offset of the function + // descriptor in the .opd section, and use that as the offset from %r2 (the + // TOC-base pointer). Instead, we have the GOT-entry offset, and that will + // be a pointer to the function descriptor in the .opd section. Using + // this scheme is simpler, but requires an extra indirection per PLT dispatch. + + write32be(Buf, 0xf8410028); // std %r2, 40(%r1) + write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha + write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) + write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) + write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 + write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) + write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) + write32be(Buf + 28, 0x4e800420); // bctr +} + +static std::pair toAddr16Rel(uint32_t Type, uint64_t Val) { + uint64_t V = Val - PPC64TocOffset; + switch (Type) { + case R_PPC64_TOC16: + return {R_PPC64_ADDR16, V}; + case R_PPC64_TOC16_DS: + return {R_PPC64_ADDR16_DS, V}; + case R_PPC64_TOC16_HA: + return {R_PPC64_ADDR16_HA, V}; + case R_PPC64_TOC16_HI: + return {R_PPC64_ADDR16_HI, V}; + case R_PPC64_TOC16_LO: + return {R_PPC64_ADDR16_LO, V}; + case R_PPC64_TOC16_LO_DS: + return {R_PPC64_ADDR16_LO_DS, V}; + default: + return {Type, Val}; + } +} + +void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // For a TOC-relative relocation, proceed in terms of the corresponding + // ADDR16 relocation type. + std::tie(Type, Val) = toAddr16Rel(Type, Val); + + switch (Type) { + case R_PPC64_ADDR14: { + checkAlignment<4>(Loc, Val, Type); + // Preserve the AA/LK bits in the branch instruction + uint8_t AALK = Loc[3]; + write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); + break; + } + case R_PPC64_ADDR16: + checkInt<16>(Loc, Val, Type); + write16be(Loc, Val); + break; + case R_PPC64_ADDR16_DS: + checkInt<16>(Loc, Val, Type); + write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); + break; + case R_PPC64_ADDR16_HA: + case R_PPC64_REL16_HA: + write16be(Loc, applyPPCHa(Val)); + break; + case R_PPC64_ADDR16_HI: + case R_PPC64_REL16_HI: + write16be(Loc, applyPPCHi(Val)); + break; + case R_PPC64_ADDR16_HIGHER: + write16be(Loc, applyPPCHigher(Val)); + break; + case R_PPC64_ADDR16_HIGHERA: + write16be(Loc, applyPPCHighera(Val)); + break; + case R_PPC64_ADDR16_HIGHEST: + write16be(Loc, applyPPCHighest(Val)); + break; + case R_PPC64_ADDR16_HIGHESTA: + write16be(Loc, applyPPCHighesta(Val)); + break; + case R_PPC64_ADDR16_LO: + write16be(Loc, applyPPCLo(Val)); + break; + case R_PPC64_ADDR16_LO_DS: + case R_PPC64_REL16_LO: + write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); + break; + case R_PPC64_ADDR32: + case R_PPC64_REL32: + checkInt<32>(Loc, Val, Type); + write32be(Loc, Val); + break; + case R_PPC64_ADDR64: + case R_PPC64_REL64: + case R_PPC64_TOC: + write64be(Loc, Val); + break; + case R_PPC64_REL24: { + uint32_t Mask = 0x03FFFFFC; + checkInt<24>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); + break; + } + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +TargetInfo *elf::getPPC64TargetInfo() { + static PPC64 Target; + return &Target; +} diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp new file mode 100644 index 000000000..1f977c1e9 --- /dev/null +++ b/ELF/Arch/SPARCV9.cpp @@ -0,0 +1,149 @@ +//===- SPARCV9.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class SPARCV9 final : public TargetInfo { +public: + SPARCV9(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +SPARCV9::SPARCV9() { + CopyRel = R_SPARC_COPY; + GotRel = R_SPARC_GLOB_DAT; + PltRel = R_SPARC_JMP_SLOT; + RelativeRel = R_SPARC_RELATIVE; + GotEntrySize = 8; + PltEntrySize = 32; + PltHeaderSize = 4 * PltEntrySize; + + PageSize = 8192; + DefaultMaxPageSize = 0x100000; + DefaultImageBase = 0x100000; +} + +RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_SPARC_32: + case R_SPARC_UA32: + case R_SPARC_64: + case R_SPARC_UA64: + return R_ABS; + case R_SPARC_PC10: + case R_SPARC_PC22: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: + return R_PC; + case R_SPARC_GOT10: + return R_GOT_OFF; + case R_SPARC_GOT22: + return R_GOT_OFF; + case R_SPARC_WPLT30: + return R_PLT_PC; + case R_SPARC_NONE: + return R_NONE; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_SPARC_32: + case R_SPARC_UA32: + // V-word32 + checkUInt<32>(Loc, Val, Type); + write32be(Loc, Val); + break; + case R_SPARC_DISP32: + // V-disp32 + checkInt<32>(Loc, Val, Type); + write32be(Loc, Val); + break; + case R_SPARC_WDISP30: + case R_SPARC_WPLT30: + // V-disp30 + checkInt<32>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); + break; + case R_SPARC_22: + // V-imm22 + checkUInt<22>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); + break; + case R_SPARC_GOT22: + case R_SPARC_PC22: + // T-imm22 + write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); + break; + case R_SPARC_WDISP19: + // V-disp19 + checkInt<21>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); + break; + case R_SPARC_GOT10: + case R_SPARC_PC10: + // T-simm10 + write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); + break; + case R_SPARC_64: + case R_SPARC_UA64: + case R_SPARC_GLOB_DAT: + // V-xword64 + write64be(Loc, Val); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t PltData[] = { + 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 + 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00 // nop + }; + memcpy(Buf, PltData, sizeof(PltData)); + + uint64_t Off = PltHeaderSize + Index * PltEntrySize; + relocateOne(Buf, R_SPARC_22, Off); + relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); +} + +TargetInfo *elf::getSPARCV9TargetInfo() { + static SPARCV9 Target; + return &Target; +} diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp new file mode 100644 index 000000000..a1e9bcaf1 --- /dev/null +++ b/ELF/Arch/X86.cpp @@ -0,0 +1,364 @@ +//===- X86.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class X86 final : public TargetInfo { +public: + X86(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + uint32_t getDynRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +X86::X86() { + GotBaseSymOff = -1; + CopyRel = R_386_COPY; + GotRel = R_386_GLOB_DAT; + PltRel = R_386_JUMP_SLOT; + IRelativeRel = R_386_IRELATIVE; + RelativeRel = R_386_RELATIVE; + TlsGotRel = R_386_TLS_TPOFF; + TlsModuleIndexRel = R_386_TLS_DTPMOD32; + TlsOffsetRel = R_386_TLS_DTPOFF32; + GotEntrySize = 4; + GotPltEntrySize = 4; + PltEntrySize = 16; + PltHeaderSize = 16; + TlsGdRelaxSkip = 2; + TrapInstr = 0xcccccccc; // 0xcc = INT3 +} + +RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_386_8: + case R_386_16: + case R_386_32: + case R_386_TLS_LDO_32: + return R_ABS; + case R_386_TLS_GD: + return R_TLSGD; + case R_386_TLS_LDM: + return R_TLSLD; + case R_386_PLT32: + return R_PLT_PC; + case R_386_PC8: + case R_386_PC16: + case R_386_PC32: + return R_PC; + case R_386_GOTPC: + return R_GOTONLY_PC_FROM_END; + case R_386_TLS_IE: + return R_GOT; + case R_386_GOT32: + case R_386_GOT32X: + // These relocations can be calculated in two different ways. + // Usual calculation is G + A - GOT what means an offset in GOT table + // (R_GOT_FROM_END). When instruction pointed by relocation has no base + // register, then relocations can be used when PIC code is disabled. In that + // case calculation is G + A, it resolves to an address of entry in GOT + // (R_GOT) and not an offset. + // + // To check that instruction has no base register we scan ModR/M byte. + // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" + // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ + // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) + if ((Loc[-1] & 0xc7) != 0x5) + return R_GOT_FROM_END; + if (Config->Pic) + error(toString(S.File) + ": relocation " + toString(Type) + " against '" + + S.getName() + + "' without base register can not be used when PIC enabled"); + return R_GOT; + case R_386_TLS_GOTIE: + return R_GOT_FROM_END; + case R_386_GOTOFF: + return R_GOTREL_FROM_END; + case R_386_TLS_LE: + return R_TLS; + case R_386_TLS_LE_32: + return R_NEG_TLS; + case R_386_NONE: + return R_NONE; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +RelExpr X86::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const { + switch (Expr) { + default: + return Expr; + case R_RELAX_TLS_GD_TO_IE: + return R_RELAX_TLS_GD_TO_IE_END; + case R_RELAX_TLS_GD_TO_LE: + return R_RELAX_TLS_GD_TO_LE_NEG; + } +} + +void X86::writeGotPltHeader(uint8_t *Buf) const { + write32le(Buf, InX::Dynamic->getVA()); +} + +void X86::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { + // Entries in .got.plt initially points back to the corresponding + // PLT entries with a fixed offset to skip the first instruction. + write32le(Buf, S.getPltVA() + 6); +} + +void X86::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { + // An x86 entry is the address of the ifunc resolver function. + write32le(Buf, S.getVA()); +} + +uint32_t X86::getDynRel(uint32_t Type) const { + if (Type == R_386_TLS_LE) + return R_386_TLS_TPOFF; + if (Type == R_386_TLS_LE_32) + return R_386_TLS_TPOFF32; + return Type; +} + +void X86::writePltHeader(uint8_t *Buf) const { + if (Config->Pic) { + const uint8_t V[] = { + 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) + 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) + 0x90, 0x90, 0x90, 0x90 // nop + }; + memcpy(Buf, V, sizeof(V)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); + return; + } + + const uint8_t PltData[] = { + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4) + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8) + 0x90, 0x90, 0x90, 0x90 // nop + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint32_t GotPlt = InX::GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); +} + +void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx) + 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset + 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC + }; + memcpy(Buf, Inst, sizeof(Inst)); + + if (Config->Pic) { + // jmp *foo@GOT(%ebx) + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + Buf[1] = 0xa3; + write32le(Buf + 2, GotPltEntryAddr - Ebx); + } else { + // jmp *foo_in_GOT + Buf[1] = 0x25; + write32le(Buf + 2, GotPltEntryAddr); + } + + write32le(Buf + 7, RelOff); + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); +} + +int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { + switch (Type) { + default: + return 0; + case R_386_8: + case R_386_PC8: + return SignExtend64<8>(*Buf); + case R_386_16: + case R_386_PC16: + return SignExtend64<16>(read16le(Buf)); + case R_386_32: + case R_386_GOT32: + case R_386_GOT32X: + case R_386_GOTOFF: + case R_386_GOTPC: + case R_386_PC32: + case R_386_PLT32: + case R_386_TLS_LDO_32: + case R_386_TLS_LE: + return SignExtend64<32>(read32le(Buf)); + } +} + +void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are + // being used for some 16-bit programs such as boot loaders, so + // we want to support them. + switch (Type) { + case R_386_8: + checkUInt<8>(Loc, Val, Type); + *Loc = Val; + break; + case R_386_PC8: + checkInt<8>(Loc, Val, Type); + *Loc = Val; + break; + case R_386_16: + checkUInt<16>(Loc, Val, Type); + write16le(Loc, Val); + break; + case R_386_PC16: + // R_386_PC16 is normally used with 16 bit code. In that situation + // the PC is 16 bits, just like the addend. This means that it can + // point from any 16 bit address to any other if the possibility + // of wrapping is included. + // The only restriction we have to check then is that the destination + // address fits in 16 bits. That is impossible to do here. The problem is + // that we are passed the final value, which already had the + // current location subtracted from it. + // We just check that Val fits in 17 bits. This misses some cases, but + // should have no false positives. + checkInt<17>(Loc, Val, Type); + write16le(Loc, Val); + break; + default: + checkInt<32>(Loc, Val, Type); + write32le(Loc, Val); + } +} + +void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // Convert + // leal x@tlsgd(, %ebx, 1), + // call __tls_get_addr@plt + // to + // movl %gs:0,%eax + // subl $x@ntpoff,%eax + const uint8_t Inst[] = { + 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax + 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax + }; + memcpy(Loc - 3, Inst, sizeof(Inst)); + write32le(Loc + 5, Val); +} + +void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // Convert + // leal x@tlsgd(, %ebx, 1), + // call __tls_get_addr@plt + // to + // movl %gs:0, %eax + // addl x@gotntpoff(%ebx), %eax + const uint8_t Inst[] = { + 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax + 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax + }; + memcpy(Loc - 3, Inst, sizeof(Inst)); + write32le(Loc + 5, Val); +} + +// In some conditions, relocations can be optimized to avoid using GOT. +// This function does that for Initial Exec to Local Exec case. +void X86::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + // Ulrich's document section 6.2 says that @gotntpoff can + // be used with MOVL or ADDL instructions. + // @indntpoff is similar to @gotntpoff, but for use in + // position dependent code. + uint8_t Reg = (Loc[-1] >> 3) & 7; + + if (Type == R_386_TLS_IE) { + if (Loc[-1] == 0xa1) { + // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" + // This case is different from the generic case below because + // this is a 5 byte instruction while below is 6 bytes. + Loc[-1] = 0xb8; + } else if (Loc[-2] == 0x8b) { + // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; + } else { + // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" + Loc[-2] = 0x81; + Loc[-1] = 0xc0 | Reg; + } + } else { + assert(Type == R_386_TLS_GOTIE); + if (Loc[-2] == 0x8b) { + // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; + } else { + // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" + Loc[-2] = 0x8d; + Loc[-1] = 0x80 | (Reg << 3) | Reg; + } + } + write32le(Loc, Val); +} + +void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + if (Type == R_386_TLS_LDO_32) { + write32le(Loc, Val); + return; + } + + // Convert + // leal foo(%reg),%eax + // call ___tls_get_addr + // to + // movl %gs:0,%eax + // nop + // leal 0(%esi,1),%esi + const uint8_t Inst[] = { + 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax + 0x90, // nop + 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi + }; + memcpy(Loc - 2, Inst, sizeof(Inst)); +} + +TargetInfo *elf::getX86TargetInfo() { + static X86 Target; + return &Target; +} diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp new file mode 100644 index 000000000..10179f57e --- /dev/null +++ b/ELF/Arch/X86_64.cpp @@ -0,0 +1,473 @@ +//===- X86_64.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +template class X86_64 final : public TargetInfo { +public: + X86_64(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + bool isPicRel(uint32_t Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxGot(uint8_t *Loc, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + +private: + void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, + uint8_t ModRm) const; +}; +} // namespace + +template X86_64::X86_64() { + GotBaseSymOff = -1; + CopyRel = R_X86_64_COPY; + GotRel = R_X86_64_GLOB_DAT; + PltRel = R_X86_64_JUMP_SLOT; + RelativeRel = R_X86_64_RELATIVE; + IRelativeRel = R_X86_64_IRELATIVE; + TlsGotRel = R_X86_64_TPOFF64; + TlsModuleIndexRel = R_X86_64_DTPMOD64; + TlsOffsetRel = R_X86_64_DTPOFF64; + GotEntrySize = 8; + GotPltEntrySize = 8; + PltEntrySize = 16; + PltHeaderSize = 16; + TlsGdRelaxSkip = 2; + TrapInstr = 0xcccccccc; // 0xcc = INT3 + + // Align to the large page size (known as a superpage or huge page). + // FreeBSD automatically promotes large, superpage-aligned allocations. + DefaultImageBase = 0x200000; +} + +template +RelExpr X86_64::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_X86_64_8: + case R_X86_64_16: + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: + case R_X86_64_DTPOFF32: + case R_X86_64_DTPOFF64: + return R_ABS; + case R_X86_64_TPOFF32: + return R_TLS; + case R_X86_64_TLSLD: + return R_TLSLD_PC; + case R_X86_64_TLSGD: + return R_TLSGD_PC; + case R_X86_64_SIZE32: + case R_X86_64_SIZE64: + return R_SIZE; + case R_X86_64_PLT32: + return R_PLT_PC; + case R_X86_64_PC32: + case R_X86_64_PC64: + return R_PC; + case R_X86_64_GOT32: + case R_X86_64_GOT64: + return R_GOT_FROM_END; + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_GOTTPOFF: + return R_GOT_PC; + case R_X86_64_NONE: + return R_NONE; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +template void X86_64::writeGotPltHeader(uint8_t *Buf) const { + // The first entry holds the value of _DYNAMIC. It is not clear why that is + // required, but it is documented in the psabi and the glibc dynamic linker + // seems to use it (note that this is relevant for linking ld.so, not any + // other program). + write64le(Buf, InX::Dynamic->getVA()); +} + +template +void X86_64::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { + // See comments in X86TargetInfo::writeGotPlt. + write32le(Buf, S.getPltVA() + 6); +} + +template void X86_64::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip) + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip) + 0x0f, 0x1f, 0x40, 0x00 // nop + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 + write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 +} + +template +void X86_64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) + 0x68, 0x00, 0x00, 0x00, 0x00, // pushq + 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] + }; + memcpy(Buf, Inst, sizeof(Inst)); + + write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); + write32le(Buf + 7, Index); + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); +} + +template bool X86_64::isPicRel(uint32_t Type) const { + return Type != R_X86_64_PC32 && Type != R_X86_64_32 && + Type != R_X86_64_TPOFF32; +} + +template +void X86_64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + // mov %fs:0x0,%rax + // lea x@tpoff,%rax + const uint8_t Inst[] = { + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax + 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax + }; + memcpy(Loc - 4, Inst, sizeof(Inst)); + + // The original code used a pc relative relocation and so we have to + // compensate for the -4 in had in the addend. + write32le(Loc + 8, Val + 4); +} + +template +void X86_64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + // mov %fs:0x0,%rax + // addq x@tpoff,%rax + const uint8_t Inst[] = { + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax + 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax + }; + memcpy(Loc - 4, Inst, sizeof(Inst)); + + // Both code sequences are PC relatives, but since we are moving the constant + // forward by 8 bytes we have to subtract the value by 8. + write32le(Loc + 8, Val - 8); +} + +// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to +// R_X86_64_TPOFF32 so that it does not use GOT. +template +void X86_64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + uint8_t *Inst = Loc - 3; + uint8_t Reg = Loc[-1] >> 3; + uint8_t *RegSlot = Loc - 1; + + // Note that ADD with RSP or R12 is converted to ADD instead of LEA + // because LEA with these registers needs 4 bytes to encode and thus + // wouldn't fit the space. + + if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { + // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" + memcpy(Inst, "\x48\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { + // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" + memcpy(Inst, "\x49\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { + // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" + memcpy(Inst, "\x4d\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x48\x03", 2) == 0) { + // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" + memcpy(Inst, "\x48\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { + // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" + memcpy(Inst, "\x49\xc7", 2); + *RegSlot = 0xc0 | Reg; + } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { + // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" + memcpy(Inst, "\x48\xc7", 2); + *RegSlot = 0xc0 | Reg; + } else { + error(getErrorLocation(Loc - 3) + + "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); + } + + // The original code used a PC relative relocation. + // Need to compensate for the -4 it had in the addend. + write32le(Loc, Val + 4); +} + +template +void X86_64::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // leaq bar@tlsld(%rip), %rdi + // callq __tls_get_addr@PLT + // leaq bar@dtpoff(%rax), %rcx + // to + // .word 0x6666 + // .byte 0x66 + // mov %fs:0,%rax + // leaq bar@tpoff(%rax), %rcx + if (Type == R_X86_64_DTPOFF64) { + write64le(Loc, Val); + return; + } + if (Type == R_X86_64_DTPOFF32) { + write32le(Loc, Val); + return; + } + + const uint8_t Inst[] = { + 0x66, 0x66, // .word 0x6666 + 0x66, // .byte 0x66 + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax + }; + memcpy(Loc - 3, Inst, sizeof(Inst)); +} + +template +void X86_64::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + switch (Type) { + case R_X86_64_8: + checkUInt<8>(Loc, Val, Type); + *Loc = Val; + break; + case R_X86_64_16: + checkUInt<16>(Loc, Val, Type); + write16le(Loc, Val); + break; + case R_X86_64_32: + checkUInt<32>(Loc, Val, Type); + write32le(Loc, Val); + break; + case R_X86_64_32S: + case R_X86_64_TPOFF32: + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_PC32: + case R_X86_64_GOTTPOFF: + case R_X86_64_PLT32: + case R_X86_64_TLSGD: + case R_X86_64_TLSLD: + case R_X86_64_DTPOFF32: + case R_X86_64_SIZE32: + checkInt<32>(Loc, Val, Type); + write32le(Loc, Val); + break; + case R_X86_64_64: + case R_X86_64_DTPOFF64: + case R_X86_64_GLOB_DAT: + case R_X86_64_PC64: + case R_X86_64_SIZE64: + case R_X86_64_GOT64: + write64le(Loc, Val); + break; + default: + llvm_unreachable("unexpected relocation"); + } +} + +template +RelExpr X86_64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr RelExpr) const { + if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) + return RelExpr; + const uint8_t Op = Data[-2]; + const uint8_t ModRm = Data[-1]; + + // FIXME: When PIC is disabled and foo is defined locally in the + // lower 32 bit address space, memory operand in mov can be converted into + // immediate operand. Otherwise, mov must be changed to lea. We support only + // latter relaxation at this moment. + if (Op == 0x8b) + return R_RELAX_GOT_PC; + + // Relax call and jmp. + if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) + return R_RELAX_GOT_PC; + + // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. + // If PIC then no relaxation is available. + // We also don't relax test/binop instructions without REX byte, + // they are 32bit operations and not common to have. + assert(Type == R_X86_64_REX_GOTPCRELX); + return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; +} + +// A subset of relaxations can only be applied for no-PIC. This method +// handles such relaxations. Instructions encoding information was taken from: +// "Intel 64 and IA-32 Architectures Software Developer's Manual V2" +// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ +// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) +template +void X86_64::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, + uint8_t ModRm) const { + const uint8_t Rex = Loc[-3]; + // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". + if (Op == 0x85) { + // See "TEST-Logical Compare" (4-428 Vol. 2B), + // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). + + // ModR/M byte has form XX YYY ZZZ, where + // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). + // XX has different meanings: + // 00: The operand's memory address is in reg1. + // 01: The operand's memory address is reg1 + a byte-sized displacement. + // 10: The operand's memory address is reg1 + a word-sized displacement. + // 11: The operand is reg1 itself. + // If an instruction requires only one operand, the unused reg2 field + // holds extra opcode bits rather than a register code + // 0xC0 == 11 000 000 binary. + // 0x38 == 00 111 000 binary. + // We transfer reg2 to reg1 here as operand. + // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. + + // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 + // See "TEST-Logical Compare" (4-428 Vol. 2B). + Loc[-2] = 0xf7; + + // Move R bit to the B bit in REX byte. + // REX byte is encoded as 0100WRXB, where + // 0100 is 4bit fixed pattern. + // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the + // default operand size is used (which is 32-bit for most but not all + // instructions). + // REX.R This 1-bit value is an extension to the MODRM.reg field. + // REX.X This 1-bit value is an extension to the SIB.index field. + // REX.B This 1-bit value is an extension to the MODRM.rm field or the + // SIB.base field. + // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + write32le(Loc, Val); + return; + } + + // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub + // or xor operations. + + // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". + // Logic is close to one for test instruction above, but we also + // write opcode extension here, see below for details. + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. + + // Primary opcode is 0x81, opcode extension is one of: + // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, + // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. + // This value was wrote to MODRM.reg in a line above. + // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), + // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for + // descriptions about each operation. + Loc[-2] = 0x81; + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + write32le(Loc, Val); +} + +template +void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { + const uint8_t Op = Loc[-2]; + const uint8_t ModRm = Loc[-1]; + + // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". + if (Op == 0x8b) { + Loc[-2] = 0x8d; + write32le(Loc, Val); + return; + } + + if (Op != 0xff) { + // We are relaxing a rip relative to an absolute, so compensate + // for the old -4 addend. + assert(!Config->Pic); + relaxGotNoPic(Loc, Val + 4, Op, ModRm); + return; + } + + // Convert call/jmp instructions. + if (ModRm == 0x15) { + // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". + // Instead we convert to "addr32 call foo" where addr32 is an instruction + // prefix. That makes result expression to be a single instruction. + Loc[-2] = 0x67; // addr32 prefix + Loc[-1] = 0xe8; // call + write32le(Loc, Val); + return; + } + + // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". + // jmp doesn't return, so it is fine to use nop here, it is just a stub. + assert(ModRm == 0x25); + Loc[-2] = 0xe9; // jmp + Loc[3] = 0x90; // nop + write32le(Loc - 1, Val + 1); +} + +TargetInfo *elf::getX32TargetInfo() { + static X86_64 Target; + return &Target; +} + +TargetInfo *elf::getX86_64TargetInfo() { + static X86_64 Target; + return &Target; +} diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt new file mode 100644 index 000000000..77243bd49 --- /dev/null +++ b/ELF/CMakeLists.txt @@ -0,0 +1,75 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(ELFOptionsTableGen) + +if(NOT LLD_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_lld_library(lldELF + Arch/AArch64.cpp + Arch/AMDGPU.cpp + Arch/ARM.cpp + Arch/AVR.cpp + Arch/Mips.cpp + Arch/MipsArchTree.cpp + Arch/PPC.cpp + Arch/PPC64.cpp + Arch/SPARCV9.cpp + Arch/X86.cpp + Arch/X86_64.cpp + Driver.cpp + DriverUtils.cpp + EhFrame.cpp + Error.cpp + Filesystem.cpp + GdbIndex.cpp + ICF.cpp + InputFiles.cpp + InputSection.cpp + LTO.cpp + LinkerScript.cpp + MapFile.cpp + MarkLive.cpp + OutputSections.cpp + Relocations.cpp + ScriptLexer.cpp + ScriptParser.cpp + Strings.cpp + SymbolTable.cpp + Symbols.cpp + SyntheticSections.cpp + Target.cpp + Thunks.cpp + Writer.cpp + + LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Analysis + BinaryFormat + BitReader + BitWriter + Codegen + Core + DebugInfoDWARF + Demangle + IPO + Linker + LTO + Object + Option + Passes + MC + Support + Target + TransformUtils + + LINK_LIBS + lldConfig + lldCore + ${LLVM_PTHREAD_LIB} + + DEPENDS + ELFOptionsTableGen + ${tablegen_deps} + ) diff --git a/ELF/Config.h b/ELF/Config.h new file mode 100644 index 000000000..23627dd81 --- /dev/null +++ b/ELF/Config.h @@ -0,0 +1,238 @@ +//===- Config.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_CONFIG_H +#define LLD_ELF_CONFIG_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/CachePruning.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Endian.h" + +#include + +namespace lld { +namespace elf { + +class InputFile; +struct Symbol; + +enum ELFKind { + ELFNoneKind, + ELF32LEKind, + ELF32BEKind, + ELF64LEKind, + ELF64BEKind +}; + +// For --build-id. +enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; + +// For --discard-{all,locals,none}. +enum class DiscardPolicy { Default, All, Locals, None }; + +// For --strip-{all,debug}. +enum class StripPolicy { None, All, Debug }; + +// For --unresolved-symbols. +enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll }; + +// For --sort-section and linkerscript sorting rules. +enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; + +// For --target2 +enum class Target2Policy { Abs, Rel, GotRel }; + +struct SymbolVersion { + llvm::StringRef Name; + bool IsExternCpp; + bool HasWildcard; +}; + +// This struct contains symbols version definition that +// can be found in version script if it is used for link. +struct VersionDefinition { + llvm::StringRef Name; + uint16_t Id = 0; + std::vector Globals; + size_t NameOff = 0; // Offset in the string table +}; + +// Structure for mapping renamed symbols +struct RenamedSymbol { + Symbol *Target; + uint8_t OriginalBinding; +}; + +// This struct contains the global configuration for the linker. +// Most fields are direct mapping from the command line options +// and such fields have the same name as the corresponding options. +// Most fields are initialized by the driver. +struct Configuration { + InputFile *FirstElf = nullptr; + uint8_t OSABI = 0; + llvm::CachePruningPolicy ThinLTOCachePolicy; + llvm::StringMap SectionStartMap; + llvm::StringRef DynamicLinker; + llvm::StringRef Entry; + llvm::StringRef Emulation; + llvm::StringRef Fini; + llvm::StringRef Init; + llvm::StringRef LTOAAPipeline; + llvm::StringRef LTONewPmPasses; + llvm::StringRef MapFile; + llvm::StringRef OutputFile; + llvm::StringRef OptRemarksFilename; + llvm::StringRef SoName; + llvm::StringRef Sysroot; + llvm::StringRef ThinLTOCacheDir; + std::string Rpath; + std::vector VersionDefinitions; + std::vector Argv; + std::vector AuxiliaryList; + std::vector FilterList; + std::vector SearchPaths; + std::vector SymbolOrderingFile; + std::vector Undefined; + std::vector VersionScriptGlobals; + std::vector VersionScriptLocals; + std::vector BuildIdVector; + llvm::MapVector RenamedSymbols; + bool AllowMultipleDefinition; + bool AsNeeded = false; + bool Bsymbolic; + bool BsymbolicFunctions; + bool ColorDiagnostics = false; + bool CompressDebugSections; + bool DefineCommon; + bool Demangle = true; + bool DisableVerify; + bool EhFrameHdr; + bool EmitRelocs; + bool EnableNewDtags; + bool ExportDynamic; + bool FatalWarnings; + bool GcSections; + bool GdbIndex; + bool GnuHash; + bool ICF; + bool MipsN32Abi = false; + bool NoGnuUnique; + bool NoUndefinedVersion; + bool Nostdlib; + bool OFormatBinary; + bool Omagic; + bool OptRemarksWithHotness; + bool Pie; + bool PrintGcSections; + bool Relocatable; + bool SaveTemps; + bool SingleRoRx; + bool Shared; + bool Static = false; + bool SysvHash; + bool Target1Rel; + bool Threads; + bool Trace; + bool Verbose; + bool WarnCommon; + bool WarnMissingEntry; + bool ZCombreloc; + bool ZExecstack; + bool ZNocopyreloc; + bool ZNodelete; + bool ZNodlopen; + bool ZNow; + bool ZOrigin; + bool ZRelro; + bool ZRodynamic; + bool ZText; + bool ExitEarly; + bool ZWxneeded; + DiscardPolicy Discard; + SortSectionPolicy SortSection; + StripPolicy Strip; + UnresolvedPolicy UnresolvedSymbols; + Target2Policy Target2; + BuildIdKind BuildId = BuildIdKind::None; + ELFKind EKind = ELFNoneKind; + uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; + uint16_t EMachine = llvm::ELF::EM_NONE; + uint64_t ErrorLimit = 20; + uint64_t ImageBase; + uint64_t MaxPageSize; + uint64_t ZStackSize; + unsigned LTOPartitions; + unsigned LTOO; + unsigned Optimize; + unsigned ThinLTOJobs; + + // The following config options do not directly correspond to any + // particualr command line options. + + // True if we need to pass through relocations in input files to the + // output file. Usually false because we consume relocations. + bool CopyRelocs; + + // True if the target is ELF64. False if ELF32. + bool Is64; + + // True if the target is little-endian. False if big-endian. + bool IsLE; + + // endianness::little if IsLE is true. endianness::big otherwise. + llvm::support::endianness Endianness; + + // True if the target is the little-endian MIPS64. + // + // The reason why we have this variable only for the MIPS is because + // we use this often. Some ELF headers for MIPS64EL are in a + // mixed-endian (which is horrible and I'd say that's a serious spec + // bug), and we need to know whether we are reading MIPS ELF files or + // not in various places. + // + // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official + // name whatever that means. A fun hypothesis is that "EL" is short for + // little-endian written in the little-endian order, but I don't know + // if that's true.) + bool IsMips64EL; + + // The ELF spec defines two types of relocation table entries, RELA and + // REL. RELA is a triplet of (offset, info, addend) while REL is a + // tuple of (offset, info). Addends for REL are implicit and read from + // the location where the relocations are applied. So, REL is more + // compact than RELA but requires a bit of more work to process. + // + // (From the linker writer's view, this distinction is not necessary. + // If the ELF had chosen whichever and sticked with it, it would have + // been easier to write code to process relocations, but it's too late + // to change the spec.) + // + // Each ABI defines its relocation type. IsRela is true if target + // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A + // few 32-bit ABIs are using RELA too. + bool IsRela; + + // True if we are creating position-independent code. + bool Pic; + + // 4 for ELF32, 8 for ELF64. + int Wordsize; +}; + +// The only instance of Configuration struct. +extern Configuration *Config; + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp new file mode 100644 index 000000000..47a50bb72 --- /dev/null +++ b/ELF/Driver.cpp @@ -0,0 +1,1061 @@ +//===- Driver.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The driver drives the entire linking process. It is responsible for +// parsing command line options and doing whatever it is instructed to do. +// +// One notable thing in the LLD's driver when compared to other linkers is +// that the LLD's driver is agnostic on the host operating system. +// Other linkers usually have implicit default values (such as a dynamic +// linker path or library paths) for each host OS. +// +// I don't think implicit default values are useful because they are +// usually explicitly specified by the compiler driver. They can even +// be harmful when you are doing cross-linking. Therefore, in LLD, we +// simply trust the compiler driver to pass all required options and +// don't try to make effort on our side. +// +//===----------------------------------------------------------------------===// + +#include "Driver.h" +#include "Config.h" +#include "Error.h" +#include "Filesystem.h" +#include "ICF.h" +#include "InputFiles.h" +#include "InputSection.h" +#include "LinkerScript.h" +#include "Memory.h" +#include "OutputSections.h" +#include "ScriptParser.h" +#include "Strings.h" +#include "SymbolTable.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "Threads.h" +#include "Writer.h" +#include "lld/Config/Version.h" +#include "lld/Driver/Driver.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TarWriter.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; +using namespace llvm::sys; + +using namespace lld; +using namespace lld::elf; + +Configuration *elf::Config; +LinkerDriver *elf::Driver; + +BumpPtrAllocator elf::BAlloc; +StringSaver elf::Saver{BAlloc}; +std::vector elf::SpecificAllocBase::Instances; + +static void setConfigs(); + +bool elf::link(ArrayRef Args, bool CanExitEarly, + raw_ostream &Error) { + ErrorCount = 0; + ErrorOS = &Error; + InputSections.clear(); + Tar = nullptr; + + Config = make(); + Driver = make(); + Script = make(); + Config->Argv = {Args.begin(), Args.end()}; + + Driver->main(Args, CanExitEarly); + freeArena(); + return !ErrorCount; +} + +// Parses a linker -m option. +static std::tuple parseEmulation(StringRef Emul) { + uint8_t OSABI = 0; + StringRef S = Emul; + if (S.endswith("_fbsd")) { + S = S.drop_back(5); + OSABI = ELFOSABI_FREEBSD; + } + + std::pair Ret = + StringSwitch>(S) + .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) + .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) + .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) + .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) + .Case("elf32ppc", {ELF32BEKind, EM_PPC}) + .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) + .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) + .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) + .Case("elf_i386", {ELF32LEKind, EM_386}) + .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) + .Default({ELFNoneKind, EM_NONE}); + + if (Ret.first == ELFNoneKind) { + if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") + error("Windows targets are not supported on the ELF frontend: " + Emul); + else + error("unknown emulation: " + Emul); + } + return std::make_tuple(Ret.first, Ret.second, OSABI); +} + +// Returns slices of MB by parsing MB as an archive file. +// Each slice consists of a member file in the archive. +std::vector> static getArchiveMembers( + MemoryBufferRef MB) { + std::unique_ptr File = + check(Archive::create(MB), + MB.getBufferIdentifier() + ": failed to parse archive"); + + std::vector> V; + Error Err = Error::success(); + for (const ErrorOr &COrErr : File->children(Err)) { + Archive::Child C = + check(COrErr, MB.getBufferIdentifier() + + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + check(C.getMemoryBufferRef(), + MB.getBufferIdentifier() + + ": could not get the buffer for a child of the archive"); + V.push_back(std::make_pair(MBRef, C.getChildOffset())); + } + if (Err) + fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + + toString(std::move(Err))); + + // Take ownership of memory buffers created for members of thin archives. + for (std::unique_ptr &MB : File->takeThinBuffers()) + make>(std::move(MB)); + + return V; +} + +// Opens a file and create a file object. Path has to be resolved already. +void LinkerDriver::addFile(StringRef Path, bool WithLOption) { + using namespace sys::fs; + + Optional Buffer = readFile(Path); + if (!Buffer.hasValue()) + return; + MemoryBufferRef MBRef = *Buffer; + + if (InBinary) { + Files.push_back(make(MBRef)); + return; + } + + switch (identify_magic(MBRef.getBuffer())) { + case file_magic::unknown: + readLinkerScript(MBRef); + return; + case file_magic::archive: { + // Handle -whole-archive. + if (InWholeArchive) { + for (const auto &P : getArchiveMembers(MBRef)) + Files.push_back(createObjectFile(P.first, Path, P.second)); + return; + } + + std::unique_ptr File = + check(Archive::create(MBRef), Path + ": failed to parse archive"); + + // If an archive file has no symbol table, it is likely that a user + // is attempting LTO and using a default ar command that doesn't + // understand the LLVM bitcode file. It is a pretty common error, so + // we'll handle it as if it had a symbol table. + if (!File->isEmpty() && !File->hasSymbolTable()) { + for (const auto &P : getArchiveMembers(MBRef)) + Files.push_back(make(P.first, Path, P.second)); + return; + } + + // Handle the regular case. + Files.push_back(make(std::move(File))); + return; + } + case file_magic::elf_shared_object: + if (Config->Relocatable) { + error("attempted static link of dynamic object " + Path); + return; + } + + // DSOs usually have DT_SONAME tags in their ELF headers, and the + // sonames are used to identify DSOs. But if they are missing, + // they are identified by filenames. We don't know whether the new + // file has a DT_SONAME or not because we haven't parsed it yet. + // Here, we set the default soname for the file because we might + // need it later. + // + // If a file was specified by -lfoo, the directory part is not + // significant, as a user did not specify it. This behavior is + // compatible with GNU. + Files.push_back( + createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); + return; + default: + if (InLib) + Files.push_back(make(MBRef, "", 0)); + else + Files.push_back(createObjectFile(MBRef)); + } +} + +// Add a given library by searching it from input search paths. +void LinkerDriver::addLibrary(StringRef Name) { + if (Optional Path = searchLibrary(Name)) + addFile(*Path, /*WithLOption=*/true); + else + error("unable to find library -l" + Name); +} + +// This function is called on startup. We need this for LTO since +// LTO calls LLVM functions to compile bitcode files to native code. +// Technically this can be delayed until we read bitcode files, but +// we don't bother to do lazily because the initialization is fast. +static void initLLVM(opt::InputArgList &Args) { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // Parse and evaluate -mllvm options. + std::vector V; + V.push_back("lld (LLVM option parsing)"); + for (auto *Arg : Args.filtered(OPT_mllvm)) + V.push_back(Arg->getValue()); + cl::ParseCommandLineOptions(V.size(), V.data()); +} + +// Some command line options or some combinations of them are not allowed. +// This function checks for such errors. +static void checkOptions(opt::InputArgList &Args) { + // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup + // table which is a relatively new feature. + if (Config->EMachine == EM_MIPS && Config->GnuHash) + error("the .gnu.hash section is not compatible with the MIPS target."); + + if (Config->Pie && Config->Shared) + error("-shared and -pie may not be used together"); + + if (!Config->Shared && !Config->FilterList.empty()) + error("-F may not be used without -shared"); + + if (!Config->Shared && !Config->AuxiliaryList.empty()) + error("-f may not be used without -shared"); + + if (Config->Relocatable) { + if (Config->Shared) + error("-r and -shared may not be used together"); + if (Config->GcSections) + error("-r and --gc-sections may not be used together"); + if (Config->ICF) + error("-r and --icf may not be used together"); + if (Config->Pie) + error("-r and -pie may not be used together"); + } +} + +static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { + int V = Default; + if (auto *Arg = Args.getLastArg(Key)) { + StringRef S = Arg->getValue(); + if (!to_integer(S, V, 10)) + error(Arg->getSpelling() + ": number expected, but got " + S); + } + return V; +} + +static const char *getReproduceOption(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_reproduce)) + return Arg->getValue(); + return getenv("LLD_REPRODUCE"); +} + +static bool hasZOption(opt::InputArgList &Args, StringRef Key) { + for (auto *Arg : Args.filtered(OPT_z)) + if (Key == Arg->getValue()) + return true; + return false; +} + +static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, + uint64_t Default) { + for (auto *Arg : Args.filtered(OPT_z)) { + std::pair KV = StringRef(Arg->getValue()).split('='); + if (KV.first == Key) { + uint64_t Result = Default; + if (!to_integer(KV.second, Result)) + error("invalid " + Key + ": " + KV.second); + return Result; + } + } + return Default; +} + +void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { + ELFOptTable Parser; + opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + + // Interpret this flag early because error() depends on them. + Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + + // Handle -help + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); + return; + } + + // Handle -v or -version. + // + // A note about "compatible with GNU linkers" message: this is a hack for + // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and + // still the newest version in March 2017) or earlier to recognize LLD as + // a GNU compatible linker. As long as an output for the -v option + // contains "GNU" or "with BFD", they recognize us as GNU-compatible. + // + // This is somewhat ugly hack, but in reality, we had no choice other + // than doing this. Considering the very long release cycle of Libtool, + // it is not easy to improve it to recognize LLD as a GNU compatible + // linker in a timely manner. Even if we can make it, there are still a + // lot of "configure" scripts out there that are generated by old version + // of Libtool. We cannot convince every software developer to migrate to + // the latest version and re-generate scripts. So we have this hack. + if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) + message(getLLDVersion() + " (compatible with GNU linkers)"); + + // ld.bfd always exits after printing out the version string. + // ld.gold proceeds if a given option is -v. Because gold's behavior + // is more permissive than ld.bfd, we chose what gold does here. + if (Args.hasArg(OPT_version)) + return; + + Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); + + if (const char *Path = getReproduceOption(Args)) { + // Note that --reproduce is a debug option so you can ignore it + // if you are trying to understand the whole picture of the code. + Expected> ErrOrWriter = + TarWriter::create(Path, path::stem(Path)); + if (ErrOrWriter) { + Tar = ErrOrWriter->get(); + Tar->append("response.txt", createResponseFile(Args)); + Tar->append("version.txt", getLLDVersion() + "\n"); + make>(std::move(*ErrOrWriter)); + } else { + error(Twine("--reproduce: failed to open ") + Path + ": " + + toString(ErrOrWriter.takeError())); + } + } + + readConfigs(Args); + initLLVM(Args); + createFiles(Args); + inferMachineType(); + setConfigs(); + checkOptions(Args); + if (ErrorCount) + return; + + switch (Config->EKind) { + case ELF32LEKind: + link(Args); + return; + case ELF32BEKind: + link(Args); + return; + case ELF64LEKind: + link(Args); + return; + case ELF64BEKind: + link(Args); + return; + default: + llvm_unreachable("unknown Config->EKind"); + } +} + +static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, + bool Default) { + if (auto *Arg = Args.getLastArg(K1, K2)) + return Arg->getOption().getID() == K1; + return Default; +} + +static std::vector getArgs(opt::InputArgList &Args, int Id) { + std::vector V; + for (auto *Arg : Args.filtered(Id)) + V.push_back(Arg->getValue()); + return V; +} + +static std::string getRpath(opt::InputArgList &Args) { + std::vector V = getArgs(Args, OPT_rpath); + return llvm::join(V.begin(), V.end(), ":"); +} + +// Determines what we should do if there are remaining unresolved +// symbols after the name resolution. +static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { + // -noinhibit-exec or -r imply some default values. + if (Args.hasArg(OPT_noinhibit_exec)) + return UnresolvedPolicy::WarnAll; + if (Args.hasArg(OPT_relocatable)) + return UnresolvedPolicy::IgnoreAll; + + UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols, + OPT_warn_unresolved_symbols, true) + ? UnresolvedPolicy::ReportError + : UnresolvedPolicy::Warn; + + // Process the last of -unresolved-symbols, -no-undefined or -z defs. + for (auto *Arg : llvm::reverse(Args)) { + switch (Arg->getOption().getID()) { + case OPT_unresolved_symbols: { + StringRef S = Arg->getValue(); + if (S == "ignore-all" || S == "ignore-in-object-files") + return UnresolvedPolicy::Ignore; + if (S == "ignore-in-shared-libs" || S == "report-all") + return ErrorOrWarn; + error("unknown --unresolved-symbols value: " + S); + continue; + } + case OPT_no_undefined: + return ErrorOrWarn; + case OPT_z: + if (StringRef(Arg->getValue()) == "defs") + return ErrorOrWarn; + continue; + } + } + + // -shared implies -unresolved-symbols=ignore-all because missing + // symbols are likely to be resolved at runtime using other DSOs. + if (Config->Shared) + return UnresolvedPolicy::Ignore; + return ErrorOrWarn; +} + +static Target2Policy getTarget2(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_target2, "got-rel"); + if (S == "rel") + return Target2Policy::Rel; + if (S == "abs") + return Target2Policy::Abs; + if (S == "got-rel") + return Target2Policy::GotRel; + error("unknown --target2 option: " + S); + return Target2Policy::GotRel; +} + +static bool isOutputFormatBinary(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_oformat)) { + StringRef S = Arg->getValue(); + if (S == "binary") + return true; + error("unknown --oformat value: " + S); + } + return false; +} + +static DiscardPolicy getDiscard(opt::InputArgList &Args) { + if (Args.hasArg(OPT_relocatable)) + return DiscardPolicy::None; + + auto *Arg = + Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); + if (!Arg) + return DiscardPolicy::Default; + if (Arg->getOption().getID() == OPT_discard_all) + return DiscardPolicy::All; + if (Arg->getOption().getID() == OPT_discard_locals) + return DiscardPolicy::Locals; + return DiscardPolicy::None; +} + +static StringRef getDynamicLinker(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); + if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) + return ""; + return Arg->getValue(); +} + +static StripPolicy getStrip(opt::InputArgList &Args) { + if (Args.hasArg(OPT_relocatable)) + return StripPolicy::None; + + auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); + if (!Arg) + return StripPolicy::None; + if (Arg->getOption().getID() == OPT_strip_all) + return StripPolicy::All; + return StripPolicy::Debug; +} + +static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { + uint64_t VA = 0; + if (S.startswith("0x")) + S = S.drop_front(2); + if (!to_integer(S, VA, 16)) + error("invalid argument: " + toString(Arg)); + return VA; +} + +static StringMap getSectionStartMap(opt::InputArgList &Args) { + StringMap Ret; + for (auto *Arg : Args.filtered(OPT_section_start)) { + StringRef Name; + StringRef Addr; + std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); + Ret[Name] = parseSectionAddress(Addr, Arg); + } + + if (auto *Arg = Args.getLastArg(OPT_Ttext)) + Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tdata)) + Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tbss)) + Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); + return Ret; +} + +static SortSectionPolicy getSortSection(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_sort_section); + if (S == "alignment") + return SortSectionPolicy::Alignment; + if (S == "name") + return SortSectionPolicy::Name; + if (!S.empty()) + error("unknown --sort-section rule: " + S); + return SortSectionPolicy::Default; +} + +static std::pair getHashStyle(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv"); + if (S == "sysv") + return {true, false}; + if (S == "gnu") + return {false, true}; + if (S != "both") + error("unknown -hash-style: " + S); + return {true, true}; +} + +// Parse --build-id or --build-id= +{% endblock %} + +{% block rootrellink %} +
  • lld Home | 
  • +{% endblock %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..410b33e98 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# +# lld documentation build configuration file. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +from datetime import date + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'lld' +copyright = u'2011-%d, LLVM Project' % date.today().year + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short version. +version = '5' +# The full version, including alpha/beta/rc tags. +release = '5' + +# 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 000000000..1e111f979 --- /dev/null +++ b/docs/design.rst @@ -0,0 +1,421 @@ +.. _design: + +Linker Design +============= + +Note: this document discuss Mach-O port of LLD. For ELF and COFF, +see :doc:`index`. + +Introduction +------------ + +lld is a new generation of linker. It is not "section" based like traditional +linkers which mostly just interlace sections from multiple object files into the +output file. Instead, lld is based on "Atoms". Traditional section based +linking work well for simple linking, but their model makes advanced linking +features difficult to implement. Features like dead code stripping, reordering +functions for locality, and C++ coalescing require the linker to work at a finer +grain. + +An atom is an indivisible chunk of code or data. An atom has a set of +attributes, such as: name, scope, content-type, alignment, etc. An atom also +has a list of References. A Reference contains: a kind, an optional offset, an +optional addend, and an optional target atom. + +The Atom model allows the linker to use standard graph theory models for linking +data structures. Each atom is a node, and each Reference is an edge. The +feature of dead code stripping is implemented by following edges to mark all +live atoms, and then delete the non-live atoms. + + +Atom Model +---------- + +An atom is an indivisible chunk of code or data. Typically each user written +function or global variable is an atom. In addition, the compiler may emit +other atoms, such as for literal c-strings or floating point constants, or for +runtime data structures like dwarf unwind info or pointers to initializers. + +A simple "hello world" object file would be modeled like this: + +.. image:: hello.png + +There are three atoms: main, a proxy for printf, and an anonymous atom +containing the c-string literal "hello world". The Atom "main" has two +references. One is the call site for the call to printf, and the other is a +reference for the instruction that loads the address of the c-string literal. + +There are only four different types of atoms: + + * DefinedAtom + 95% of all atoms. This is a chunk of code or data + + * UndefinedAtom + This is a place holder in object files for a reference to some atom + outside the translation unit.During core linking it is usually replaced + by (coalesced into) another Atom. + + * SharedLibraryAtom + If a required symbol name turns out to be defined in a dynamic shared + library (and not some object file). A SharedLibraryAtom is the + placeholder Atom used to represent that fact. + + It is similar to an UndefinedAtom, but it also tracks information + about the associated shared library. + + * AbsoluteAtom + This is for embedded support where some stuff is implemented in ROM at + some fixed address. This atom has no content. It is just an address + that the Writer needs to fix up any references to point to. + + +File Model +---------- + +The linker views the input files as basically containers of Atoms and +References, and just a few attributes of their own. The linker works with three +kinds of files: object files, static libraries, and dynamic shared libraries. +Each kind of file has reader object which presents the file in the model +expected by the linker. + +Object File +~~~~~~~~~~~ + +An object file is just a container of atoms. When linking an object file, a +reader is instantiated which parses the object file and instantiates a set of +atoms representing all content in the .o file. The linker adds all those atoms +to a master graph. + +Static Library (Archive) +~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the traditional unix static archive which is just a collection of object +files with a "table of contents". When linking with a static library, by default +nothing is added to the master graph of atoms. Instead, if after merging all +atoms from object files into a master graph, if any "undefined" atoms are left +remaining in the master graph, the linker reads the table of contents for each +static library to see if any have the needed definitions. If so, the set of +atoms from the specified object file in the static library is added to the +master graph of atoms. + +Dynamic Library (Shared Object) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dynamic libraries are different than object files and static libraries in that +they don't directly add any content. Their purpose is to check at build time +that the remaining undefined references can be resolved at runtime, and provide +a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way +this is modeled in the linker is that a dynamic library contributes no atoms to +the initial graph of atoms. Instead, (like static libraries) if there are +"undefined" atoms in the master graph of all atoms, then each dynamic library is +checked to see if exports the required symbol. If so, a "shared library" atom is +instantiated by the by the reader which the linker uses to replace the +"undefined" atom. + +Linking Steps +------------- + +Through the use of abstract Atoms, the core of linking is architecture +independent and file format independent. All command line parsing is factored +out into a separate "options" abstraction which enables the linker to be driven +with different command line sets. + +The overall steps in linking are: + + #. Command line processing + + #. Parsing input files + + #. Resolving + + #. Passes/Optimizations + + #. Generate output file + +The Resolving and Passes steps are done purely on the master graph of atoms, so +they have no notion of file formats such as mach-o or ELF. + + +Input Files +~~~~~~~~~~~ + +Existing developer tools using different file formats for object files. +A goal of lld is to be file format independent. This is done +through a plug-in model for reading object files. The lld::Reader is the base +class for all object file readers. A Reader follows the factory method pattern. +A Reader instantiates an lld::File object (which is a graph of Atoms) from a +given object file (on disk or in-memory). + +Every Reader subclass defines its own "options" class (for instance the mach-o +Reader defines the class ReaderOptionsMachO). This options class is the +one-and-only way to control how the Reader operates when parsing an input file +into an Atom graph. For instance, you may want the Reader to only accept +certain architectures. The options class can be instantiated from command +line options, or it can be subclassed and the ivars programmatically set. + +Resolving +~~~~~~~~~ + +The resolving step takes all the atoms' graphs from each object file and +combines them into one master object graph. Unfortunately, it is not as simple +as appending the atom list from each file into one big list. There are many +cases where atoms need to be coalesced. That is, two or more atoms need to be +coalesced into one atom. This is necessary to support: C language "tentative +definitions", C++ weak symbols for templates and inlines defined in headers, +replacing undefined atoms with actual definition atoms, and for merging copies +of constants like c-strings and floating point constants. + +The linker support coalescing by-name and by-content. By-name is used for +tentative definitions and weak symbols. By-content is used for constant data +that can be merged. + +The resolving process maintains some global linking "state", including a "symbol +table" which is a map from llvm::StringRef to lld::Atom*. With these data +structures, the linker iterates all atoms in all input files. For each atom, it +checks if the atom is named and has a global or hidden scope. If so, the atom +is added to the symbol table map. If there already is a matching atom in that +table, that means the current atom needs to be coalesced with the found atom, or +it is a multiple definition error. + +When all initial input file atoms have been processed by the resolver, a scan is +made to see if there are any undefined atoms in the graph. If there are, the +linker scans all libraries (both static and dynamic) looking for definitions to +replace the undefined atoms. It is an error if any undefined atoms are left +remaining. + +Dead code stripping (if requested) is done at the end of resolving. The linker +does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main +executable) and follows each references and marks each Atom that it visits as +"live". When done, all atoms not marked "live" are removed. + +The result of the Resolving phase is the creation of an lld::File object. The +goal is that the lld::File model is **the** internal representation +throughout the linker. The file readers parse (mach-o, ELF, COFF) into an +lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce +their file kind, and every Pass only operates on an lld::File. This is not only +a simpler, consistent model, but it enables the state of the linker to be dumped +at any point in the link for testing purposes. + + +Passes +~~~~~~ + +The Passes step is an open ended set of routines that each get a change to +modify or enhance the current lld::File object. Some example Passes are: + + * stub (PLT) generation + + * GOT instantiation + + * order_file optimization + + * branch island generation + + * branch shim generation + + * Objective-C optimizations (Darwin specific) + + * TLV instantiation (Darwin specific) + + * DTrace probe processing (Darwin specific) + + * compact unwind encoding (Darwin specific) + + +Some of these passes are specific to Darwin's runtime environments. But many of +the passes are applicable to any OS (such as generating branch island for out of +range branch instructions). + +The general structure of a pass is to iterate through the atoms in the current +lld::File object, inspecting each atom and doing something. For instance, the +stub pass, looks for call sites to shared library atoms (e.g. call to printf). +It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for +each proxy atom needed, and these new atoms are added to the current lld::File +object. Next, all the noted call sites to shared library atoms have their +References altered to point to the stub atom instead of the shared library atom. + + +Generate Output File +~~~~~~~~~~~~~~~~~~~~ + +Once the passes are done, the output file writer is given current lld::File +object. The writer's job is to create the executable content file wrapper and +place the content of the atoms into it. + +lld uses a plug-in model for writing output files. All concrete writers (e.g. +ELF, mach-o, etc) are subclasses of the lld::Writer class. + +Unlike the Reader class which has just one method to instantiate an lld::File, +the Writer class has multiple methods. The crucial method is to generate the +output file, but there are also methods which allow the Writer to contribute +Atoms to the resolver and specify passes to run. + +An example of contributing +atoms is that if the Writer knows a main executable is being linked and such +an executable requires a specially named entry point (e.g. "_main"), the Writer +can add an UndefinedAtom with that special name to the resolver. This will +cause the resolver to issue an error if that symbol is not defined. + +Sometimes a Writer supports lazily created symbols, such as names for the start +of sections. To support this, the Writer can create a File object which vends +no initial atoms, but does lazily supply atoms by name as needed. + +Every Writer subclass defines its own "options" class (for instance the mach-o +Writer defines the class WriterOptionsMachO). This options class is the +one-and-only way to control how the Writer operates when producing an output +file from an Atom graph. For instance, you may want the Writer to optimize +the output for certain OS versions, or strip local symbols, etc. The options +class can be instantiated from command line options, or it can be subclassed +and the ivars programmatically set. + + +lld::File representations +------------------------- + +Just as LLVM has three representations of its IR model, lld has two +representations of its File/Atom/Reference model: + + * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File). + + * textual (in YAML) + + +Textual representations in YAML +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In designing a textual format we want something easy for humans to read and easy +for the linker to parse. Since an atom has lots of attributes most of which are +usually just the default, we should define default values for every attribute so +that those can be omitted from the text representation. Here is the atoms for a +simple hello world program expressed in YAML:: + + target-triple: x86_64-apple-darwin11 + + atoms: + - name: _main + scope: global + type: code + content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00, + 00, 00, 31, c0, 5d, c3 ] + fixups: + - offset: 07 + kind: pcrel32 + target: 2 + - offset: 0E + kind: call32 + target: _fprintf + + - type: c-string + content: [ 73, 5A, 00 ] + + ... + +The biggest use for the textual format will be writing test cases. Writing test +cases in C is problematic because the compiler may vary its output over time for +its own optimization reasons which my inadvertently disable or break the linker +feature trying to be tested. By writing test cases in the linkers own textual +format, we can exactly specify every attribute of every atom and thus target +specific linker logic. + +The textual/YAML format follows the ReaderWriter patterns used in lld. The lld +library comes with the classes: ReaderYAML and WriterYAML. + + +Testing +------- + +The lld project contains a test suite which is being built up as new code is +added to lld. All new lld functionality should have a tests added to the test +suite. The test suite is `lit `_ driven. Each +test is a text file with comments telling lit how to run the test and check the +result To facilitate testing, the lld project builds a tool called lld-core. +This tool reads a YAML file (default from stdin), parses it into one or more +lld::File objects in memory and then feeds those lld::File objects to the +resolver phase. + + +Resolver testing +~~~~~~~~~~~~~~~~ + +Basic testing is the "core linking" or resolving phase. That is where the +linker merges object files. All test cases are written in YAML. One feature of +YAML is that it allows multiple "documents" to be encoding in one YAML stream. +That means one text file can appear to the linker as multiple .o files - the +normal case for the linker. + +Here is a simple example of a core linking test case. It checks that an +undefined atom from one file will be replaced by a definition from another +file:: + + # RUN: lld-core %s | FileCheck %s + + # + # Test that undefined atoms are replaced with defined atoms. + # + + --- + atoms: + - name: foo + definition: undefined + --- + atoms: + - name: foo + scope: global + type: code + ... + + # CHECK: name: foo + # CHECK: scope: global + # CHECK: type: code + # CHECK-NOT: name: foo + # CHECK: ... + + +Passes testing +~~~~~~~~~~~~~~ + +Since Passes just operate on an lld::File object, the lld-core tool has the +option to run a particular pass (after resolving). Thus, you can write a YAML +test case with carefully crafted input to exercise areas of a Pass and the check +the resulting lld::File object as represented in YAML. + + +Design Issues +------------- + +There are a number of open issues in the design of lld. The plan is to wait and +make these design decisions when we need to. + + +Debug Info +~~~~~~~~~~ + +Currently, the lld model says nothing about debug info. But the most popular +debug format is DWARF and there is some impedance mismatch with the lld model +and DWARF. In lld there are just Atoms and only Atoms that need to be in a +special section at runtime have an associated section. Also, Atoms do not have +addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go +into specially named sections and the DWARF references function code by address. + +CPU and OS specific functionality +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Currently, lld has an abstract "Platform" that deals with any CPU or OS specific +differences in linking. We just keep adding virtual methods to the base +Platform class as we find linking areas that might need customization. At some +point we'll need to structure this better. + + +File Attributes +~~~~~~~~~~~~~~~ + +Currently, lld::File just has a path and a way to iterate its atoms. We will +need to add more attributes on a File. For example, some equivalent to the +target triple. There is also a number of cached or computed attributes that +could make various Passes more efficient. For instance, on Darwin there are a +number of Objective-C optimizations that can be done by a Pass. But it would +improve the plain C case if the Objective-C optimization Pass did not have to +scan all atoms looking for any Objective-C data structures. This could be done +if the lld::File object had an attribute that said if the file had any +Objective-C data in it. The Resolving phase would then be required to "merge" +that attribute as object files are added. diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 000000000..ce91341d6 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,45 @@ +.. _development: + +Development +=========== + +Note: this document discuss Mach-O port of LLD. For ELF and COFF, +see :doc:`index`. + +lld is developed as part of the `LLVM `_ project. + +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: + + Readers + Driver diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 000000000..97c3d1bcc --- /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 check-lld + +Using Visual Studio +~~~~~~~~~~~~~~~~~~~ + +#. Get the required tools. + + * `CMake 2.8`_\+. + * `Visual Studio 12 (2013) or later`_ (required for C++11 support) + * `Python 2.4`_\+ (not 3.x) for running tests. + +.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html +.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us +.. _Python 2.4: http://python.org/download/ + +#. Check out LLVM:: + + $ cd path/to/llvm-project + $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm + +#. Check out lld:: + + $ cd llvm/tools + $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld + + * lld can also be checked out to ``path/to/llvm-project`` and built as an external + project. + +#. Generate Visual Studio project files:: + + $ cd path/to/llvm-build/llvm (out of source build required) + $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm + +#. Build + + * Open LLVM.sln in Visual Studio. + * Build the ``ALL_BUILD`` target. + +#. Test + + * Build the ``lld-test`` target. + +More Information +~~~~~~~~~~~~~~~~ + +For more information on using CMake see the `LLVM CMake guide`_. + +.. _LLVM CMake guide: http://llvm.org/docs/CMake.html diff --git a/docs/hello.png b/docs/hello.png new file mode 100644 index 0000000000000000000000000000000000000000..70df111f1abd151f2a0ffe133bb6d00b4467d73e GIT binary patch literal 27616 zcmdqIW1D0_*CkxG)n%j0=(26wwrzE}x@_CFyKLLGZNJ&~^Ugi)|naU#!- zvtwhe72)!-V(>87FhD>+@Dk#}iaDlb^XCl4pxEKpQ+~U&@$#3w(1y<=mTJzY$-eAYi_mcMmswOmy^+b(kW0ga@r zfC!+_fb%o)$zUEFj;SLfkM_U=L;VE8&ILhbrBK;H!90QdS}KN&H6OUb33vLmS@Fxs zbu?1s0OJ2W;>^sJln{AC79@iEn*koE6=gU3(E=n$K^&Ax&^Qq48pCM=Bqf5w^Y`@h za1dA<5#uG$&Zu=W0|JmD;+~nY{a!3CDRLjVH(d-OP}=WW5{m3e5q21Z{(}P-!znR! zwl{i@y{|rN*N5j!Yu61o-4_gFvO7aJ-EzY4PKU2uzg04dB9d>bt-`qM2{}#jYIuAL zRPE-DYhu{=BP-VHnB7na`nT8FaS#j+)f247kpSl9ZhQTae7;{>Hmk(Lg`VEi2|Z89 z%htTz3_L%ba(l3bp@grx*UO-kOk|=QS7!!wSLRxxqVE&tpyh{%@!$&Tsn+@r6DyJ(^70B8t zj*F0Y?fZ|B70Ap72+-O?4)3I!_~|pSeNkuv-Gur`C;^bb zE&(@izdqbw5Ml;+QzEE70kkj(N`A{&R%4(v0oGWO1K?Ky0eLVq@Ie9ZpLk;du7V!& zM9MH({^fZ&d8Q|v3(${(F}cX*D4vi$Aqosw$-hrG@s)H?E%A?w;jy~d(+=mY+EcQSLDPF6Gjxv$iJ?? zmVuhVA@wm8SDNt%tr*`4bv_2GU)rcnoijPSX~@%vq!xNbX2tsg*&44IeLVtiP{AA}$Jb|}H{G)f`V z8W@)#&~K>~@t=gsD4I~uP)0!-#7QHhoJc}p&;yqPD2BARqu158*U2OB5Y(YH{IlP63r50P?({O zpp(JW3@e1wgad_h25=+-3Y!Zf4zNe1M-4|K;-5+Nq>u}p3pWZ^6txP+3e$@qii%5_ z%PCp>)1@a%vh!RODGD9tIOp)^v`?*16Xw_o#VmfNlTSts4Z+@Q_RAi{5S!9n0BOcq;q6+^g6ISd^<2b zNIJ+mG&*oPJU@6pY4f1+ll;#Lu+KBJ~n)2?w>zAfIfBEur{B8yh6o&zr$ z9;>bIa*VwrKTH_Y8B?Mvr_!YYN$RI!Q`W7RQ^`_6RgO@uDVHsuUBF#*w-m8lUeIMS z#-fWP6@@OyB2rXSeO8rIlLnlJs;n`l;_nl^!b6iX+vEWswyBKZ6pUv*lPUg0`S zH-@*;u8g2Yuh?%Ih_#k!2Md?+gk=D84f_tB8V)jQM3hbxOO!>FWXRcwZy#?cYRE3x zoHks$-cMpU-i|z(T!K7_Tu!=3#z)#MwK=ux*F4*PYEl{xLrJPvx*dxhlb@A=KC+R+ z!d@QPG~E%bhImA-=!A5Zn-G7I#K=S26;D z)q)^^al;!!6oY-$<92Y{d#v955GWSV5Wwqg+-d4H3n&rN7J?DX4mt}d4s8yW2&sap zK*)f0L!^fz(5*8bJVJLPK_hWTmWgW}sU1;@Q=;Zk#n1^uGTT-Dj5F>HT`W58q3JGp;=Gz0Wvaw>&L&D32xKOm)Am!o!Wd(A(?k<*ZGz^nJ%}@iuaN4f zH=Ji{-06pj4+~UJR5K;5WY49i%D73o3_0uH&BAsT>*Z}MUgs;UH8v$Js4Wz>-!7q} z(S3LXt|8afqpG7@$vkg?%ZMx-C>(v6y*f`F(U+pvN0(PyMqS4@*>-Ik8(bdb9)liw zcO0*7zRaI>2g7ZhbzU8?l`zp){a5?fI4jqU-_Ar$3=Q@V{@=eth(#4_XF~(65M42} z&8ZY3^8BNOPU`l+~l>tD;>68FmfD(O|csPvZv%C@L!sj1~C@G8lJE*CCK zXY05$A7{R|6>Ao(p}IV@|GnSwetS*f6Z_=0?|l|r7s-fdN@=7|TAn|1!pRMZg3lj% z8QLulE8a5AIcmmuPkz&j^ebzx^liKNbCDEKF;KCpc3f?un_-FG*wuya=F@0nvz~xM zZOd)0x3%Rn|9o_*mEB_N-0G~|acTeVSfXQgkC(v}a5|q_-*-W<F`*0`^LhXQvst1gcLtAod! zQ~mMbSc*{%SdFRP@kiiW%pF_19o^^dhggbvu=z#R&E-bN$1}`z1+Tidc?L|TCuS%Bj?OpubJ0P?)^f64*LKKJ{P7W(HIbJtY;G)mbQJiG4mwaG zlrR_JTguP6T)$(IT=2>0TJ?_U^XKma@F;EqJ8=G_UqE^5KsQ$4J3r?dk;zF4)FDFH zL02|Dyo9(7rJ`8$kj#)Y!o(9|oSd#zfO?vMZdBOW*u0EwudK-O=Lvvk((7|O1}kb6 zfpCYz%M!|{@V_R%priK=8b^bKlK~Ydw7s~76A%zA>c1~AP2BFJsYn7q;awEKos-hND z6ZTv;1k0!jDnYMFf@Z?PPwYn2@xl~gqIklfbbjJrJ#bTvAAZLd2gXcJrbiPV(z@Ha z)D&hE#%LpPYM});6S9U;X}lyJ)Wtfrx%VDErPSB z;NV~hk@jt=Z0C7CWI}8vVY*CP`$Ghi)@@A1gV^cBdxYu@V8rJPB1E}v2!C^Nvs-`L z*!}MBPrE6u57D<#9uM3sSp2nBmjt=xZ#$oJt=4@tUr=}ZUyTB1-BlFWb4sizkN$40 zRu&c>uZJnyzVDZ)6tbDTK5u&8ZzIX`5_kY@bF-N(0RX|mJors3u0*h{42kCAcJ)p%8zMWpl2(@MzJ;M;U?D2=lAt7 zS0rUNks6nkg-1ZZ=j?D=klfPLRHe~STwj0pa=Wjl?I6;6l8f6bK*S_V!Rhs6?d0Sn zEj=+1j{07D3R+5~@bLF9H=bh&%>r?)L4SxG@9RMn+ZGV2 zj_>Q?4sl>A6wI}q?|lZ_w)g$PXhH&o+}GQAje?1@e<*=3rbtEA7m}n{AX8P}(@w5k z*DE;*31~m#9%0ppr7R+Hs&w&jj^EaY}H#9Y|@rouM7Kt9m9kj61g=7C|u6Z?~MJ@4DW%a-k}l@)O##;TFCIQ)W! zGNqE_q$HViW=bX|6ix+UVXy__33V%i^v?S!uIFvP?|hMn9^qvjw=6fG61kkOMK!%V zgqgm-LZf1W{*6S?Ff434gx<*e(m~He<|j#Nx^2%}Ug3cYxfcA`P4SCq80E^1+| zBZMrA;Co38KJQPD=gWaRxnQG?NKAa*FANKHdS7=b<*?Yq(BUDCFzLUL(TJTVBYw~u zYC12Lt7!fzdUzwUf8KOcQ&S5JA;cSjir-@{Y!6Z@k@dOu+U{3t6ADGx^uC|`y7#zj zT4rD!_}lbtF2tQ^E^Y-Gt4t&-lv)_{Rl}krSwjGV1R2(E+ajbE9Qgu=oGPvZjcGfb z!Djb*cL?~X7o#yGC=`hDyzB&WaBu({Asj+6vlU9bolKrAxlitycC+({7j4jG{}+|iog+;&;kQBMzA1o~~{ zHr(UJ?9KarH%@kZNGrT_bL`y2jGVC?tFY{3s2b^n90acoP*@DOH+OgEDU$6Cak{G~)Z zGFCWXUPjWWk$}V8{Cr{>kiLQKy}<~T1!RJS9z7})gg8=Rp>!}>3n6VHLHgzYxdBlH z>Mq~{E%|A~X`1J5gyf%p-L6U*pv0Juj*eo^tc=XqeWF1jtaW<1$;eCsHtDCZ5@wKGscD0T!9gBIl(~4tz@YA?i-6d2x=y#8 zUo{;C4NXbI_VRo|z?I?NGd?o6@7LFJHzcHhpMPOuuxZSfz7lx5o%EP z!eF5IFZ}{hT_-IGtO#uL$6*{0!@Z_tTW=N+u!m5-4`5to+YNR-hk(aW$zXcST6z*8 z0=pA&oVy`mIRY`I)AonVz0UPIPcj;74~v3Q(N@g}w@Or>zB#9-mI8h?rKxrouBU^_ z3@i**r`N9X=ZF@1v7oeb$8>8$A6(jZ;hfq7mqAFaHZ_&2rOHn+78N%6w&vpU%W(yY zJXJ5M^q_Q2xrNV9Fk5V?mYVfCHVPgMDCzC_gBj(xuY{MflI*@@ix;|L63E*ngLs^X z+IKmrcLkY3HjYiO2%uu_I(KX?ou=ky-=|eG0>2Lj5fO0V^X!;KVq1>HLwOZ+@%!R905218jm;HXqsZ}g9809E9l5<(K0J=` zeIW6EUnZ*%NQQEc>L#2@s`dP|HJ#dIrjCyqVXbmw5Hng0u~c<*K8}}&vtIh8u|5Vv zjjdWZ-P(OI_xXDa0f`Rnyg_@2IDTw=qQNc)8E4DafZQlFXa%`H2=8kdpy_;)r1{FrlW?m|fsPKz`> z(^F4WT|j8-cM>|=?!^Yq`F?*NalWX`cw=oiNpL7OFo~G(-Voi;ejN$1SbyktO(rfG zTy!7GuU)4&F%%FMPQODY*S!6ix0lk|urT*|&mlwMr86od7KTmkr0(JNv$8rW2#S;h zS+zK*wRRV3R*PQmSOMIic!r-O*zxF0v#~TZ0$%w9{jZWsTE~r@jjSww77|X7LuRUx zW|jKobjNK_9T9PvJ1|Oz5*_oFP3u+3>30(gl$#RHuk?D=6^~gSR!qx@Y|bn6I`tU} zN^*DSOa9!SE@g=ZY3|}M4aK=xT zW}uX2tC5_ggUN_4#3Q=9yY@1zJ8MZ*!S7I1wv&f#F`g4RuwJ1MF_*M#_d?oGJ&+vA{5@% zou3F7%t0~q>_pULWP?J-DYQMatF}(T!$X51zcS5DWBx=ZV~VqO?VQ#&xw7Zy8yTSw zJf=y^09Q{vv8uh4wyuaDIp$8y#{IU!b|!+L0NUS|($Ln%ecJFJ3-s};J)Z$o8DVm2 zD|s&aLs1YZ+X+08iB!^}2RfBBT@whzn3r5(kwN zv--q$#)7I#cjJi2_=C~mc(GYOdzMT@L_}8d(7AxYbAG>}rG5|Xb_xsOL(Sz*fFiwd zj3E1GQMtws*;h6h>$jIoZP4~HK;v?MFUS=VO3!{9b)l21v z1`3Q$IabJ;aTgWnU*~58z~2@uA%;v)IBqmr&2SXtmJ^avj`>6y58^oS!GlP0$W}Gz z{yHLUU+F2MOk*B8zc17Sb-7 zc&LKN`xG1JsmFvPe;SGUgI5%r)R+bJo=2*6HlL8H+vo5$Y<|?w*4M5cUe$j?VAWTh}LFGjt`bKFu#4xtSXUckNcBLuFI~SIntkM)H|^- zs$wpyPa6Gn+;(ag5BvLcO(}rLL;20Im#-zUc)efRoQUGByRH6S!yv=I4vEIZPPOx( zV%UiXVZBuks=Q)kn<$;inbk~q=TdnA44ywN#kAcev(-^p<~Wpik!w(a&y;20S2ar)f@f&}LIhSzb>qn#X@D~P(G)-U?H#zC?Oekjc) zzKEW9vV0=D*_qr498?~kXrCK$DOxI|$r(NdEhE$JaI?oIyjKa2BbjkiM%Lv_HQx6$ z%jE24TyiZ+N+${f11;+`yL)CH>QMAJ`0K-8N;azrP6Zlw*5jeUeSfasmY>ztmqv%L z2R-vB-^X2L#Xn2;yRZL#LV$hhtAbSgC?|~E{!4RV;s(-smCptuh#)j?U>!DCE!1%7 zt0}VLv5 zam2|xi^@whI3R4K@-ZciR`G*HU}i3TdZlf%yJHaRiih@MaA%7PI5R$Jgf7G&OC*2L%D0v=?!GRuulDOi(8Zx4`L;@MFf{V$7tl5xUuN zE!EOSX^601-R+us?uMYnr5Y~>MHbf2SIe3gakEoLe=Y76VKTguj@i5DsY}k>pGmf; zrH=___p8k+?XN3b=#I+ieWIt~qdFMFHL|^G@=!&|bN)7ZIE>kWdwp$9>Cnat9=L)) zr3mm#GCbJw3)P+ycwQpR7^dUE0L2dN+>ZO|B)YDTSro*^SkOYS&(aWkuPP-+z7~%% zt_MxXXu!+SLYp-kFb0Ho?(B1Z_R%-fe)r17*Icr4p?XI-I7nfS)fX2{ZFNGt!lDZG ztGjF8ksPibp(%0G*Y|9&lEgz-WCht@wX*`9e68Bp&|iTe@!1&=y{M+z{{TFf*%p-e zX~+h=Ds3-@=LidzeBfvwFOpzaf0EXUTXRbvGY{R8k9j}svXBiu{W^9^Rp;c8D4FJ`(V4dW%($Zlb_L=)b-~mCKuUdaw zIm*1$&b~zPofc$;4#vx26d1Co5Iuuy$%?D32s(7OLl68u9qmC*>IxKRPB`KQ-@6x-26T41L@k5W5YgoHyn&Yfty`3MfG zk5BZZF8lk+P99OW>dPCknYV2!#MtEIplKu`_e~Gi_1|9}cgELDezy^NJM0#n2tHjG z_2UnQ%-7`z+64JTBqqm}YYy+$XbfIgOP|5(3G)$L9u`@U^9jo;-oEByZ%=!3JOQ6R z>P&n@_`CQ^mx3^$HdkEF$Az$mp_3b3*FFvc5mknW&(Qlz-#_)j(YxfQfe!)wdj;23 zE2tRhUQqqRgR`E?FbzwpIiPgwA_hAoz{kIGgwIY@b zecR0KexvWtngR}A3vbiJoP1gfMxF=8 zc~P?@4T|&_O6B@5d$TbN#g)nN+VPOpqvQtOmZnv9pDkr&t1{ZL9rV)4Ltc1z7Qx`) zgwrheQaY(Ie{|nwd6{IZtJsP!=5g6bGkh zO0TyPpi>7hF_cX6MbX-*+>^=Nz1M~6EMC8w2@Opq1r3EVH$hZKe_m5n(NI_I^gr(; zsPtDjpPJ8V_O?!d@G>p#g=w&tfIou52RCM?<6O%M4Gs>jKz|o!*!Ee0q9~_6KLcH*`}{k zrnh#x4O?6Jhq(9nI;X52Xbw%2!*T2H9XR#Q5S!;-h@Yq!$3qGhlh zKf22}pd>`ur^iM4TrrBF)$79LGn+ya&Yh{!ZbMl=rH;Iyz{ao%H2)CBOcxLq%8TV{ zsmkek5K#U6hJks~R3ExjYU@;gOsP#p%IyCjM=*1RFxaeC8|)y@(z(7~Z}@gHXlRP- z?=U~9@bm7GW*hj#@x`vZc`Pq!_Lj|L|9yR>)ofi>TG|T0Mgp65dze{eG3Hc*s~1x7 z=iF%H>6*^grNctthVE_w^16ugx;b+3cp|CbfDmNewZzUX6+R*3NZ9|1=s- zv3s1m23lVglx(DovGVE8?AbRhqtj`3x4qs;R3z*uZ3K*-O|@@Q!><0xs8+QKwqvO8 zHHiV$yydW7s?>Nob*#1hQEvH*9;LXH%ek!Ci+rkCGfyyI zYLcq|Bj(;XiXDEkvp(jJO8~mB8tLp9?{s9CI*JKtu(9lp}SORfJj?AUS0O!~TQ z2YhpaoSL0)>gHNE1FKN++mq+F&e3AEs|M9g`iWuov-kqv zuf$Hv_Rh^A;?2wJMXeUdZJ60){KMg)r_?#FH7%}88Y*7kb!TUetg4%i2KY(82^g!E z+U>s{_W;P?`@Q>H%P6akn%8>Celc}gUy{zHp?9J5Ybp6gTpEl6+ijzhvtc6M%D2j@ z8?mGzT_wjY0NC@g_V-#vi>=zcbK2cL3U}4HOLL!^(loE^FPF0g0Q}Y%L(M22QPP$t z56#MLYB~lgk_3-qW-#wHE25*Op~y=~rHr2I*hu7mnpa#*ZsP$}_6q5B`3hHzD~vTyNZG_5KK2Fx#js{QiWYA)VCN#eLF=**rqr0)) z)*~;g>#U3!&)UYDPSxHBjw#N)>rLlx(%r3o7YsX{?Zk)m;S?D`elw%R`Hm-LzriE2 z@0Z<16KJMeo_NH+IWKcD1v$OK;o;$$mU3&cY@UVi9!7I=-rDHJ9>r?WU`iReRj+vP z=vJ(DR-ELmN-{DfT)~H1W(d3uHtQK1*TPB}wRfZAi`VOorfwQ8_ZmU1n$)5)TG~9^ z9{c47{TWKAeu|MQVu5qN{qnzkcpvmX{BT{&Y+Zw;lj^ogwa6qA#iJIG==G{tOK5t1&WGCF@InYg6I zJ|dicnb`eAItyrEyPLRafDtvb*kGzEfS`_S#)Vh5b(1A}iz&C%V+(5kx(VeQKoG{J zjzUGXVg0O1WLYY=OGscP<&_K3v3`6fr`d>2Ra@1kia zEpyGVSeR19ba2mttpI$xIky4@XYa;zA)pXp&8%!Yvb!GjqvygItLeCRO;BIYGWzS*GkdkODsdy za6@_rb(!=6>$IcTjAYsvN`P;0c2<$I(N7yj2H29$MC(dFTT-}HODwwtJdNgWPQu{ zW#>Zxusb>8>Y8B#uzYLocfe_j-<7>iC*I*V;Uy(|@gn7i$^T%5QWU4AvP+Oi??Wwp zNK!QQ|1fcJzKD!Mw`}NftXq1RD9MVkr8++eL;8$A-g0iXT&TY5f1XYqAGfUETPpM>l=>J6q(33i6VzGCOSCCg~_2j}~l zdX*XtFQ<5QBv~J~bT-HSqN84uUrfHt$(c?`o4ih|F*kQ;H@BJZ{zLf1zcQtXUNp&^w0?PADv7V+g{1s$TBL!2jOicjK zC(ogC6moWcZr8dC0gsLxZzznBXwp5j2O;cOUwiH08_=m_Z7^+}by-{I){@uK8}bQ) zlaxARv_z-Ios8B;r<&QL6$+oQ=wep0UXXfh@F> z@bIdmiX9JPKsXeA2J=jd8vBGu)*uy}ulh3L%*^U!QkP6%z(0kvva-q>LRbrJe`qd} zA%q193%!LwHz3--9f-7HM*3q&>>6RQ#;WKD%!L@|0g%jKGIqH#Eh)C%qLLLN0sbGS z!eU}pc|?F;MPvZIt`t&syYm&{SV1W^l7DUM-xn1TS@y0)OY~?3#bW@@GYFs#Ffc^2 z4O5b_!VHQ+@*mJBNul_0>x&D!29CQGXF~J|uKA*K8RVD^Yc^KTJrVrwnQHl7K&ah1v%1pw4>~4r80h`jRXbve z@=l^7W22SO%K?4LZR`^X_8gUOc%VJ#Awh+;p6{zkRhpvbC(=(kx}jBG?`a`7gEDG? z0@jB~w(XgABD(_sK*k8&7uv1naV#nps#U8mpr8=v3OYhaC7|F#0wmxc0_eW_ivp>C zU?|$JzRFS&Tza;J0HXYhJCYWlCF1*n~ zYb$#gM07&jfH2kA0P}pC)3Gw?fkfE%$T(OL z7NDwq;-CLZ3jiFp)A_um)$U9g1Oj<#&*+dPuJe0ELUSC_3vP_A`@_*i1aVIpz(oa( zbA-(!d2-;kb4645o#chy-QWM9)f6uHCG%1)1Gkdnz88LXcQ=gh1-I9efJng@SBP3R zg5PFQM@eEMj^P9VOwP077ULR_k?}^YuVsey9E!Dtgvi0ggRR zv#B48tz8A=JBB{uXH&#qD@Hn%Bb_0vc5V{Y8 z+!Kld7K&pb3^ChN76RDHEY7|tDDbbqVhTupWqZJ}hW9D7exx(+x0wF^JESUM6;fe{ zyzz>&Q7~YnQ6UMi)!y0=l^H*Ni$BeKXK3gK(9i3}@(z2-046CAVlOz|s_e7o*QF*GSrihRZq zayjlDKV^0>5S@hdMcEMB(UAzT=Sm22ok&QWowbX^KTBnTiuEK5zySd|B_57|<0YztHvAf(N%4)1&1yp%Z^Bxc=0 zndcE%qXZlbEj#!p<@(|+16lo4NkN){1_nIREG{6FIT8Xmf`3hsACx{3OR@XM;0>NA zGie0;KUV8N0_sH=D1sp@#5=!$3Ls%Yw@x&NA_2ngi&u650%ZOOod09kzDhp*`;p&}{5gJV4iir#NOGOOhKLqCb&0Meb^EB+1O& zdMH%|kWJAlEvyWuFTs061pPz0?ufuXh;l`6`lu{vxb9NkW8p}!vEvO(M6LMwVd2ZR z=w*a_Ao&&Z^MDCS%MH5)fja07pMScj5M%%U=?DPpc@z8d6f(?T{917X!hr9^kFw6_ zL?-^P)&3z17DCL72e7LD2(DN@BElG;=K6lu^g9Dz9}D3lSp5H9_qVhOGZ)8~&pbb- z_WuCrpZGC=0m;l@c29!25S&Mn3k_Mm3VwDYw&qF@z?fm(QGgx%yRs{_8iq`A@C$FP zOIS!q>ucd{=ilWlF1Kj7G2>fuKrRgCh6c`oDqRZEmls`&rK$W6)JQ?Jg9^O3hBO;X zFC8A@O(gUcLMI|mjskL}_1d~Eh5Ysu0=V-975-IFG=Z-KN4rf(_lhmOzIcEa zY3FYswOiPs?>G@vv zm7n@aq?Yd?n?Ep{4=e=0%8!3m77Xd-p)H_Ec9+&G>CI>h;`0eejfU&TGiy%<#_aVKX zgp`z&j7*bel|C_^3-JsR!5+Al2H+XO02Gvv7$7YP57=dWiXEEIr5ke^%l~tUIXx9b@df&S-dSYz!L*Cs15Y0bYoZi_7b5 zp$woE%4W7ep%0qAFvlVkTB2$siiDXJvX@OWu)*uWN?#ORf~(n3)Acw6 zsCA0!QpwdHrQihq>0OG7imqUge_$0BSL3=c2j#t?t7+#|4+!M^0SHRMI8c9w9=M>@q;HJkV7V? z3yfKiz&`9KP4T4L3GtDT#|NhAbnbbq=Zuf`ipT#PyH|7l@d7SwAn_NFubdy*A3$0fkOgSQ^k!bT!a4l9a$bNqA3SJs==}Ap_$^mM?*y4Vyp}YuOeSvelodA_v1|9gbajl*wXs zK1@=x6m*lPAjigD*jwCab#mb_FyP3#du`P`LtJWEK{~Ol(!|F=M}6cXU_6{hl-IlH z!bC?$S3aE1=8*!>q61+eAO1oDGmi7PVh)7f3yD z_mfoS<_9BjLO?i4GNjmw(3yS4(ZzEvryPS`E&J3G>MM71q6#|pO&Hhe6mLOA#}{^D zy4A&*F6XWnqZ(|#XsnO!d{nM~*y%+>{aQX`hF*g(ica>)ms7uM-wUkTsGxGQTKX#3 z>s*T{aQGiOXjIT9{#ltBS|o2u>pA&q{SSp`o%4G;o|n^HaM-W;XJ!s{ zBZnafFzbxZllkdt_0F`q&6rE?1T|F~8wh^R$PxWfU)e07Ja#JAYnwWBNW@DP0 zDOfX@`<5yI-Mh48T#{U+{fUCV@MfmCWSmXI$i}>ojJulLUQwO|XtUJSQ`_3iZ>!S- zjL+W&VV5%{s>>+T)LSpB12~5`pSL&+KG#vlCzI>Rnpy5qq_h}d_c?W&I^I%Mv_R=n z@7=03G@1qhG*U_{hsoWRXNLUoCXQ+~U$R!?>6sn2+t*$y9#_tP$#yGhSkYs=dr8QuqS8tB@ ze7}|eYq(0wb=RCW7PG<{CAFqvn_XwDT3L`lmZpBX-Q|6UVPLmkneKM2hjc8d-s#Ks z>)19OeN@yqV~H!Zpw3!|g_@(?X|zzB^*pW8#v~XWo_fw~L(lcpmp}yKFiYii*yPvV zN+eI)G#amx@4*&YA*)JrXBzJC)Z+4fsC-+5YIAex!z}sSt!CzcY;oa4 zI`8H~6%HoOQy_Q(gpXfeT?Cb>2f+W_#OFdj_6v9(h>Z|8e#)k?2Ty<v1j8uu5BB6ig0_SL342oLAHUk zu<*r4l@`qM^w5iCU%!inR(yF&5niJRsi7m8pkjt$2rMXzgCfLt{_$5GYmI%sVC2}I zjFn;o^{*qt)Z>?T*!Aq!b&KbX#Z3x43yTqzut-sH^ zVmdwcHKk0)K5(V;g>+Eq0=EqQZ~{InrT`R_&(Hw7#s4nneFtIC0C5EoP0!wdJ1T{A z%N-#4rlh2lBy@3ZUf15ObEw;$FlksV$S)v+xPwmbUs~G@`x70dg0yT#jt?B&eo&gj zXHt`HYu8dY(z=pMz`)GM&BSDX$TJ3iDaY^ypj;h`ZHIp9!gpAJz`3Q{l`RA3}$ z&I*l34+^IWIe#?#UMknE+Ytl(Pvw&3QYn_&*jYs_>_iIzyPcA#_UigV@3~yP%YvNT zg~_{8sUp3qcQ4sO_(wNrEUoUF)&q2@NLoYt!{}KzYwHUkTl%yKn59n z<#HnQGzgPC)RwTO#bHm}WxabQ4bisG+qS%l*tK}#5Q8TFn1O0k`XjA+stmSC@yd0D zzM--VrE6W3oq|~2hoKuPb?kg(4StU}Rx~8yDrC*_r$45r=lH8l5p|fi&`ygTe_IOhc~4#!0M9!?T$W51(Sw7PRUTo?`RShvQOh=-u|+wtfjhzG^^A zZG04XEV8;SpM!U2vmabJC7az<4{?*~F==ftepH&A-L{on1}?87lc>PTON+kt!;Zj7 z51AjFu;*X#rG;2|5%Wt+AvIqDNn$ypAbo(9Ln4+z<~)CrR{u-H*iq=ZyjSiGJ6%!s zP|~1g$}6vGRlU*b)xYQBbw0e|E=JX-*q~&G4SHV>`ueI#dyKxc=F!|IZj9V-S3KR7%LsX}8R^n17O1B=52Y6r=HX6qernm{g_ zdv#^S{br~4?#_|$Dm#ONExZVWLxjG9Bc+bCp^0RDApUNGJDr0bJ;r93j4N_H{*LC# zLde06tv{7zd4ni%(Z{ao;J2h@YmR-6WizW8L$ZQLyjqzzY`Jwa8(MB1nb>9i@hHuJ z&}SA#V?Pb^O1hQd>JdWQhB1;kI&4*N8eZl+h~iaw(n;QJfT!UrapC>#Fo7RHY#jTe z5MoszK;SSEykd8ESG@sSxt#CwR8A_H2AXPAK08u7lR*IfA=JpSe2daYQJCsI#rtTCd&e~)XC!68pde3{0C2+U9U%Br zJdqpz9h@N=vuUSkDBfFae8$W=S`#rpC$s#`LEOpEiA$12nFG(nqN5UVGPA6WKHZJr zLarZa*|R(j-n$oA1CFk%p9I>Nm(C)!BssYDx?I6^B%4?dZ`;&t8eo~%`h2aw=rAaR zZTdHmTp7;n5G)q}2Q~t$(37!eeP6x=NNh&~zwGm0RAm<(PH=`gO5^kq?zj2e7}mdNde`)pIBHT` zxx;OI|K@^w)ix;`TQ}(cSqt6lwub2B&T@p(X1wwof_d)JJT|O;n>&6x-jKJlvJw;& ztQq?G0*v>kS@$7Esir0IyA-V)S2w25AEj9*X-mUNLlP)=v=90wvJH34I%ZF7G(`? zH3Ei2y$sff%K&Lep2L1StDu4|%Y;xIpunZ8uYHb*>6Smlc*?r0s=hhddOH87jdee> zq`$6d_U*&X%3{UX>hN@&)oFfW)p{unQg`!IwtJ=z^j8NkCWNb>V=5%>d=tF}f3O2d zybqYtq|0e9zK{LBAm4Y*Okv*jsN4{F9*|%LRXpPJFdDWy?IDVQ4EO)CcwF4=UaqoL z#YA3;(C|_NlRvWFs{LnTYiQncRO6mxTCE!kI9%uRs+KRne8+%OIJ^#f1G#tXz8^3D z#4x$>gpOurX0=ZQy%>x$`|}$!{3(QsdXym3yzexun0UPONHu^aLFhli<3NIl)Gr1!MF_8Gb<^qm?Eq@%STLdc{%8^w zbCN6I|7-3nqpIrqwGW%_O(Pv5Ddi@lq&uZkx*GxM?i3N}7Dc4HrBPbCyBh&%&*Z+( z{ha4L-@yo+xTmZlnolJ0wDDN~5U)zXY)dj2Z3QJu#69X4zk z`kqfbIIPe|AF43`ttzOmg%G~_=5x6cK5b$3vp}|$_VV--ZYsOk{9R<&{AkWiZV=og zXOPFG*0ax&^z`(Xeh+rBwk9rmY4Ve7ZM;Cv4yY=D^Fd7-KO##Wv!Uq9l3`B6M zV2PHLBjFrI4p9jz1(m0R!9vkgJWOi`88kV9aHvWooVB=I03Bcyc-=IJ>a@V_gUI*S zNt26-&_iI1Y7p{=D~9y8t3&jc-w@ohr)Yh=)uip_|D$!69jfr{)?)4E@NIG?JEnOASzjQ$C*P>YCS`Pt*EIz zGW(WwIY^R>|1v0u-anu@#@N1*hSBcPsce$YC;QEu0F+XuRmBje9A<-O~ zX1md;(Y2H7?)ENDPR{9e9NP$|U4+`B&e0v7^n;~8_jNvo>&1`Yw+n!+F2Hwxy24|@ zZ3<{ik6pVWaKTBpen{!_)kj9NVVit~T)v(n?AzEzLh$6_sV$squX|SjG}zC?a`e1uJ7xISgM5H}038fwnzhNH&B2_Qfa-rl}_D{|Cp3I_>#r%qGK zMk9PFBPYqr3|(HP%k6vG5gOnBO=2VxPS~TKc!o)gnpu@B5$_A5x-p&%dG-^I=N~!l zRpP+F6?`U?0{E~0<6}4{2;Qfd5Dcx*h=AAMS_ClQ*o=oF!vKjEzC`N{ezSg9fP4>z zY8R)-uq4wB_9y(jL8GJ2?LVd^83iZ#Jp!e|MvqFTuAf_(V7d%>@q;#sU@UIy{)92aMqXlPfSe!b6qvolXYFvSJRZ(NVL^S7k`#7o{%R}bC4`0FJx+_%l zQSItDLs@$k#%KZ!UJpWm&(%cmYe7HKm$wN6N%>E?0oYilswB&!*--gwr{)UrTkUI~ zekd^Mv`NDSbCJwk+}K=1qlZ~hXti0fXaqq~X&?nyOekOwdagjU4S=Kh=>!akwlO3S8TQ!l~_d>Or2i&fCsOWrkd+tS^$!yw+6*7 z0T1_0k`oR7BPtY&Nm4FG8b&~%Pml^#34!x{qK2sE@%W!gC>1zsq)_@%6%{8{Gcgfd zzSxKHKF8Pk9& zoM!eRFp!*bTB-1?H^IT@@IthkBJu+xf|J%jSNN;B7{vml%%Y53q9tJK$jA$L5HD(x z=&&Hkw-2NyMzC{cChH8Yy4HkIDF42JB{Ih2m0c(_mcss4s30fc=>MfW87MSKE7>x_0 zSbgTDJd1{o#DKfkE+*4M-cC!T?{oC)L$hyC|67wAk#B2^l=0cZc#l>oaB-dQZ?F2< z+vXGIQA`V0f-6*gm!1r9*SmzH%kti~9u@P|+fcv7cBmJ>nRgVMoF5t*!ljdfq96g} z0PY4-9A=|vf&ZVIr3{bD*fTX+I?AU`?gZlSkQ}nE-8`xjs{MxJZ1DKU=TJW@Q7v~r z*)1-cOzVfrE5iyteWTxnKXRJ-`STP^PulJ-=0GYyKsTLT**RIMr9P70;HSb#|QKDHDRZ*f-hA%UMMPN>R0@D^% z_OsR2;M%5fUQd-8xVgD0eR|iMTa1eeXBdF_+4;?FM<_$DPhnpsVNQkHLfzQI+Shs$y(BPa->JI)^b;lwcDj@|!C zURPJw#^%d}4HAB+0t4t~G{Bokm~$?-3Y04+j~+cDi33*j^C;;TVsUU1MqH^`{`a2Y zoh$7UJrkkG=FH_EnQRDiJfEyojlNkDyL#ciudSn_V``dj`S^N)7}dNrMf? zTS`ywP58pj7`}_n-~Nk8rOX?MOm64`Ta{ zAx?7$9zMR?u=|Lm46MMgixvsZRouzPj}*uPQbk>}cUkzW)x^l5P`*BKvenfwVlvj; z!Vd}PGJjplI|&n7>!?PCn8Ry)h(2MWl$n$hGz|a@{#1OdqRtW)La(aNm~KoG+Z$<> z`CVZ&%em;HMhTgRAK&s6V86_xajQQsSXDr@2g(;A_}5c_Pd^~9U_R7AdV85n@OBtq znFQfhG-AX@XgN&)dmkr5(IQ+EaKHRNhj~AqPS5r8Z}+|NG%G(qT^q;6tw<*3aPFj| zyu-N(K%bz=6y4Ie7v%Tf@a)0EE|nB~@G&Ax9Znur0D%oZeo6e$a(Bq^%{0_c3@LV` zmS$=62C#6kibUR90cw^M0!x8zCjG$0By&YSnF~LON<25{c&Piyv?Rb^wxSo$A+~8s%^)MP?7Aec~ z!oO1q8KE<(e$Bxd;(IB+R4S@MJDMOYCP6&4*l&QHZW_SaNy*3k{%x7N?02&t+ODq8 zfcfk#+P3UNZEb;;kMwtF=+m;Q@0QcLz~9XL#AZwMYI)>(@<=u-Rc$MOV90mpnd+G3 zZu-R_W`EJ%8SY?PoqgGL^}Xw1m5NUZ)eAqLY{C}_7=?;P;tWE#w#90#BL7p7JYC5> zkNq}986Hn-z+gB~XQsj9nD$n?Ej%_HQ`av%v9%5`lDu!_QztUHpww0xho zGudpEc0Vv-mGZgQcl#({(ecb~bFxK4C7x8CN=L0{dMN4ZPpM75w0Bvpf3}~0MA{}Q zbM;r^-%Vz%T8>Q)?9jN#9~_eQ<_KXS@OSEA)lwoO?})VI9gzn zz|b?C?K`I%=AjkPx@o8A4|V_B?#V7%xBJ^oiX=%fg(J7jmXo@lfs{+rF4N8X3F~4) ziowe!TW5{dP~u7T>#-S@XH<;E+*%IvEygE}E$5~V&2)suMKeXbvBm>l)Gz*|OiV|4 zZXAA@ZDn-Rvv=?u%>OmK&uYrqar$AX#Y0K^&qbF@)knKX`@!a}pUDwqN7_RvOm${0 z)(V$z^D<*U9sCE#6*18iJMh0Oq23clBHl*tbTT5Pwrai*6gajI()V4M3Fh!jv#3j#2DvNjT*D`V@)H!eDa2Tt zoU)ncdNet8OEd-stlW zo|c37Qz{_f{8?9N7RN4J!~^CrX@U3_`W#y>d5axicn65WIgG1#lPX4!Jq#sAB&qPF zf1r;M^t%@(S5#=ZE1o@8QpDQ~>)QPaeEOQ)obRSaKqd0v@MG>F&O8arWdzgLO8eKG z5_+x_>@+@NQQx=r-+50WY*6BhgOHU4ks^ElVg^N3GM2ZFBvlzg!~GG&#nZUQ81*D^3$XJQ+2ekHz;8jtbkV=XZ1P# z39I$~ZTs}1&&twuvD%Xrg?#D5do{QDsSjTao!xG5g`7R{=5F7JMh8FFW#+2Y z;gF;dGIwCEB4|F3WZ|E6Uw=B*kyQ7m$jacIT4}6SOjA}xM@!jcLrQV$S%WAK@A&w* z1ViQL!`PNZ<1encA+1o7w*4td>$;MRCmAHBy3tn&Rz$e1`%LmZK4a@C_F~Lxnw@I$ z9jW%(n5LbVmephIwW>x&;q87BZuVhzO(Nxnt^UMF+9YOb)qz75~_swcFJ3u@{ z9t7Kl&mqPsm}->iCXI9fEp+8Ij28UE*)JTcW{z_aQAP_23f_p%&MfYt$HzsxQF%A; z&&@4AA|qRf&ysv_ixLSl(@bWHSRyMH4{%6C>rBtryr!X*Rdhk zViG!ypr5)t^xov;?I_w}RuuD-F{v3m0`ti>I-tz4J6->N*A#bG=YHLce(iYk*&-z1 z1oc}jB`HzHi6qt#UPKu3C;cLgT%eK*D^$uP{eg#~qXX)03OVB$!Xj|;v~70>j=x3Q zgFk{*aWMVP?pN=&QngV_hhW=0$BW7XmvQ>g(2XzE4O4Y~G=o5PNjEPcP705iayz{r zS{08aOlsnC5S4NHMppKe+wk2yyeR21E(c>e2!Voglz63?ZPh1pW}qnGkR1!L7+z>> zbMkiaa%NyJ`DNsF+88yAb0D*1sNX1E-i9N;s5aV#U>{4klQ(sGCUmYJj~+Sb+kdmF z1Xuo6d1=i2F}v}a%~sFv&)bu}M*{P+8cQ=tRSpJ2i$WZoOTSJchjGaHcE&bat4wg} zmX|7cExm{CrI>C;=1DxNf9HyaJ2ap4j8vOAC3B6(Y`?ZEgN$hwH(+jlE&R*N*|GWV zeI42c?}q};WcP849v7*v=&V&R_05uQgRE|^q7poeo5ac}*5owI`P9l#0{35lS*6?a zYcA5U6ib$y7^FYgeek~|YOGP_mf*RU6>TKvC(FUY&Bw_<%ubAc*K7Y-i80VCY}obK zR0~EYUfm$g;$l1kiijaiK|f|I^9qFB@ztYu4&d|AS}bCJH*wQBl~GN2MJJo5d3gmDTH5jQ-}3tQo_ z{uG0l{G09z*-(1xb35T8{5qqt#oiAT?9Kf!`&rmKYnR2`qCYisEHxbFx+W6Z(>+@_ z{Nd77S?;-ncB>NYy4{1GGxMgMFp20b`VfEbR;%`-WNO5^2Z7l$OYCGt)9(VwZT=u! z43y5gC_LujO|Ea2{**RCvVBg!gQ}i7!>14tuq-852$-8xesxVV&NZsF{Hi+sGK5>{y+b5;yC(Pj+dT zN5gS3BRj1wh|HslqxST>SV+xO3pSy3cZTztgMvx&)}rlpOq|6(-u`s=PWwYTN1evd zgZV~~#A0rH8_VQ2x3wQ76Jvl#{AdXK1+V9+Jrac~T298 z2fgQ^6^RoSw@X%J3Fm@4)D(}X&Muup;AV|J#plpPR(i5GJhXe*@EL#p{@eAC`gQ3a zRSc!Dc6OVU%}U5GD$8YOH#DB#=by01GwE6TS-+EH@_VXF3{+_w1w<7i?Fvi)x$sVsmFL)})cel&^Sp16GW0JV07+_fdv4hNbFY!DOuPa&Vr%aER z!WmfQm&S`zSDe4IB%hr=nt#z@y2aMye^}`^B{QHbPS^-~O+}*Bl?%Cl!FcMRghrrgB;zzK+c{ntAQ_D%p$%pS_FNst^Pi`T5N+*Q~Ni z$#|VszdhZZg8W05xjhzlp-e6BkU_ncowsLZF+6%W$waMF%mbmEy*kpjE$N5ZkLPjV z!teC{0K;iPVWG+MRiG^bC8R+xTLg4LiEMfW@n=hi8&CB*6s8TeIs8aI0&$*01TuIKmMRdw$0orNTIs0vAgi;93vbR~w( z!3V_Qucg5{o-%Fq5LzoXIVJm01^?ql;}fF z4_miyaByVoPtoCexm7D;@~N(X@An(db+D9bJ5I%3GzH4+6got8Isuk@tp>RU(`yeTH{Vvox?S=V%XM9g`OC-+w?= z@A^r)|ABu1vL{>mIZ$soI`w(zv!j)tF7iL3D?^)Ne#lSiiqgmre)(E5Fh@I2B*M9e zg3Ya}B>uS!)PD#uS~I^-Qi$_tI||%>J65LJD%!O-08D7rYcT*T;sn&NlQ>>YQN{#su6y4Xz~)c9@s z@!q<8JiA_{$<(WgE!F$`PAui&MWY{#_ylxY-}7L#7H$baeskEVJO^e;xuwcpFKyqn*<@X>KPN)u}_-QA;!<{g) z6|u3!+y*VaC4Gg>q&Y6>3v0Yv_F7PqxVNs`&{My);^BYU^4-cq*7p}xn1%mU|EqFE z(prtKMB8cq97<4xoN4xa#`=PpnfbaM38l@H2aVIsy#6?jab) zTp~>4;$3rerm^MFDs)1`a#8*%6!mL=+LCiKGfQ!OO*l`1%qj1fV_UoqkD%Vfx=CE{ z@J3R_xSoZQLHqP(2C=Rk+lP{(Jl5>gQWw2biaQFDZHGDU@`=Og@19d-J#;FZySaK2^N9fW!t6Xu>bY6{3UJ-tJ;>$u_C_ zc&IhPP?mnxj$<>du}#(>@o;d}CwAGf29>PC<-xqWWJ1jIjDRPWFoS#ev0Y0PyS@nw zUsz*?wds*wflrj~C5hI^xjpvAx+Z$n=wukzy`(bh^AgRBIwE-j_MuIE^&kPYum&u} zDy=B8W|y{V{gZq{WyoAr^fczln4a=^7ZzFQ53(JV?3~T8=Di^M$Z~GdL0NCQ{Ae7V zX%8W3=6j~va?8c!J&=(Whhe8~668h8fMWJU-GyDP+Y#B%U z?qMzBU#&yZjeX11P0)$RrmDK-+zgd*CXkFQW=kbE*;h*42FArtL`EYM7f*ZfbmsJ<>ak1wlFQZaX z@#WT0;X_eJ<`cwn7)e2*GD#>HKUDi(wmyIrD5xKXim1Xsx-thk*v?P*==0zxq5+)% zJuuG-e8-3YY)jF|U*SPQ0>prwhX5iuiV83GjS+0eh$WxWBR(7eKp@1ZJY4V{Rj|Di z%sPOyeD*!sg_8t6F{vF6B~xfrWhB9qA)&G6^%_OE&ow!GqEdGBH!URKMWM+b&*rat zS#T{Xh#K7={pvMEjtsaSs)<$-cvMaV4r z2EcU%R_#7W2a1G0qZ95RfNQ7v#(0s;hsvvR5Bk{^U>Yn+inv(PIra5#fW`(I+f)z{ ziPs^d zsd1NCGo$t- zHxAH@NWsba`hQz=J3Bj_Ejqtw6l0U~C1ho>5og|th5t)8Kp++v{JK7+UWuU5OGP#i z7!%P$5|*5XL;*MNUm00&PF@6&dr8^ZZC0bSq?uRU!=FXI-FM+DgBtDMX59Ah53l?h zx+D^n%+ybk91|Xnj;4LI{WAiyOved&&F>|6QPDet0~p2DaCWw!Cs*9>uSG@AJzw&T zw0PKDe`J6J5K|-AzzJLbEJ#emi|M0AjX)3!bp1p_`e6sHWwUuZfLal{8bh67bq~zX z%j3U5zVozQEr`S=W!QCl{d#$Gf2K;i+GTqr7X(aemuQBZcD~>yl#TSIhND118Sd@s zdax-0Fl5>jv+|-0te2;!r$Nl`3bL?DoD(gJA;}wi>d5$kK7j(%5qQzGWnh#PCKuo8 zX(DbR?==d{;@dGgAeTW`5AD2g>Yz28O&n9_p(ny!rd`(BE>Q8LMq-0}7IR8K`i$Zd z_(Chp0*suqwZ~`QF`$&bda3UM zLu3N5TX>n8QF}%cB+fR zY9|c%v68OxXx4LzD8*STP$J)qKzqrXJ5&37Rl@2ZkGt2r&A7U#_g@VHgd<96M1G9g z$VX*QBMq{ypRLslXwZy6`6Bj!54XrJ4@5xI^HO34Wjies^BH0H_L{>{nf>F%Wnv0l z4Z#GRq(lW+Mv30Q6~rtD#|=@To%snOrx5<58mNdzOlu^=7XBGEPpf~-wXA@ciMs3> z4#K0M?>}S7qD{P)FFKP14o(!oe-jFHMA2OHz3}L zFjYE-Qb}a~U2hWJPsJCa0mxg>Zptmb9Im-0DQsl}m37LSy~ z8H1Lbc4;77sID!Qpw%&CuY3d_+_FBTry9`#C<||H)zeu%J|hQh*-29fc^F7vK&s>V zUkDS(p+X^HAeh;VuS@+Q&;C+6zzQru{*QegQ}DwH{BgjqhyMupzjki_KhJ0R4}#&F WeM-GeSUR|TI9W+0iBd76p#K7$0(0X4 literal 0 HcmV?d00001 diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000..fbdade7da --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,179 @@ +LLD - The LLVM Linker +===================== + +LLD is a linker from the LLVM project. That is a drop-in replacement +for system linkers and runs much faster than them. It also provides +features that are useful for toolchain developers. + +The linker supports ELF (Unix), PE/COFF (Windows) and Mach-O (macOS) +in descending order of completeness. Internally, LLD consists of three +different linkers. The ELF port is the one that will be described in +this document. The PE/COFF port is almost complete except the lack of +the Windows debug info (PDB) support. The Mach-O port is built based +on a different architecture than the ELF or COFF ports. For the +details about Mach-O, please read :doc:`AtomLLD`. + +Features +-------- + +- LLD is a drop-in replacement for the GNU linkers. That accepts the + same command line arguments and linker scripts as GNU. + + We are currently working closely with the FreeBSD project to make + LLD default system linker in future versions of the operating + system, so we are serious about addressing compatibility issues. As + of February 2017, LLD is able to link the entire FreeBSD/amd64 base + system including the kernel. With a few work-in-progress patches it + can link approximately 95% of the ports collection on AMD64. For the + details, see `FreeBSD quarterly status report + `_. + +- LLD is very fast. When you link a large program on a multicore + machine, you can expect that LLD runs more than twice as fast as GNU + gold linker. Your milage may vary, though. + +- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64, + ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU. + Among these, x86-64 is the most well-supported target and have + reached production quality. AArch64 and MIPS seem decent too. x86 + should be OK but not well tested yet. ARM support is being developed + actively. + +- It is always a cross-linker, meaning that it always supports all the + above targets however it was built. In fact, we don't provide a + build-time option to enable/disable each target. This should make it + easy to use our linker as part of a cross-compile toolchain. + +- You can embed LLD to your program to eliminate dependency to + external linkers. All you have to do is to construct object files + and command line arguments just like you would do to invoke an + external linker and then call the linker's main function, + ``lld::elf::link``, from your code. + +- It is small. We are using LLVM libObject library to read from object + files, so it is not completely a fair comparison, but as of February + 2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold + consists of 198k lines of C++ code. + +- Link-time optimization (LTO) is supported by default. Essentially, + all you have to do to do LTO is to pass the ``-flto`` option to clang. + Then clang creates object files not in the native object file format + but in LLVM bitcode format. LLD reads bitcode object files, compile + them using LLVM and emit an output file. Because in this way LLD can + see the entire program, it can do the whole program optimization. + +- Some very old features for ancient Unix systems (pre-90s or even + before that) have been removed. Some default settings have been + tuned for the 21st century. For example, the stack is marked as + non-executable by default to tighten security. + +Performance +----------- + +This is a link time comparison on a 2-socket 20-core 40-thread Xeon +E5-2680 2.80 GHz machine with an SSD drive. + +LLD is much faster than the GNU linkers for large programs. That's +fast for small programs too, but because the link time is short +anyway, the difference is not very noticeable in that case. + +Note that this is just a benchmark result of our environment. +Depending on number of available cores, available amount of memory or +disk latency/throughput, your results may vary. + +============ =========== ============ ============= ====== +Program Output size GNU ld GNU gold [1]_ LLD +ffmpeg dbg 91 MiB 1.59s 1.15s 0.78s +mysqld dbg 157 MiB 7.09s 2.49s 1.31s +clang dbg 1.45 GiB 86.76s 21.93s 8.38s +chromium dbg 1.52 GiB 142.30s [2]_ 40.86s 12.69s +============ =========== ============ ============= ====== + +.. [1] With the ``--threads`` option to enable multi-threading support. + +.. [2] Since GNU ld doesn't support the ``-icf=all`` option, we + removed that from the command line for GNU ld. GNU ld would be + slower than this if it had that option support. For gold and + LLD, we use ``-icf=all``. + +Build +----- + +If you have already checked out LLVM using SVN, you can check out LLD +under ``tools`` directory just like you probably did for clang. For the +details, see `Getting Started with the LLVM System +`_. + +If you haven't checkout out LLVM, the easiest way to build LLD is to +checkout the entire LLVM projects/sub-projects from a git mirror and +build that tree. You need `cmake` and of course a C++ compiler. + +.. code-block:: console + + $ git clone https://github.com/llvm-project/llvm-project/ + $ mkdir build + $ cd build + $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm + $ make install + +Using LLD +--------- + +LLD is installed as ``ld.lld``. On Unix, linkers are invoked by +compiler drivers, so you are not expected to use that command +directly. There are a few ways to tell compiler drivers to use ld.lld +instead of the default linker. + +The easiest way to do that is to overwrite the default linker. After +installing LLD to somewhere on your disk, you can create a symbolic +link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that +``/usr/bin/ld`` is resolved to LLD. + +If you don't want to change the system setting, you can use clang's +``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to +LDFLAGS when building your programs. + +LLD leaves its name and version number to a ``.comment`` section in an +output. If you are in doubt whether you are successfully using LLD or +not, run ``readelf --string-dump .comment `` and examine the +output. If the string "Linker: LLD" is included in the output, you are +using LLD. + +History +------- + +Here is a brief project history of the ELF and COFF ports. + +- May 2015: We decided to rewrite the COFF linker and did that. + Noticed that the new linker is much faster than the MSVC linker. + +- July 2015: The new ELF port was developed based on the COFF linker + architecture. + +- September 2015: The first patches to support MIPS and AArch64 landed. + +- October 2015: Succeeded to self-host the ELF port. We have noticed + that the linker was faster than the GNU linkers, but we weren't sure + at the time if we would be able to keep the gap as we would add more + features to the linker. + +- July 2016: Started working on improving the linker script support. + +- December 2016: Succeeded to build the entire FreeBSD base system + including the kernel. We had widen the performance gap against the + GNU linkers. + +Internals +--------- + +For the internals of the linker, please read :doc:`NewLLD`. It is a bit +outdated but the fundamental concepts remain valid. We'll update the +document soon. + +.. toctree:: + :maxdepth: 1 + + NewLLD + AtomLLD + windows_support + ReleaseNotes diff --git a/docs/llvm-theme/layout.html b/docs/llvm-theme/layout.html new file mode 100644 index 000000000..0cd0918ea --- /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 0000000000000000000000000000000000000000..7fb82154a1748d507925865d3fbf7508d62483e5 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!3HGlw@oMq2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^HyC+E#mt?nx10eANtU=qlsM<-=BDPAFgO>bCYGe8D3oWG zWGJ|M`UZqI@`(c#nR~i8hHzY8+H1+jpulh_>fir3VfEN66+Lr739Q`5pWRz06>Sig9Kks4{%Sw0^VLi(+L0&(f>6FAU*Rd z03gU)3JWVJSlBt+Ia%1*6H5vU6Wcr5nOXiY1pxPzEM;>QKy4GyHGzs)55OS-jEZ5w)BuzhU@$~R<_`Q!12Dv{ z)p@RHt5FYWz?Mp@=V>A56b;aZ`|bd%u1-%#H6e*ji@|RA$uM1jzQ-dChdF>1W$R`P z0CM9n!P?%uxleqqo|s^d0e#m0e)0$AgVe}q_kDk|!d?IXww-;a-{}|{aQ(Sq{B7Rz zzg<9C=pp91JVct+qX;wtxyLK&H}?N*BbxWCWqEmjZ*NJePe|KvMBV4zyhp!F{q4t- zFVE}4-B#xgc>uF+fH>6SR?pb2OcDNMJp50iwS!pk*Cxb|SAtp6K1rh%4H}GHMKp&P zk@Tn=<|5K?p?K>4Z!;ezJDYSbkbIkLK&=%Ygjd}6Qe9)ndud8k4d`?%zP6VLqy_?t<_I{<*52sypVNCW>M8~}*q2GG87M>*GG0qSW56&cK)~9iXc3ZN|Czo=wfQrzJ<78o zTy{5AdjLF?;1C?TA<0S@gi(YBSqvO@TJR%Dw*(YgBsuYL7=|LLbR3%mlTw5Vv8n{Y zHLv3*&QKk();R7VfI09rq+OgTF`!_orAs;*^OqQ+g~`ZpM`3Z(QCe z_PoQX3Ja8#SU%xF#;&8Uuq=H)80iOkh3fvJgHJFXts|{Osu;knRjY(-3%@g-taF1x z3lQysXNPhVA~qxxl+cjTkXw={CB`Rb{jvhj0T208v4@g0p;Y=eMeCQRzOP2iOraVQ zbYu%?vFHq_USYz09OP)>!pxK{zdlLU6{^gj&4|s|Dv=%2m1VF>;F2W_ub5cZ!*V9l z5z`I@?`7@v?y>CQ?U7t-BV-u~I21lA?@%d?SV`gRqwcfr!W&TJ&kpb8@g(`o8q8cLd-ss;^+#v3zk1R+T( zi6RM)hC!vQytsU$98vW~byOv`Oi$UTT1=HidAAIHF1bRrJWJtJ8Bf`~jJq_n+`QCI zg}=~O^DP`kvsb29Ubs*(w@!bzeSjFz7^lIVj>HTO zyeyAXm_>?3y+P?F(TpE;!byq4KiwdI>@amMkyVT{V5VbrD`( zn~2*V+mega>`p!ZY#FCBm1J9r zsf)Q~xMc>%$Hw!=7t+`=c$pTN4>Jxk7Be=R47A*}=s=~QW>d-fJ*{HR3sAdluokCg zk%p?4Zi84=R@JwKwyL(0FC{H<333(L3+BDGSD;}~Srbm}{u0b;HOL0!V`y%KZQj&h z-FuPHk>Jzn6aB^uiyXTAxq?88z}M-wBLf{p3E(m>; zy3aC8Ib&Ab9NWCbDd;9FGF&=vls<)zJ_B!HeW+tk%K6SgciVI3E-RxUqvyPIwdR8T z!tx??EoY21hdNu6#c8T{NO((ef0`dLCyCK|v(i^ySU$kK@sNzcm?2KRYO%Jd$gTXr z@DiKvp3gC7mv5JcV}p4^Q-6%3t7)idRKC|PTR(VH*pKYP3#k3xnNXoiy)?8Y+zO3es>j##n9QWDw2o8)QPwW%g@0IzDEmF zu!aYQk-ff1l)<6F>LL6w_F)>h(@ZIBZqsYRPMadnBFQ2f8Rks#oHgI2*l765>8*HH zI9gd-`3LCDG{@#OvNR-rNaJ(T(^RwD{^;C%J--Rv$=X5O^}VN1d~G=y^35;U@&@n>=E zY#!wOEJbwtEk7yCeznUW%dBT`Wn-ng65BBIa&<5T#mD_}5Gp5;O#qpnm>-zAj#iom z*T47MMm8}JCczF{H~gxE*8GkD5-L7Y(V|+Ufvq<;RX6)H9zMdET#-#Xem>SPvigf7 z^D^h-9IXd!J04UNBCYjjBk43WW)1Se3b|#la)u)L+VCl*mC7Ka5lmGdNL|2Da*%~{%Or%H6P@4XgslL zg<^Nvit4;QBl;0}$lcC8p>y5rd|kh~kFMUVo?gSHZ*$^&!tqz-FG1|85MtM=yF5j+y zD{wBjEW92%&#(Qywsg7XXVvAFdo#Tz{s0pkH2EHP7mFec9h(+A8iE{hn*ARiC+7~o z2|7bY9AJO2Qu-@1nPpu2YoL z7AC!0wU_g5w>39{%Ysc5`8{u9KdKLlr@A}ksgjojoP>lAD9F^CS7Vm%tKfW-*jPeI z763fI0f2uH06cwwCb4z-rrlu{eZ1(r}&(F_Y{EM%y zu9Z|&kB^VF%;VYEIo8)VctuQp*w_V^FDx&w%+D`qY3URem5PXpB_^l+1~ogmdW?-v zWM=1y+m@Es4!gK}MMeKAE-mjL7{dPgHRe}BcTZnSTgT6k@QH~jDQTIZ;gPz!`h|tX zzW#y0prEa-t?JtP+q*|cXBT%*pO24^{e#2gl=Rov*V6LJ)by<3k+F@9&D#3kzgwq# z{ep7yi@ZyhZS5WX1A}Gd6zYbKI@&u!!Xke+HaU5v+B-V;^bO?Y=bM;X@To-U8yFe< zNH43buKx`JHMhwrDn}&zwsOvDZfRRtS&fTN{PioYv#ZD2)O2QMHt=U?@UIe^oVlHy zT@Pm$Pj6opHI4Yhl-Bl6V?8}{3oGxSEPE@f@SnlurDZF7cZo?UJG*-$V-rLD18GUg z{$Aesg(WHx{aPxj>Ka;ESvj~QwCNey-adW4g2JVRh26dVx|&)sN$Hu%sgsjaCQjd@ zqoaoUdJ+n5UT)se;gQ{)-T2sFaVeGCTiZ>IjjJmwgQKfsqho(M|7>n-rl+K05>Q6Q zX0*4p2glUNh)YC;h7sc7lM|B&2nfzC?LouBU0(h@IlcPRx3IZ=Ix?}ox4U+xPeK@9pjFRoqw3GW>Lu#X((?0+K>uDf-h>Jn=fj)a0nX&=NudNWbEt7jnDe0W4B}5PP`N zs_2T6C8SESv9o)bhIXW_L)E&AskL9zy8y;{dE|Xn1-v9GrfL5|tM;f@XXl28-`Z<4 zJiJBSK=5~+v3SUlzmmHy0l*C z49;FeM|FZ@&7%pS-F*goC_bA~=(b<@%dLI5Aq2%*=oj#YJQFk4$w=M z7nC2P<8wzWh^OOS!NbgKH>~2hJkM)^UG2SBrLqgFk-aD#PS?97gqzH$iD_wR zk~L{WTyS@V07uYQmq+lMhn(-nK!fBbrtyRIX}+Rk@Ier z&>8v8r{yO%^}zu!#3;wn*E=-^*T>w~ka-8r@^=0U>|5i$tx}B82+FGx>^?L%7iTYP z8Kp(1oqtL{qh#1kHq~u$eHzQjS$pa`)$X*25?ww$47J^C`lMSC+8X+k>E4v!Xoorx z=K;YdmUZD*nT6-VrDlg-PC~-$W)4BiUjGc)afa(h z`t-)xZ zDViiH4<4+FePomVJqe%9qSIzm%~5+bK?SL#WUc*KsVuo==q4-)(!=oVZ827MmS$m+ z^MGjCa~!Fkz(KUHthgPQ&ktfBX2Zebee;Tnf(Y6^5z@F)CCQ?8j$fF^Wa~aDLiVHe z$+EJ0){T5)YG$0u(%+>5#6!2wJn~nOJ@OK6^387}>96FGPKXXdH+24X%TcBI$e^b1 zr3r9$czYPRnAXWqU`2+DKQj9hEd&@$;>>us_css2tXlZE+@@c9`M}~DQ-1O|>E>0_VdOn4BPpyig z(2zYbHqKJFiRG*^+TDt3h&PQ03-!cg2XMC0|E_wvjG@;Zj{MJ|n8Apnpp8(vcKD~(W}`Jac+A+Oe$mE@ZrSjkyM1({7ojjk8eeR4 zTdjt@JiP~I-M8iIzidH{DEz(h*=BbwHAc_ijrWq7B23|vEUUV^>xiH$!~Ag)v(&^2 zl`Ax%a?Cs4+cSpuuU*zzDRZQN^&Buoq z%7wfk!wLG_0fmfq2kJ-IbQ5Kj=q6Fw?k*;Bu+5Pb!vnSF1wXC1G2-vw5~naGrV~;5 zCys`OV`y_vS8u{2J0DaRJU1`vp)IHpJ@hYi+~2=PcN;Kzww|8m?H%ZRswY?Mx+vWw zi0g`Xx?ScfSqZ|GTq_Tn#2o8kH#ScIZ@jKB< zy}MTUTf|1m9%^^Wt&08yjOpd&7VhY2UllFm!wT}%GX2I+4vq?qhfO%1ZAa0^ zxy7%}t)?~eTC$^2itfT$W?BAe8GA8%HIsg8C)^dA`o!b~cDwL)wic77u z_oA9wSh!Nu3R@jMK6tO;tre@z9@vX?h-y5+$Z{RSE{neA78Ke^%Qew;+4X(2wQdY- zizWUVKR#!c$C)c$O1Us_Ah3|vlO4T5X^$e7Ffd1%qmz*TD;rggT41$!)e=$ILmpC9 z@b=p^>Vc$rumoE-Gl7FiERFEe4$f9w>umVWcG_XuJ>V|gFL`~3fgxK1x81Kdoz42b za#>mVWe}E#$NLci3jX}eWX_EhQOe4vBGOcZdNg)+v+r;xp-?%d8h52br^bXTt1N}H zZ>gdIX)=Jm`&(zXC)6Yd_r{b%JPMj^$XfQuNUKBtznNs)yU7bL>h6Bw&_TGge7f^% zzmGKcb#aHtf6ZyP$%=a3Tf3Ls?4!a_9Eo>wBz4jG^T*&B;l?qN87l&33*RWpu<{z~ z%(OYA!G@+E`=a?a4D{W;%hVHjGB4yS&z-L1&BCC13PWhh}uu~42S zJsU68=qJ9rHarTTOmi3O)M~cRyzyBLL|2L5WBJomwDV^MDA8`M05ytQN1ff>IkuDH+C>ryug!X67WTBnO}KR&w*If5G})Qu9<_JeJ-aM|0n=_rrB)$`^yT!_{UV_wTM4hxgrT!ssTa>rsNT7ln|m z{QA&yWO>;~-M69Myoyi4)9Bly3}j)B({uH-&9$fKc-K}l3PIQbL>$lB(L{gTuFtp! z*490X*9TI?pM8;b7+IsLEtB z?=rZg(_{`1k2cGM49hUd8j2C-t8diGVZdi3YQ`JkKZOiwKxjo6H^j~v?s*DSeVqkx z!9o^lw{j=ScJKE?h}_w0w}iL-D)Fd+i0RX{Bh`}mITp}UC@DCdGafp zS2#%IrY1Jn-Ff$}clv{Zgry%Md&s_mJ@^=Yyt%oGu;oT6C_=){?~cl6U5^YCQ1mXV zSi`M>0R-rco2JMCfNgw7%&MO~n_&GM2kR4{Nql)!vH0iZIVbx+d&j4}I^n2`Vh!1@ zNCY1Jl&Zra4;lwiQ==joI;_b4@bPWDdsx^@eKLd^$%@c)=x>c94<#$sYjrj9_p_t# zfBVJt_xNLpO>1zY2O+}u)Wl`Mh8D;-f~}^21cr((jsUC)NP@Az4X2COk{q9#J}=72 zPL|qZiOUf^Szlqa?25>-?IEy%D}{6vGd}OLQ;K|11^1di?y+h$<4Fu6rr)N?e|@WO zZyYDpmS9QZs8_CHqRQsAzwW}LO$IwM9SKf!P0*tXhjTfU3!ou`7#0eMz+hFhEht}N z=*s3P=uB6UFST{sc|Tu$m-o3nu#0W4H5OMQ>!{#h$z_C}+~>G+deu-ORXo6>G!V}6 z@vwe&EGVSeJeZjH?HQJ}%BT7AHISI;BMCE}ZuhEaSu*&fxasrRlCwqOP7M`DAhGnx zJ#N$F*8<%*45ZefPo-$Yam^}N@#|`*XGg4G2SyAd`-K`jMK|j&j!~Mtul5HSiY~k( z<*W*^C6H`_B@wE}cZ%vy`b0K=Itz+xZKS`wSWESZIG74~dFcq9uULHxBnB@OcP!lZ zU`_r%X?W;gBcgLt=GK{&0$!A0RWM2tqZ|gY6r^BGh6vW@#W$)@tU`iOVJt2eVnP7SH%J_?EeZ&a3*V}s?SNV;Qt&A6Lv~Z&|88t;k zoiiQ}=z+ezzSp3?f1|=)pSTjPFt?0c06+oP4jKSb_X2Gj6XSIueqJD7dRA3fZcKeB zG`*eIO!z%7b8IFmYWs|g1|HFRu|VQm9hMb}BzBO?{aV%0ccOkg7`Ji2G^*2}Xp0!r z&DJ+(#SNg++X)dM(}YkMH0Ch;3Rtz{0$L{>BB8a_kdb`$wr@?bd~c7*3?PNbQY|x1 ztEoCzf0h4RXuv30}!z1K{6Js zvgeVZ5Vln)!_fqY9I~x+Ia!MeU}Hy$>Z>=sub$iaHJiRv>r&5ZmGmDT?zVXA zf{4T?gqAB7pOw(0W@dMHW)jE(Q{<3j3zOCY7IHS_*m29i1<8DcN_te%2x~fuKmfo1 z0CGn!&VuA#1u6^#5cY$)#NGk{jE_O9?b|cB3(@@O9%|9jehwH>C(fM+E1Vi?rJANX zbrDs{>bt6{B64yCD{J(n{0#I+{!OBoO7aT@ORH#<$rrJmTIw`8gv?NFz-96_e(}t$loa7OQ0|tD~;ZQIUOo*PmZP z&HDYW&O5{k97a)4eYWOZ3R~|^#fQBtdkfl>iX)E@RIB046P`o=y0E)aE7B#XVu-7% z{eu{$`cR)pQsvJt^>^&HR;Mp0&}cjX48wk}m<7`oYfq3OHOAH2>gsNzA{$=d;l(B& z78*B{8!)BRM4l}=?S1Ddi;%z=HNgbqD3&IShPt9ZmaJM9@Ai))87=MUpUn^LG15=n zwvZ#CM684C0?nWWF-rKL(+Pu{vFpzK~Ss|HV*O1V;*ic(qPpwaN#fA~JGg)y78@hTU) zyS+bb?ks7?Chb@x5CThke`|XUQ((M(%h1PC1b{9n2tdG99f^~-ey9#o03&W)SD8u; zpaP9|pPT`JL6L$8pkXtAmW_{=*9LELIy}F>I?d2g@31@2L6Ix=+QBg{2q+6E}sh5$5OQtRO z{s-$t(>x}M#7NqXySdbzFLwN zxj;AL_@~}lUVH%*YgX+sgAYQt+nX9WyLMCNw5Z-plGuYd{nWxPrzb026W5sR-tEVy z;eE#zor}Z4ZTnl!eyE%vuyJ#-4Z7YxvnYRqD>) z7I8{x81!p4{sb$PYvSyy^ACkXob`RLwW&?7{dsMQgt$GnH2m!4Wc^f=phY%OGxLYT zy??mbJGihUlF9Ka#TyG71-S;cI)Hp1k?=s}_#utoU*!4;`-%M3v|oM-EpA ze$co&3y`%~W(fsYf&;hJ7X(SH3>LN3>m+t(+;2%|2M3H5J?O3Jq~X{e^UraH%2L;r zyXUmOZgH7cuMz*LfWSjI>4L#SSffDBhLNnUTGzdvt4!B}17nv50Hw7GR8dWbc{a~( zxZdT^OOrWeCg$akkueAD7DXUe);#rF@!_7b1`X_jaK? z2`MQns<9LmOtyeFAy_o`kc^;UK;t_&qQZ}}g$Fq}VMUBT6)+=+owMI6)nfufr1h%V zaZ}Fuu@|XMU4qV@DTN#hxt54S40Jy%Bpee%LV9{$0px~Kz%AuStzH~O9~TASvZvJ~ z{kcmbPe@p(B_Z@x7L+ug94u50m$6k47mUWrZtv-?L4`4~wCHs}Xs>CE+L0?ggJ(T7 z_Zxce5SvTN*H<8eA|X4!qt}a4s%&=$3hfghMSVYtxhhV>#YX}K?6nsQ)}S*+i&_op zMm5g)GLY3*EI8zlVJ!1W1!qrP=2DH|1|8i7(o5RabpI-w{@n--^$))-!F596%EFT^ z$G^KYZc)_?l*?P{Ql4JM$S^@9;6moC0b}35y%hPFZbkQ7gxnQ1WgM94$1R#9gBJL= zj>3xEAL^(Vo#5Rpv*P1GE-_b@o`S;E{6DBFCOLPE1J{8NtO1 z3Jg5DN5jCFb4RU)ePDWaEXN9F0P~LEG6g%^J5x62OhZ_vm(PQk)A*=53lfR&`-5Ka zd~zEt(xv7>|DJ-e59(QCdxmJ9obE>DC@TH;%1T>XI}OCl`%L!j&*;a5*ZJAWLVo_S zCAg+GZ`G(}GhaQe2>nQ%3kh^hb!k^17v>)y=O+d+$|wnJQ3m;LCjP60f8e~8D8AbP Z?KG8a2Cm$O;IlqJQdCZ)TF4;q{{RiG|G@wN literal 0 HcmV?d00001 diff --git a/docs/llvm-theme/static/navigation.png b/docs/llvm-theme/static/navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..1081dc1439fb984dfa7ef627afe3c7dc476fdbce GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI|!3HFkf4uMuBv2gW?!>U}oXkrghqJ&VvY3H^ zTNs2H8D`Cq01C2~c>21s-(chw7$R|bZ|_0D0|q>YSbqDzW^|HYIk%*-&O)*` 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 000000000..eeb9f9f48 --- /dev/null +++ b/docs/open_projects.rst @@ -0,0 +1,11 @@ +.. _open_projects: + +Open Projects +============= + +.. include:: ../include/lld/Core/TODO.txt + +Documentation TODOs +~~~~~~~~~~~~~~~~~~~ + +.. todolist:: diff --git a/docs/sphinx_intro.rst b/docs/sphinx_intro.rst new file mode 100644 index 000000000..6845bc812 --- /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 000000000..6b06d29af --- /dev/null +++ b/docs/windows_support.rst @@ -0,0 +1,91 @@ +.. raw:: html + + + +.. role:: none +.. role:: partial +.. role:: good + +=============== +Windows support +=============== + +LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with +``-flavor link``, the driver for Windows operating system is used to parse +command line options, and it drives further linking processes. LLD accepts +almost all command line options that the linker shipped with Microsoft Visual +C++ (link.exe) supports. + +The current status is that LLD can link itself on Windows x86/x64 +using Visual C++ 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. + +Linking against DLL + :good:`Done`. LLD can read import libraries needed to link against DLL. Both + export-by-name and export-by-ordinal are supported. + +Linking against static library + :good:`Done`. The format of static library (.lib) on Windows is actually the + same as on Unix (.a). LLD can read it. + +Creating DLL + :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported + functions can be specified either via command line (``/EXPORT``) or via + module-definition file (.def). Both export-by-name and export-by-ordinal are + supported. + +Windows resource files support + :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF + file using LLVM's Object library. + +Safe Structured Exception Handler (SEH) + :good:`Done` for both x86 and x64. + +Module-definition file + :partial:`Partially done`. LLD currently recognizes these directives: + ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. + +Debug info + :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`` diff --git a/include/lld/Config/Version.h b/include/lld/Config/Version.h new file mode 100644 index 000000000..1cec3cc76 --- /dev/null +++ b/include/lld/Config/Version.h @@ -0,0 +1,25 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// +// +// Defines a version-related utility function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_VERSION_H +#define LLD_VERSION_H + +#include "lld/Config/Version.inc" +#include "llvm/ADT/StringRef.h" + +namespace lld { +/// \brief Retrieves a string representing the complete lld version. +std::string 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 000000000..2789a5c46 --- /dev/null +++ b/include/lld/Config/Version.inc.in @@ -0,0 +1,6 @@ +#define LLD_VERSION @LLD_VERSION@ +#define LLD_VERSION_STRING "@LLD_VERSION@" +#define LLD_VERSION_MAJOR @LLD_VERSION_MAJOR@ +#define LLD_VERSION_MINOR @LLD_VERSION_MINOR@ +#define LLD_REVISION_STRING "@LLD_REVISION@" +#define LLD_REPOSITORY_STRING "@LLD_REPOSITORY@" diff --git a/include/lld/Core/AbsoluteAtom.h b/include/lld/Core/AbsoluteAtom.h new file mode 100644 index 000000000..ed25297ce --- /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/ArchiveLibraryFile.h b/include/lld/Core/ArchiveLibraryFile.h new file mode 100644 index 000000000..2c736e7d6 --- /dev/null +++ b/include/lld/Core/ArchiveLibraryFile.h @@ -0,0 +1,47 @@ +//===- Core/ArchiveLibraryFile.h - Models static library ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H +#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H + +#include "lld/Core/File.h" +#include + +namespace lld { + +/// +/// The ArchiveLibraryFile subclass of File is used to represent unix +/// static library archives. These libraries provide no atoms to the +/// initial set of atoms linked. Instead, when the Resolver will query +/// ArchiveLibraryFile instances for specific symbols names using the +/// find() method. If the archive contains an object file which has a +/// DefinedAtom whose scope is not translationUnit, then that entire +/// object file File is returned. +/// +class ArchiveLibraryFile : public File { +public: + static bool classof(const File *f) { + return f->kind() == kindArchiveLibrary; + } + + /// Check if any member of the archive contains an Atom with the + /// specified name and return the File object for that member, or nullptr. + virtual File *find(StringRef name) = 0; + + virtual std::error_code + parseAllMembers(std::vector> &result) = 0; + +protected: + /// only subclasses of ArchiveLibraryFile can be instantiated + ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {} +}; + +} // namespace lld + +#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h new file mode 100644 index 000000000..156a5d4a7 --- /dev/null +++ b/include/lld/Core/Atom.h @@ -0,0 +1,131 @@ +//===- Core/Atom.h - A node in linking graph --------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ATOM_H +#define LLD_CORE_ATOM_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace lld { + +class File; + +template +class OwningAtomPtr; + +/// +/// The linker has a Graph Theory model of linking. An object file is seen +/// as a set of Atoms with References to other Atoms. Each Atom is a node +/// and each Reference is an edge. An Atom can be a DefinedAtom which has +/// content or a UndefinedAtom which is a placeholder and represents an +/// undefined symbol (extern declaration). +/// +class Atom { + template friend class OwningAtomPtr; + +public: + /// Whether this atom is defined or a proxy for an undefined symbol + enum Definition { + definitionRegular, ///< Normal C/C++ function or global variable. + definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content. + definitionUndefined, ///< Only in .o files to model reference to undef. + definitionSharedLibrary ///< Only in shared libraries to model export. + }; + + /// The scope in which this atom is acessible to other atoms. + enum Scope { + scopeTranslationUnit, ///< Accessible only to atoms in the same translation + /// unit (e.g. a C static). + scopeLinkageUnit, ///< Accessible to atoms being linked but not visible + /// to runtime loader (e.g. visibility=hidden). + scopeGlobal ///< Accessible to all atoms and visible to runtime + /// loader (e.g. visibility=default). + }; + + /// file - returns the File that produced/owns this Atom + virtual const File& file() const = 0; + + /// name - The name of the atom. For a function atom, it is the (mangled) + /// name of the function. + virtual StringRef name() const = 0; + + /// definition - Whether this atom is a definition or represents an undefined + /// symbol. + Definition definition() const { return _definition; } + + static bool classof(const Atom *a) { return true; } + +protected: + /// Atom is an abstract base class. Only subclasses can access constructor. + explicit Atom(Definition def) : _definition(def) {} + + /// The memory for Atom objects is always managed by the owning File + /// object. Therefore, no one but the owning File object should call + /// delete on an Atom. In fact, some File objects may bulk allocate + /// an array of Atoms, so they cannot be individually deleted by anyone. + virtual ~Atom() = default; + +private: + Definition _definition; +}; + +/// Class which owns an atom pointer and runs the atom destructor when the +/// owning pointer goes out of scope. +template +class OwningAtomPtr { +private: + OwningAtomPtr(const OwningAtomPtr &) = delete; + void operator=(const OwningAtomPtr &) = delete; + +public: + OwningAtomPtr() = default; + OwningAtomPtr(T *atom) : atom(atom) { } + + ~OwningAtomPtr() { + if (atom) + runDestructor(atom); + } + + void runDestructor(Atom *atom) { + atom->~Atom(); + } + + OwningAtomPtr(OwningAtomPtr &&ptr) : atom(ptr.atom) { + ptr.atom = nullptr; + } + + void operator=(OwningAtomPtr&& ptr) { + if (atom) + runDestructor(atom); + atom = ptr.atom; + ptr.atom = nullptr; + } + + T *const &get() const { + return atom; + } + + T *&get() { + return atom; + } + + T *release() { + auto *v = atom; + atom = nullptr; + return v; + } + +private: + T *atom = nullptr; +}; + +} // end namespace lld + +#endif // LLD_CORE_ATOM_H diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h new file mode 100644 index 000000000..7f623d2ea --- /dev/null +++ b/include/lld/Core/DefinedAtom.h @@ -0,0 +1,374 @@ +//===- Core/DefinedAtom.h - An Atom with content --------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_DEFINED_ATOM_H +#define LLD_CORE_DEFINED_ATOM_H + +#include "lld/Core/Atom.h" +#include "lld/Core/Reference.h" +#include "lld/Core/LLVM.h" +#include "llvm/Support/ErrorHandling.h" + +namespace lld { +class File; + +/// \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 + typeMachHeader, // atom representing mach_header [Darwin] + typeCode, // executable code + typeResolver, // function which returns address of target + typeBranchIsland, // linker created for large binaries + typeBranchShim, // linker created to switch thumb mode + typeStub, // linker created for calling external function + typeStubHelper, // linker created for initial stub binding + typeConstant, // a read-only constant + typeCString, // a zero terminated UTF8 C string + typeUTF16String, // a zero terminated UTF16 string + typeCFI, // a FDE or CIE from dwarf unwind info + typeLSDA, // extra unwinding info + typeLiteral4, // a four-btye read-only constant + typeLiteral8, // an eight-btye read-only constant + typeLiteral16, // a sixteen-btye read-only constant + typeData, // read-write data + typeDataFast, // allow data to be quickly accessed + typeZeroFill, // zero-fill data + typeZeroFillFast, // allow zero-fill data to be quicky accessed + typeConstData, // read-only data after dynamic linker is done + typeObjC1Class, // ObjC1 class [Darwin] + typeLazyPointer, // pointer through which a stub jumps + typeLazyDylibPointer, // pointer through which a stub jumps [Darwin] + typeNonLazyPointer, // pointer to external symbol + typeCFString, // NS/CFString object [Darwin] + typeGOT, // pointer to external symbol + typeInitializerPtr, // pointer to initializer function + typeTerminatorPtr, // pointer to terminator function + typeCStringPtr, // pointer to UTF8 C string [Darwin] + typeObjCClassPtr, // pointer to ObjC class [Darwin] + typeObjC2CategoryList, // pointers to ObjC category [Darwin] + typeObjCImageInfo, // pointer to ObjC class [Darwin] + typeObjCMethodList, // pointer to ObjC method list [Darwin] + typeDTraceDOF, // runtime data for Dtrace [Darwin] + typeInterposingTuples, // tuples of interposing info for dyld [Darwin] + typeTempLTO, // temporary atom for bitcode reader + typeCompactUnwindInfo, // runtime data for unwinder [Darwin] + typeProcessedUnwindInfo,// compressed compact unwind info [Darwin] + typeThunkTLV, // thunk used to access a TLV [Darwin] + typeTLVInitialData, // initial data for a TLV [Darwin] + typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin] + typeTLVInitializerPtr, // pointer to thread local initializer [Darwin] + typeDSOHandle, // atom representing DSO handle [Darwin] + typeSectCreate, // Created via the -sectcreate option [Darwin] + }; + + // Permission bits for atoms and segments. The order of these values are + // important, because the layout pass may sort atoms by permission if other + // attributes are the same. + enum ContentPermissions { + perm___ = 0, // mapped as unaccessible + permR__ = 8, // mapped read-only + permRW_ = 8 + 2, // mapped readable and writable + permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only + // loader writable + permR_X = 8 + 4, // mapped readable and executable + permRWX = 8 + 2 + 4, // mapped readable and writable and executable + permUnknown = 16 // unknown or invalid permissions + }; + + enum SectionChoice { + sectionBasedOnContent, // linker infers final section based on content + sectionCustomPreferred, // linker may place in specific section + sectionCustomRequired // linker must place in specific section + }; + + enum DeadStripKind { + deadStripNormal, // linker may dead strip this atom + deadStripNever, // linker must never dead strip this atom + deadStripAlways // linker must remove this atom if unused + }; + + enum DynamicExport { + /// \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 + // MIPS code models + codeMipsPIC, // PIC function in a PIC / non-PIC mixed file + codeMipsMicro, // microMIPS instruction encoding + codeMipsMicroPIC, // microMIPS instruction encoding + PIC + codeMips16, // MIPS-16 instruction encoding + // ARM code models + codeARMThumb, // ARM Thumb instruction set + codeARM_a, // $a-like mapping symbol (for ARM code) + codeARM_d, // $d-like mapping symbol (for data) + codeARM_t, // $t-like mapping symbol (for Thumb code) + }; + + struct Alignment { + Alignment(int v, int m = 0) : value(v), modulus(m) {} + + uint16_t value; + uint16_t modulus; + + bool operator==(const Alignment &rhs) const { + return (value == rhs.value) && (modulus == rhs.modulus); + } + }; + + /// \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. + 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; + } + + bool operator!=(const reference_iterator &other) const { + return !(*this == other); + } + + reference_iterator &operator++() { + _atom.incrementIterator(_it); + return *this; + } + private: + const DefinedAtom &_atom; + const void *_it; + }; + + /// \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; + + /// Adds a reference to this atom. + virtual void addReference(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t off, + const Atom *target, Reference::Addend a) { + llvm_unreachable("Subclass does not permit adding references"); + } + + static bool classof(const Atom *a) { + return a->definition() == definitionRegular; + } + + /// Utility for deriving permissions from content type + static ContentPermissions permissions(ContentType type); + + /// Utility function to check if the atom occupies file space + bool occupiesDiskSpace() const { + ContentType atomContentType = contentType(); + return !(atomContentType == DefinedAtom::typeZeroFill || + atomContentType == DefinedAtom::typeZeroFillFast || + atomContentType == DefinedAtom::typeTLVInitialZeroFill); + } + + /// Utility function to check if relocations in this atom to other defined + /// atoms can be implicitly generated, and so we don't need to explicitly + /// emit those relocations. + bool relocsToDefinedCanBeImplicit() const { + ContentType atomContentType = contentType(); + return atomContentType == typeCFI; + } + +protected: + // DefinedAtom is an abstract base class. Only subclasses can access + // constructor. + DefinedAtom() : Atom(definitionRegular) { } + + ~DefinedAtom() override = default; + + /// \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 000000000..b0bf73b1c --- /dev/null +++ b/include/lld/Core/Error.h @@ -0,0 +1,68 @@ +//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the lld library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ERROR_H +#define LLD_CORE_ERROR_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" +#include + +namespace lld { + +const std::error_category &YamlReaderCategory(); + +enum class YamlReaderError { + unknown_keyword, + illegal_value +}; + +inline std::error_code make_error_code(YamlReaderError e) { + return std::error_code(static_cast(e), YamlReaderCategory()); +} + +/// Creates an error_code object that has associated with it an arbitrary +/// error messsage. The value() of the error_code will always be non-zero +/// but its value is meaningless. The messsage() will be (a copy of) the +/// supplied error string. +/// Note: Once ErrorOr<> is updated to work with errors other than error_code, +/// this can be updated to return some other kind of error. +std::error_code make_dynamic_error_code(StringRef msg); + +/// Generic error. +/// +/// For errors that don't require their own specific sub-error (most errors) +/// this class can be used to describe the error via a string message. +class GenericError : public llvm::ErrorInfo { +public: + static char ID; + GenericError(Twine Msg); + const std::string &getMessage() const { return Msg; } + void log(llvm::raw_ostream &OS) const override; + + std::error_code convertToErrorCode() const override { + return make_dynamic_error_code(getMessage()); + } + +private: + std::string Msg; +}; + +} // end namespace lld + +namespace std { +template <> struct is_error_code_enum : std::true_type {}; +} + +#endif diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h new file mode 100644 index 000000000..20418688d --- /dev/null +++ b/include/lld/Core/File.h @@ -0,0 +1,278 @@ +//===- Core/File.h - A Container of Atoms ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_FILE_H +#define LLD_CORE_FILE_H + +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include +#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 { + kindErrorObject, ///< a error object file (.o) + kindNormalizedObject, ///< a normalized file (.o) + kindMachObject, ///< a MachO object file (.o) + kindCEntryObject, ///< a file for CEntries + kindHeaderObject, ///< a file for file headers + kindEntryObject, ///< a file for the entry + kindUndefinedSymsObject, ///< a file for undefined symbols + kindStubHelperObject, ///< a file for stub helpers + kindResolverMergedObject, ///< the resolver merged file. + kindSectCreateObject, ///< a sect create object file (.o) + kindSharedLibrary, ///< shared library (.so) + kindArchiveLibrary ///< archive (.a) + }; + + /// \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; } + + /// Returns the ordinal for the next atom to be defined in this file. + uint64_t getNextAtomOrdinalAndIncrement() const { + return _nextAtomOrdinal++; + } + + /// For allocating any objects owned by this File. + llvm::BumpPtrAllocator &allocator() const { + return _allocator; + } + + /// The type of atom mutable container. + template using AtomVector = std::vector>; + + /// The range type for the atoms. + template class AtomRange { + public: + AtomRange(AtomVector &v) : _v(v) {} + AtomRange(const AtomVector &v) : _v(const_cast &>(v)) {} + + typedef std::pointer_to_unary_function&, + const T*> ConstDerefFn; + + typedef std::pointer_to_unary_function&, T*> DerefFn; + + typedef llvm::mapped_iterator::const_iterator, + ConstDerefFn> ConstItTy; + typedef llvm::mapped_iterator::iterator, + DerefFn> ItTy; + + static const T* DerefConst(const OwningAtomPtr &p) { + return p.get(); + } + + static T* Deref(OwningAtomPtr &p) { + return p.get(); + } + + ConstItTy begin() const { + return ConstItTy(_v.begin(), ConstDerefFn(DerefConst)); + } + ConstItTy end() const { + return ConstItTy(_v.end(), ConstDerefFn(DerefConst)); + } + + ItTy begin() { + return ItTy(_v.begin(), DerefFn(Deref)); + } + ItTy end() { + return ItTy(_v.end(), DerefFn(Deref)); + } + + llvm::iterator_range::iterator> owning_ptrs() { + return llvm::make_range(_v.begin(), _v.end()); + } + + llvm::iterator_range::iterator> owning_ptrs() const { + return llvm::make_range(_v.begin(), _v.end()); + } + + bool empty() const { + return _v.empty(); + } + + size_t size() const { + return _v.size(); + } + + const OwningAtomPtr &operator[](size_t idx) const { + return _v[idx]; + } + + OwningAtomPtr &operator[](size_t idx) { + return _v[idx]; + } + + private: + AtomVector &_v; + }; + + /// \brief Must be implemented to return the AtomVector object for + /// all DefinedAtoms in this File. + virtual const AtomRange defined() const = 0; + + /// \brief Must be implemented to return the AtomVector object for + /// all UndefinedAtomw in this File. + virtual const AtomRange undefined() const = 0; + + /// \brief Must be implemented to return the AtomVector object for + /// all SharedLibraryAtoms in this File. + virtual const AtomRange sharedLibrary() const = 0; + + /// \brief Must be implemented to return the AtomVector object for + /// all AbsoluteAtoms in this File. + virtual const AtomRange absolute() const = 0; + + /// Drop all of the atoms owned by this file. This will result in all of + /// the atoms running their destructors. + /// This is required because atoms may be allocated on a BumpPtrAllocator + /// of a different file. We need to destruct all atoms before any files. + virtual void clearAtoms() = 0; + + /// \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(); + + // 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), + _nextAtomOrdinal(0) {} + + /// \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(); } + + static AtomVector _noDefinedAtoms; + static AtomVector _noUndefinedAtoms; + static AtomVector _noSharedLibraryAtoms; + static AtomVector _noAbsoluteAtoms; + mutable llvm::BumpPtrAllocator _allocator; + +private: + StringRef _path; + std::string _archivePath; + mutable std::string _archiveMemberPath; + Kind _kind; + mutable uint64_t _ordinal; + mutable uint64_t _nextAtomOrdinal; + std::shared_ptr _sharedMemoryBuffer; + llvm::Optional _lastError; + std::mutex _parseMutex; +}; + +/// An ErrorFile represents a file that doesn't exist. +/// If you try to parse a file which doesn't exist, an instance of this +/// class will be returned. That's parse method always returns an error. +/// This is useful to delay erroring on non-existent files, so that we +/// can do unit testing a driver using non-existing file paths. +class ErrorFile : public File { +public: + ErrorFile(StringRef path, std::error_code ec) + : File(path, kindErrorObject), _ec(ec) {} + + std::error_code doParse() override { return _ec; } + + const AtomRange defined() const override { + llvm_unreachable("internal error"); + } + const AtomRange undefined() const override { + llvm_unreachable("internal error"); + } + const AtomRange sharedLibrary() const override { + llvm_unreachable("internal error"); + } + const AtomRange absolute() const override { + llvm_unreachable("internal error"); + } + + void clearAtoms() override { + } + +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 000000000..162375905 --- /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 000000000..ccf08859f --- /dev/null +++ b/include/lld/Core/LLVM.h @@ -0,0 +1,83 @@ +//===--- 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 Error; + class StringRef; + class Twine; + class MemoryBuffer; + class MemoryBufferRef; + template class ArrayRef; + template class SmallString; + template class SmallVector; + template class SmallVectorImpl; + + template + struct SaveAndRestore; + + template + class ErrorOr; + + template + class Expected; + + 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::Error; + using llvm::StringRef; + using llvm::Twine; + using llvm::MemoryBuffer; + using llvm::MemoryBufferRef; + using llvm::ArrayRef; + using llvm::SmallString; + using llvm::SmallVector; + using llvm::SmallVectorImpl; + using llvm::SaveAndRestore; + using llvm::ErrorOr; + using llvm::Expected; + + 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 000000000..b3a999b00 --- /dev/null +++ b/include/lld/Core/LinkingContext.h @@ -0,0 +1,258 @@ +//===- lld/Core/LinkingContext.h - Linker Target Info Interface -*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_LINKING_CONTEXT_H +#define LLD_CORE_LINKING_CONTEXT_H + +#include "lld/Core/Node.h" +#include "lld/Core/Reader.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#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. +class LinkingContext { +public: + virtual ~LinkingContext(); + + /// \name Methods needed by core linking + /// @{ + + /// Name of symbol linker should use as "entry point" to program, + /// usually "main" or "start". + virtual StringRef entrySymbolName() const { return _entrySymbolName; } + + /// Whether core linking should remove Atoms not reachable by following + /// References from the entry point Atom or from all global scope Atoms + /// if globalsAreDeadStripRoots() is true. + bool deadStrip() const { return _deadStrip; } + + /// Only used if deadStrip() returns true. Means all global scope Atoms + /// should be marked live (along with all Atoms they reference). Usually + /// this method returns false for main executables, but true for dynamic + /// shared libraries. + bool globalsAreDeadStripRoots() const { return _globalsAreDeadStripRoots; } + + /// Only used if deadStrip() returns true. This method returns the names + /// of DefinedAtoms that should be marked live (along with all Atoms they + /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can + /// be kept live using this method. + 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); + } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking prints out a list of remaining UndefinedAtoms. + /// + /// \todo This should be a method core linking calls with a list of the + /// UndefinedAtoms so that different drivers can format the error message + /// as needed. + bool printRemainingUndefines() const { return _printRemainingUndefines; } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines to be an error. + bool allowRemainingUndefines() const { return _allowRemainingUndefines; } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines from the shared library + /// to be an error. + bool allowShlibUndefines() const { return _allowShlibUndefines; } + + /// If true, core linking will write the path to each input file to stdout + /// (i.e. llvm::outs()) as it is used. This is used to implement the -t + /// linker option. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the line as needed. + bool logInputFiles() const { return _logInputFiles; } + + /// Parts of LLVM use global variables which are bound to command line + /// options (see llvm::cl::Options). This method returns "command line" + /// options which are used to configure LLVM's command line settings. + /// For instance the -debug-only XXX option can be used to dynamically + /// trace different parts of LLVM and lld. + 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 setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; } + + void setPrintRemainingUndefines(bool print) { + _printRemainingUndefines = print; + } + + void setAllowRemainingUndefines(bool allow) { + _allowRemainingUndefines = allow; + } + + void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; } + void setLogInputFiles(bool log) { _logInputFiles = log; } + + void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); } + + std::vector> &getNodes() { return _nodes; } + const std::vector> &getNodes() const { return _nodes; } + + /// This method adds undefined symbols specified by the -u option to the to + /// the list of undefined symbols known to the linker. This option essentially + /// forces an undefined symbol to be created. You may also need to call + /// addDeadStripRoot() for the symbol if your platform supports dead + /// stripping, so that the symbol will not be removed from the output. + void addInitialUndefinedSymbol(StringRef symbolName) { + _initialUndefinedSymbols.push_back(symbolName); + } + + /// Iterators for symbols that appear on the command line. + typedef std::vector 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. + ArrayRef 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 = 0; + + /// @} + /// \name Methods used by Driver::link() + /// @{ + + /// Returns the file system path to which the linked output should be written. + /// + /// \todo To support in-memory linking, we need an abstraction that allows + /// the linker to write to an in-memory buffer. + StringRef outputPath() const { return _outputPath; } + + /// Accessor for Register object embedded in LinkingContext. + const Registry ®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 void createImplicitFiles(std::vector> &) = 0; + + /// This method is called by core linking to build the list of Passes to be + /// run on the merged/linked graph of all input files. + virtual void addPasses(PassManager &pm) = 0; + + /// Calls through to the writeFile() method on the specified Writer. + /// + /// \param linkedFile This is the merged/linked graph of all input file Atoms. + virtual llvm::Error writeFile(const File &linkedFile) const; + + /// Return the next ordinal and Increment it. + virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; } + + // This function is called just before the Resolver kicks in. + // Derived classes may use it to change the list of input files. + virtual void finalizeInputFiles() = 0; + + /// Callback invoked for each file the Resolver decides we are going to load. + /// This can be used to update context state based on the file, and emit + /// errors for any differences between the context state and a loaded file. + /// For example, we can error if we try to load a file which is a different + /// arch from that being linked. + virtual llvm::Error handleLoadedFile(File &file) = 0; + + /// @} +protected: + LinkingContext(); // Must be subclassed + + /// Abstract method to lazily instantiate the Writer. + virtual Writer &writer() const = 0; + + /// Method to create an internal file for the entry symbol + virtual std::unique_ptr 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; + + StringRef _outputPath; + StringRef _entrySymbolName; + bool _deadStrip = false; + bool _globalsAreDeadStripRoots = false; + bool _printRemainingUndefines = true; + bool _allowRemainingUndefines = false; + bool _logInputFiles = false; + bool _allowShlibUndefines = false; + std::vector _deadStripRoots; + std::vector _llvmOptions; + StringRefVector _initialUndefinedSymbols; + std::vector> _nodes; + mutable llvm::BumpPtrAllocator _allocator; + mutable uint64_t _nextOrdinal = 0; + Registry _registry; + +private: + /// Validate the subclass bits. Only called by validate. + virtual bool validateImpl(raw_ostream &diagnostics) = 0; +}; + +} // end namespace lld + +#endif // LLD_CORE_LINKING_CONTEXT_H diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h new file mode 100644 index 000000000..c30482409 --- /dev/null +++ b/include/lld/Core/Node.h @@ -0,0 +1,75 @@ +//===- lld/Core/Node.h - Input file class -----------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// The classes in this file represents inputs to the linker. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_NODE_H +#define LLD_CORE_NODE_H + +#include "lld/Core/File.h" +#include +#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() = default; + + virtual Kind kind() const { return _kind; } + +private: + Kind _kind; +}; + +// This is a marker for --end-group. getSize() returns the number of +// files between the corresponding --start-group and this marker. +class GroupEnd : public Node { +public: + explicit GroupEnd(int size) : Node(Kind::GroupEnd), _size(size) {} + + int getSize() const { return _size; } + + static bool classof(const Node *a) { + return a->kind() == Kind::GroupEnd; + } + +private: + int _size; +}; + +// A container of File. +class FileNode : public Node { +public: + explicit FileNode(std::unique_ptr f) + : Node(Node::Kind::File), _file(std::move(f)) {} + + static bool classof(const Node *a) { + return a->kind() == Node::Kind::File; + } + + File *getFile() { return _file.get(); } + +protected: + std::unique_ptr _file; +}; + +} // end namespace lld + +#endif // LLD_CORE_NODE_H diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h new file mode 100644 index 000000000..bfe3f9b10 --- /dev/null +++ b/include/lld/Core/Pass.h @@ -0,0 +1,43 @@ +//===------ Core/Pass.h - Base class for linker passes ----------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PASS_H +#define LLD_CORE_PASS_H + +#include "llvm/Support/Error.h" + +namespace lld { + +class SimpleFile; + +/// Once the core linking is done (which resolves references, coalesces atoms +/// and produces a complete Atom graph), the linker runs a series of passes +/// on the Atom graph. The graph is modeled as a File, which means the pass +/// has access to all the atoms and to File level attributes. Each pass does +/// a particular transformation to the Atom graph or to the File attributes. +/// +/// This is the abstract base class for all passes. A Pass does its +/// actual work in it perform() method. It can iterator over Atoms in the +/// graph using the *begin()/*end() atom iterator of the File. It can add +/// new Atoms to the graph using the File's addAtom() method. +class Pass { +public: + virtual ~Pass() = default; + + /// Do the actual work of the Pass. + virtual llvm::Error perform(SimpleFile &mergedFile) = 0; + +protected: + // Only subclassess can be instantiated. + Pass() = default; +}; + +} // end namespace lld + +#endif // LLD_CORE_PASS_H diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h new file mode 100644 index 000000000..09b417a29 --- /dev/null +++ b/include/lld/Core/PassManager.h @@ -0,0 +1,48 @@ +//===- lld/Core/PassManager.h - Manage linker passes ----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PASS_MANAGER_H +#define LLD_CORE_PASS_MANAGER_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Pass.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace lld { +class SimpleFile; +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)); + } + + llvm::Error runOnFile(SimpleFile &file) { + for (std::unique_ptr &pass : _passes) + if (llvm::Error EC = pass->perform(file)) + return EC; + return llvm::Error::success(); + } + +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 000000000..32d04249f --- /dev/null +++ b/include/lld/Core/Reader.h @@ -0,0 +1,155 @@ +//===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_READER_H +#define LLD_CORE_READER_H + +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include + +namespace llvm { +namespace yaml { +class IO; +} // end namespace yaml +} // end namespace llvm + +namespace lld { + +class File; +class LinkingContext; +class MachOLinkingContext; + +/// \brief An abstract class for reading object files, library files, and +/// executable files. +/// +/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader. +class Reader { +public: + virtual ~Reader() = default; + + /// Sniffs the file to determine if this Reader can parse it. + /// The method is called with: + /// 1) the file_magic enumeration returned by identify_magic() + /// 2) the whole file content buffer if the above is not enough. + virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0; + + /// \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 ErrorOr> + loadFile(std::unique_ptr mb, const class Registry &) 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. + ErrorOr> + loadFile(std::unique_ptr mb) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// name to a value. + bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns, + Reference::KindArch &a, + Reference::KindValue &value) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// value to a string. + bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a, + Reference::KindValue value, StringRef &) const; + + /// Walk the list of registered tag handlers and have the one that handles + /// the current document type process the yaml into an lld::File*. + bool handleTaggedDoc(llvm::yaml::IO &io, const lld::File *&file) const; + + // These methods are called to dynamically add support for various file + // formats. The methods are also implemented in the appropriate lib*.a + // library, so that the code for handling a format is only linked in, if this + // method is used. Any options that a Reader might need must be passed + // as parameters to the addSupport*() method. + void addSupportArchives(bool logLoading); + void addSupportYamlFiles(); + void addSupportMachOObjects(MachOLinkingContext &); + + /// To convert between kind values and names, the registry walks the list + /// of registered kind tables. Each table is a zero terminated array of + /// KindStrings elements. + struct KindStrings { + Reference::KindValue value; + StringRef name; + }; + + /// A Reference Kind value is a tuple of . 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 // LLD_CORE_READER_H diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h new file mode 100644 index 000000000..1d3003c84 --- /dev/null +++ b/include/lld/Core/Reference.h @@ -0,0 +1,119 @@ +//===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_REFERENCES_H +#define LLD_CORE_REFERENCES_H + +#include + +namespace lld { + +class Atom; + +/// +/// The linker has a Graph Theory model of linking. An object file is seen +/// as a set of Atoms with References to other Atoms. Each Atom is a node +/// and each Reference is an edge. +/// +/// For example if a function contains a call site to "malloc" 40 bytes into +/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40, +/// kind=callsite, target=malloc, addend=0. +/// +/// Besides supporting traditional "relocations", references are also used +/// forcing layout (one atom must follow another), marking data-in-code +/// (jump tables or ARM constants), etc. +/// +/// The "kind" of a reference is a tuple of . This +/// enable us to re-use existing relocation types definded for various +/// file formats and architectures. +/// +/// References and atoms form a directed graph. The dead-stripping pass +/// traverses them starting from dead-strip root atoms to garbage collect +/// unreachable ones. +/// +/// References of any kind are considered as directed edges. In addition to +/// that, references of some kind is considered as bidirected edges. +class Reference { +public: + /// Which universe defines the kindValue(). + enum class KindNamespace { + all = 0, + testing = 1, + mach_o = 2, + }; + + KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; } + void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; } + + // Which architecture the kind value is for. + enum class KindArch { all, AArch64, ARM, x86, x86_64}; + + KindArch kindArch() const { return (KindArch)_kindArch; } + void setKindArch(KindArch a) { _kindArch = (uint8_t)a; } + + typedef uint16_t KindValue; + + KindValue kindValue() const { return _kindValue; } + + /// setKindValue() is needed because during linking, some optimizations may + /// change the codegen and hence the reference kind. + void setKindValue(KindValue value) { + _kindValue = value; + } + + /// KindValues used with KindNamespace::all and KindArch::all. + enum { + // kindLayoutAfter is treated as a bidirected edge by the dead-stripping + // pass. + kindLayoutAfter = 1, + kindAssociate, + }; + + // A value to be added to the value of a target + typedef int64_t Addend; + + /// If the reference is a fixup in the Atom, then this returns the + /// byte offset into the Atom's content to do the fix up. + virtual uint64_t offsetInAtom() const = 0; + + /// Returns the atom this reference refers to. + virtual const Atom *target() const = 0; + + /// During linking, the linker may merge graphs which coalesces some nodes + /// (i.e. Atoms). To switch the target of a reference, this method is called. + virtual void setTarget(const Atom *) = 0; + + /// Some relocations require a symbol and a value (e.g. foo + 4). + virtual Addend addend() const = 0; + + /// During linking, some optimzations may change addend value. + virtual void setAddend(Addend) = 0; + + /// Returns target specific attributes of the reference. + virtual uint32_t tag() const { return 0; } + +protected: + /// Reference is an abstract base class. Only subclasses can use constructor. + Reference(KindNamespace ns, KindArch a, KindValue value) + : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {} + + /// The memory for Reference objects is always managed by the owning File + /// object. Therefore, no one but the owning File object should call + /// delete on an Reference. In fact, some File objects may bulk allocate + /// an array of References, so they cannot be individually deleted by anyone. + virtual ~Reference() = default; + + KindValue _kindValue; + uint8_t _kindNamespace; + uint8_t _kindArch; +}; + +} // end namespace lld + +#endif // LLD_CORE_REFERENCES_H diff --git a/include/lld/Core/Reproduce.h b/include/lld/Core/Reproduce.h new file mode 100644 index 000000000..6e1d36a54 --- /dev/null +++ b/include/lld/Core/Reproduce.h @@ -0,0 +1,39 @@ +//===- Reproduce.h - Utilities for creating reproducers ---------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_REPRODUCE_H +#define LLD_CORE_REPRODUCE_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace opt { class Arg; } +} + +namespace lld { + +// Makes a given pathname an absolute path first, and then remove +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", +// assuming that the current directory is "/home/john/bar". +std::string relativeToRoot(StringRef Path); + +// Quote a given string if it contains a space character. +std::string quote(StringRef S); + +// Rewrite the given path if a file exists with that pathname, otherwise +// returns the original path. +std::string rewritePath(StringRef S); + +// Returns the string form of the given argument. +std::string toString(llvm::opt::Arg *Arg); +} + +#endif diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h new file mode 100644 index 000000000..fb62a779c --- /dev/null +++ b/include/lld/Core/Resolver.h @@ -0,0 +1,106 @@ +//===- Core/Resolver.h - Resolves Atom References -------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_RESOLVER_H +#define LLD_CORE_RESOLVER_H + +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/Simple.h" +#include "lld/Core/SymbolTable.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/ErrorOr.h" +#include +#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), _result(new MergedFile()) {} + + // InputFiles::Handler methods + void doDefinedAtom(OwningAtomPtr atom); + bool doUndefinedAtom(OwningAtomPtr atom); + void doSharedLibraryAtom(OwningAtomPtr atom); + void doAbsoluteAtom(OwningAtomPtr atom); + + // Handle files, this adds atoms from the current file thats + // being processed by the resolver + llvm::Expected handleFile(File &); + + // Handle an archive library file. + llvm::Expected handleArchiveFile(File &); + + // Handle a shared library file. + llvm::Error 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(StringRef)> UndefCallback; + + bool undefinesAdded(int begin, int end); + File *getFile(int &index); + + /// \brief The main function that iterates over the files to resolve + bool resolveUndefines(); + void updateReferences(); + void deadStripOptimize(); + bool checkUndefines(); + void removeCoalescedAwayAtoms(); + llvm::Expected forEachUndefines(File &file, UndefCallback callback); + + void markLive(const Atom *atom); + + class MergedFile : public SimpleFile { + public: + MergedFile() : SimpleFile("", kindResolverMergedObject) {} + void addAtoms(llvm::MutableArrayRef> 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; + + // 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/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h new file mode 100644 index 000000000..7fec7a3e3 --- /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 Darwin it is the LC_DYLIB_LOAD dylib name. + virtual StringRef loadName() const = 0; + + /// Returns if shared library symbol can be missing at runtime and if + /// so the loader should silently resolve address of symbol to be nullptr. + virtual bool canBeNullAtRuntime() const = 0; + + virtual Type type() const = 0; + + virtual uint64_t size() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionSharedLibrary; + } + + static inline bool classof(const SharedLibraryAtom *) { return true; } + +protected: + SharedLibraryAtom() : Atom(definitionSharedLibrary) {} + + ~SharedLibraryAtom() override = default; +}; + +} // namespace lld + +#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H diff --git a/include/lld/Core/SharedLibraryFile.h b/include/lld/Core/SharedLibraryFile.h new file mode 100644 index 000000000..53bf967b0 --- /dev/null +++ b/include/lld/Core/SharedLibraryFile.h @@ -0,0 +1,70 @@ +//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H +#define LLD_CORE_SHARED_LIBRARY_FILE_H + +#include "lld/Core/File.h" + +namespace lld { + +/// +/// The SharedLibraryFile subclass of File is used to represent dynamic +/// shared libraries being linked against. +/// +class SharedLibraryFile : public File { +public: + static bool classof(const File *f) { + return f->kind() == kindSharedLibrary; + } + + /// Check if the shared library exports a symbol with the specified name. + /// If so, return a SharedLibraryAtom which represents that exported + /// symbol. Otherwise return nullptr. + virtual OwningAtomPtr exports(StringRef name) const = 0; + + // Returns the install name. + virtual StringRef getDSOName() const = 0; + + const AtomRange defined() const override { + return _definedAtoms; + } + + const AtomRange undefined() const override { + return _undefinedAtoms; + } + + const AtomRange sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const AtomRange absolute() const override { + return _absoluteAtoms; + } + + void clearAtoms() override { + _definedAtoms.clear(); + _undefinedAtoms.clear(); + _sharedLibraryAtoms.clear(); + _absoluteAtoms.clear(); + } + +protected: + /// only subclasses of SharedLibraryFile can be instantiated + explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {} + + AtomVector _definedAtoms; + AtomVector _undefinedAtoms; + AtomVector _sharedLibraryAtoms; + AtomVector _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 000000000..3aa7abf5d --- /dev/null +++ b/include/lld/Core/Simple.h @@ -0,0 +1,271 @@ +//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provide simple implementations for Atoms and File. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SIMPLE_H +#define LLD_CORE_SIMPLE_H + +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/Atom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include + +namespace lld { + +class SimpleFile : public File { +public: + SimpleFile(StringRef path, File::Kind kind) + : File(path, kind) {} + + ~SimpleFile() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } + + void addAtom(DefinedAtom &a) { + _defined.push_back(OwningAtomPtr(&a)); + } + void addAtom(UndefinedAtom &a) { + _undefined.push_back(OwningAtomPtr(&a)); + } + void addAtom(SharedLibraryAtom &a) { + _shared.push_back(OwningAtomPtr(&a)); + } + void addAtom(AbsoluteAtom &a) { + _absolute.push_back(OwningAtomPtr(&a)); + } + + void addAtom(const Atom &atom) { + if (auto *p = dyn_cast(&atom)) { + addAtom(const_cast(*p)); + } else if (auto *p = dyn_cast(&atom)) { + addAtom(const_cast(*p)); + } else if (auto *p = dyn_cast(&atom)) { + addAtom(const_cast(*p)); + } else if (auto *p = dyn_cast(&atom)) { + addAtom(const_cast(*p)); + } else { + llvm_unreachable("atom has unknown definition kind"); + } + } + + void removeDefinedAtomsIf(std::function pred) { + auto &atoms = _defined; + auto newEnd = std::remove_if(atoms.begin(), atoms.end(), + [&pred](OwningAtomPtr &p) { + return pred(p.get()); + }); + atoms.erase(newEnd, atoms.end()); + } + + const AtomRange defined() const override { return _defined; } + + const AtomRange undefined() const override { + return _undefined; + } + + const AtomRange sharedLibrary() const override { + return _shared; + } + + const AtomRange absolute() const override { + return _absolute; + } + + void clearAtoms() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } + +private: + AtomVector _defined; + AtomVector _undefined; + AtomVector _shared; + AtomVector _absolute; +}; + +class SimpleReference : public Reference, + public llvm::ilist_node { +public: + SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue value, uint64_t off, const Atom *t, + Reference::Addend a) + : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a) { + } + SimpleReference() + : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0), + _target(nullptr), _offsetInAtom(0), _addend(0) {} + + uint64_t offsetInAtom() const override { return _offsetInAtom; } + + const Atom *target() const override { + assert(_target); + return _target; + } + + Addend addend() const override { return _addend; } + void setAddend(Addend a) override { _addend = a; } + void setTarget(const Atom *newAtom) override { _target = newAtom; } + +private: + const Atom *_target; + uint64_t _offsetInAtom; + Addend _addend; +}; + +class SimpleDefinedAtom : public DefinedAtom { +public: + explicit SimpleDefinedAtom(const File &f) + : _file(f), _ordinal(f.getNextAtomOrdinalAndIncrement()) {} + + ~SimpleDefinedAtom() override { + _references.clearAndLeakNodesUnsafely(); + } + + const File &file() const override { return _file; } + + StringRef name() const override { return StringRef(); } + + uint64_t ordinal() const override { return _ordinal; } + + Scope scope() const override { return DefinedAtom::scopeLinkageUnit; } + + Interposable interposable() const override { + return DefinedAtom::interposeNo; + } + + Merge merge() const override { return DefinedAtom::mergeNo; } + + Alignment alignment() const override { return 1; } + + SectionChoice sectionChoice() const override { + return DefinedAtom::sectionBasedOnContent; + } + + StringRef customSectionName() const override { return StringRef(); } + DeadStripKind deadStrip() const override { + return DefinedAtom::deadStripNormal; + } + + DefinedAtom::reference_iterator begin() const override { + const void *it = + reinterpret_cast(_references.begin().getNodePtr()); + return reference_iterator(*this, it); + } + + DefinedAtom::reference_iterator end() const override { + const void *it = + reinterpret_cast(_references.end().getNodePtr()); + return reference_iterator(*this, it); + } + + const Reference *derefIterator(const void *it) const override { + return &*RefList::const_iterator( + *reinterpret_cast *>(it)); + } + + void incrementIterator(const void *&it) const override { + RefList::const_iterator ref( + *reinterpret_cast *>(it)); + it = reinterpret_cast(std::next(ref).getNodePtr()); + } + + void addReference(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t off, + const Atom *target, Reference::Addend a) override { + assert(target && "trying to create reference to nothing"); + auto node = new (_file.allocator()) + SimpleReference(ns, arch, kindValue, off, target, a); + _references.push_back(node); + } + + /// Sort references in a canonical order (by offset, then by kind). + void sortReferences() const { + // Cannot sort a linked list, so move elements into a temporary vector, + // sort the vector, then reconstruct the list. + llvm::SmallVector 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"); + } + + ~SimpleUndefinedAtom() override = default; + + /// file - returns the File that produced/owns this Atom + const File &file() const override { return _file; } + + /// name - The name of the atom. For a function atom, it is the (mangled) + /// name of the function. + StringRef name() const override { return _name; } + + CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; } + +private: + const File &_file; + StringRef _name; +}; + +} // end namespace lld + +#endif // LLD_CORE_SIMPLE_H diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h new file mode 100644 index 000000000..ba4951e5b --- /dev/null +++ b/include/lld/Core/SymbolTable.h @@ -0,0 +1,96 @@ +//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SYMBOL_TABLE_H +#define LLD_CORE_SYMBOL_TABLE_H + +#include "lld/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: + /// @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 returns atom in symbol table for specified name (or nullptr) + const Atom *findByName(StringRef sym); + + /// @brief returns vector of remaining UndefinedAtoms + std::vector undefines(); + + /// @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 *); + +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 &); + + AtomToAtom _replacedAtoms; + NameToAtom _nameTable; + 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 000000000..8b523045d --- /dev/null +++ b/include/lld/Core/TODO.txt @@ -0,0 +1,17 @@ +include/lld/Core +~~~~~~~~~~~~~~~~ + +* The 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/TargetOptionsCommandFlags.h b/include/lld/Core/TargetOptionsCommandFlags.h new file mode 100644 index 000000000..9ba99d94b --- /dev/null +++ b/include/lld/Core/TargetOptionsCommandFlags.h @@ -0,0 +1,20 @@ +//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper to create TargetOptions from command line flags. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CodeGen.h" +#include "llvm/Target/TargetOptions.h" + +namespace lld { +llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); +llvm::CodeModel::Model GetCodeModelFromCMModel(); +} diff --git a/include/lld/Core/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h new file mode 100644 index 000000000..f45d6ecda --- /dev/null +++ b/include/lld/Core/UndefinedAtom.h @@ -0,0 +1,68 @@ +//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_UNDEFINED_ATOM_H +#define LLD_CORE_UNDEFINED_ATOM_H + +#include "lld/Core/Atom.h" + +namespace lld { + +/// An UndefinedAtom has no content. +/// It exists as a placeholder for a future atom. +class UndefinedAtom : public Atom { +public: + /// Whether this undefined symbol needs to be resolved, + /// or whether it can just evaluate to nullptr. + /// This concept is often called "weak", but that term + /// is overloaded to mean other things too. + enum CanBeNull { + /// Normal symbols must be resolved at build time + canBeNullNever, + + /// This symbol can be missing at runtime and will evalute to nullptr. + /// That is, the static linker still must find a definition (usually + /// is some shared library), but at runtime, the dynamic loader + /// will allow the symbol to be missing and resolved to nullptr. + /// + /// On Darwin this is generated using a function prototype with + /// __attribute__((weak_import)). + /// On linux this is generated using a function prototype with + /// __attribute__((weak)). + /// On Windows this feature is not supported. + canBeNullAtRuntime, + + /// This symbol can be missing at build time. + /// That is, the static linker will not error if a definition for + /// this symbol is not found at build time. Instead, the linker + /// will build an executable that lets the dynamic loader find the + /// symbol at runtime. + /// This feature is not supported on Darwin nor Windows. + /// On linux this is generated using a function prototype with + /// __attribute__((weak)). + canBeNullAtBuildtime + }; + + virtual CanBeNull canBeNull() const = 0; + + static bool classof(const Atom *a) { + return a->definition() == definitionUndefined; + } + + static bool classof(const UndefinedAtom *) { return true; } + +protected: + UndefinedAtom() : Atom(definitionUndefined) {} + + ~UndefinedAtom() override = default; +}; + +} // namespace lld + +#endif // LLD_CORE_UNDEFINED_ATOM_H diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h new file mode 100644 index 000000000..216f93491 --- /dev/null +++ b/include/lld/Core/Writer.h @@ -0,0 +1,47 @@ +//===- lld/Core/Writer.h - Abstract File Format Interface -----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_WRITER_H +#define LLD_CORE_WRITER_H + +#include "lld/Core/LLVM.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace lld { +class File; +class LinkingContext; +class MachOLinkingContext; + +/// \brief The Writer is an abstract class for writing object files, shared +/// library files, and executable files. Each file format (e.g. mach-o, etc) +/// has a concrete subclass of Writer. +class Writer { +public: + virtual ~Writer(); + + /// \brief Write a file from the supplied File object + virtual llvm::Error 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 void createImplicitFiles(std::vector> &) {} + +protected: + // only concrete subclasses can be instantiated + Writer(); +}; + +std::unique_ptr createWriterMachO(const MachOLinkingContext &); +std::unique_ptr createWriterYAML(const LinkingContext &); +} // end namespace lld + +#endif diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h new file mode 100644 index 000000000..4ba0994e8 --- /dev/null +++ b/include/lld/Driver/Driver.h @@ -0,0 +1,33 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_DRIVER_DRIVER_H +#define LLD_DRIVER_DRIVER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" + +namespace lld { +namespace coff { +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); +} + +namespace elf { +bool link(llvm::ArrayRef Args, bool CanExitEarly, + llvm::raw_ostream &Diag = llvm::errs()); +} + +namespace mach_o { +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); +} +} + +#endif diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h new file mode 100644 index 000000000..9eefa8c4d --- /dev/null +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -0,0 +1,508 @@ +//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H +#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Reader.h" +#include "lld/Core/Writer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/ErrorHandling.h" +#include + +using llvm::MachO::HeaderFileType; + +namespace lld { + +namespace mach_o { +class ArchHandler; +class MachODylibFile; +class MachOFile; +class SectCreateFile; +} + +class MachOLinkingContext : public LinkingContext { +public: + MachOLinkingContext(); + ~MachOLinkingContext() override; + + enum Arch { + arch_unknown, + arch_ppc, + arch_x86, + arch_x86_64, + arch_armv6, + arch_armv7, + arch_armv7s, + arch_arm64, + }; + + enum class OS { + unknown, + macOSX, + iOS, + iOS_simulator + }; + + enum class ExportMode { + globals, // Default, all global symbols exported. + whiteList, // -exported_symbol[s_list], only listed symbols exported. + blackList // -unexported_symbol[s_list], no listed symbol exported. + }; + + enum class DebugInfoMode { + addDebugMap, // Default + noDebugMap // -S option + }; + + enum class UndefinedMode { + error, + warning, + suppress, + dynamicLookup + }; + + enum ObjCConstraint { + objc_unknown = 0, + objc_supports_gc = 2, + objc_gc_only = 4, + // Image optimized by dyld = 8 + // GC compaction = 16 + objc_retainReleaseForSimulator = 32, + objc_retainRelease + }; + + /// Initializes the context to sane default values given the specified output + /// file type, arch, os, and minimum os version. This should be called before + /// other setXXX() methods. + void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, + bool exportDynamicSymbols); + + void addPasses(PassManager &pm) override; + bool validateImpl(raw_ostream &diagnostics) override; + std::string demangle(StringRef symbolName) const override; + + void createImplicitFiles(std::vector> &) override; + + /// Creates a new file which is owned by the context. Returns a pointer to + /// the new file. + template + typename std::enable_if::value, T *>::type + make_file(Args &&... args) const { + auto file = std::unique_ptr(new T(std::forward(args)...)); + auto *filePtr = file.get(); + auto *ctx = const_cast(this); + ctx->getNodes().push_back(llvm::make_unique(std::move(file))); + return filePtr; + } + + uint32_t getCPUType() const; + uint32_t getCPUSubType() const; + + bool addEntryPointLoadCommand() const; + bool addUnixThreadLoadCommand() const; + bool outputTypeHasEntry() const; + bool is64Bit() const; + + virtual uint64_t pageZeroSize() const { return _pageZeroSize; } + virtual uint64_t pageSize() const { return _pageSize; } + + mach_o::ArchHandler &archHandler() const; + + HeaderFileType outputMachOType() const { return _outputMachOType; } + + Arch arch() const { return _arch; } + StringRef archName() const { return nameFromArch(_arch); } + OS os() const { return _os; } + + ExportMode exportMode() const { return _exportMode; } + void setExportMode(ExportMode mode) { _exportMode = mode; } + void addExportSymbol(StringRef sym); + bool exportRestrictMode() const { return _exportMode != ExportMode::globals; } + bool exportSymbolNamed(StringRef sym) const; + + DebugInfoMode debugInfoMode() const { return _debugInfoMode; } + void setDebugInfoMode(DebugInfoMode mode) { + _debugInfoMode = mode; + } + + void appendOrderedSymbol(StringRef symbol, StringRef filename); + + bool keepPrivateExterns() const { return _keepPrivateExterns; } + void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; } + bool demangleSymbols() const { return _demangle; } + void setDemangleSymbols(bool d) { _demangle = d; } + bool mergeObjCCategories() const { return _mergeObjCCategories; } + void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; } + /// Create file at specified path which will contain a binary encoding + /// of all input and output file paths. + std::error_code createDependencyFile(StringRef path); + void addInputFileDependency(StringRef path) const; + void addInputFileNotFound(StringRef path) const; + void addOutputFileDependency(StringRef path) const; + + bool minOS(StringRef mac, StringRef iOS) const; + void setDoNothing(bool value) { _doNothing = value; } + bool doNothing() const { return _doNothing; } + bool printAtoms() const { return _printAtoms; } + bool testingFileUsage() const { return _testingFileUsage; } + const StringRefVector &searchDirs() const { return _searchDirs; } + const StringRefVector &frameworkDirs() const { return _frameworkDirs; } + void setSysLibRoots(const StringRefVector &paths); + const StringRefVector &sysLibRoots() const { return _syslibRoots; } + bool PIE() const { return _pie; } + void setPIE(bool pie) { _pie = pie; } + bool generateVersionLoadCommand() const { + return _generateVersionLoadCommand; + } + void setGenerateVersionLoadCommand(bool v) { + _generateVersionLoadCommand = v; + } + + bool generateFunctionStartsLoadCommand() const { + return _generateFunctionStartsLoadCommand; + } + void setGenerateFunctionStartsLoadCommand(bool v) { + _generateFunctionStartsLoadCommand = v; + } + + bool generateDataInCodeLoadCommand() const { + return _generateDataInCodeLoadCommand; + } + void setGenerateDataInCodeLoadCommand(bool v) { + _generateDataInCodeLoadCommand = v; + } + + uint64_t stackSize() const { return _stackSize; } + void setStackSize(uint64_t stackSize) { _stackSize = stackSize; } + + uint64_t baseAddress() const { return _baseAddress; } + void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } + + ObjCConstraint objcConstraint() const { return _objcConstraint; } + + uint32_t osMinVersion() const { return _osMinVersion; } + + uint32_t sdkVersion() const { return _sdkVersion; } + void setSdkVersion(uint64_t v) { _sdkVersion = v; } + + uint64_t sourceVersion() const { return _sourceVersion; } + void setSourceVersion(uint64_t v) { _sourceVersion = v; } + + uint32_t swiftVersion() const { return _swiftVersion; } + + /// \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). + llvm::Optional searchDirForLibrary(StringRef path, + StringRef libName) const; + + /// \brief Iterates through all search path entries looking for libName (as + /// specified by -lFoo). + llvm::Optional 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"). + llvm::Optional 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 Whether or not to use flat namespace. + /// + /// MachO usually uses a two-level namespace, where each external symbol + /// referenced by the target is associated with the dylib that will provide + /// the symbol's definition at runtime. Using flat namespace overrides this + /// behavior: the linker searches all dylibs on the command line and all + /// dylibs those original dylibs depend on, but does not record which dylib + /// an external symbol came from. At runtime dyld again searches all images + /// and uses the first definition it finds. In addition, any undefines in + /// loaded flat_namespace dylibs must be resolvable at build time. + bool useFlatNamespace() const { return _flatNamespace; } + + /// \brief How to handle undefined symbols. + /// + /// Options are: + /// * error: Report an error and terminate linking. + /// * warning: Report a warning, but continue linking. + /// * suppress: Ignore and continue linking. + /// * dynamic_lookup: For use with -twolevel namespace: Records source dylibs + /// for symbols that are defined in a linked dylib at static link time. + /// Undefined symbols are handled by searching all loaded images at + /// runtime. + UndefinedMode undefinedMode() const { return _undefinedMode; } + + /// \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 setUseFlatNamespace(bool flatNamespace) { + _flatNamespace = flatNamespace; + } + + void setUndefinedMode(UndefinedMode undefinedMode) { + _undefinedMode = undefinedMode; + } + + void setBundleLoader(StringRef loader) { _bundleLoader = loader; } + void setPrintAtoms(bool value=true) { _printAtoms = value; } + void setTestingFileUsage(bool value = true) { + _testingFileUsage = value; + } + void addExistingPathForDebug(StringRef path) { + _existingPaths.insert(path); + } + + void addRpath(StringRef rpath); + const StringRefVector &rpaths() const { return _rpaths; } + + /// Add section alignment constraint on final layout. + void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align); + + /// \brief Add a section based on a command-line sectcreate option. + void addSectCreateSection(StringRef seg, StringRef sect, + std::unique_ptr content); + + /// Returns true if specified section had alignment constraints. + bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const; + + StringRef dyldPath() const { return "/usr/lib/dyld"; } + + /// Stub creation Pass should be run. + bool needsStubsPass() const; + + // GOT creation Pass should be run. + bool needsGOTPass() const; + + /// Pass to add TLV sections. + bool needsTLVPass() const; + + /// Pass to transform __compact_unwind into __unwind_info should be run. + bool needsCompactUnwindPass() const; + + /// Pass to add shims switching between thumb and arm mode. + bool needsShimPass() const; + + /// Pass to add objc image info and optimized objc data. + bool needsObjCPass() const; + + /// Magic symbol name stubs will need to help lazy bind. + StringRef binderSymbolName() const; + + /// Used to keep track of direct and indirect dylibs. + void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const; + + // Reads a file from disk to memory. Returns only a needed chunk + // if a fat binary. + ErrorOr> getMemoryBuffer(StringRef path); + + /// Used to find indirect dylibs. Instantiates a MachODylibFile if one + /// has not already been made for the requested dylib. Uses -L and -F + /// search paths to allow indirect dylibs to be overridden. + mach_o::MachODylibFile* findIndirectDylib(StringRef path); + + uint32_t dylibCurrentVersion(StringRef installName) const; + + uint32_t dylibCompatVersion(StringRef installName) const; + + ArrayRef allDylibs() const { + return _allDylibs; + } + + /// Creates a copy (owned by this MachOLinkingContext) of a string. + StringRef copy(StringRef str) { return str.copy(_allocator); } + + /// If the memoryBuffer is a fat file with a slice for the current arch, + /// this method will return the offset and size of that slice. + bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size); + + /// Returns if a command line option specified dylib is an upward link. + bool isUpwardDylib(StringRef installName) const; + + static bool isThinObjectFile(StringRef path, Arch &arch); + static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); + static Arch archFromName(StringRef archName); + static StringRef nameFromArch(Arch arch); + static uint32_t cpuTypeFromArch(Arch arch); + static uint32_t cpuSubtypeFromArch(Arch arch); + static bool is64Bit(Arch arch); + static bool isHostEndian(Arch arch); + static bool isBigEndian(Arch arch); + + /// Construct 32-bit value from string "X.Y.Z" where + /// bits are xxxx.yy.zz. Largest number is 65535.255.255 + static bool parsePackedVersion(StringRef str, uint32_t &result); + + /// Construct 64-bit value from string "A.B.C.D.E" where + /// bits are aaaa.bb.cc.dd.ee. Largest number is 16777215.1023.1023.1023.1023 + static bool parsePackedVersion(StringRef str, uint64_t &result); + + void finalizeInputFiles() override; + + llvm::Error handleLoadedFile(File &file) override; + + bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, + bool &leftBeforeRight) const; + + /// Return the 'flat namespace' file. This is the file that supplies + /// atoms for otherwise undefined symbols when the -flat_namespace or + /// -undefined dynamic_lookup options are used. + File* flatNamespaceFile() const { return _flatNamespaceFile; } + +private: + Writer &writer() const override; + mach_o::MachODylibFile* loadIndirectDylib(StringRef path); + void checkExportWhiteList(const DefinedAtom *atom) const; + void checkExportBlackList(const DefinedAtom *atom) const; + struct ArchInfo { + StringRef archName; + MachOLinkingContext::Arch arch; + bool littleEndian; + uint32_t cputype; + uint32_t cpusubtype; + }; + + struct SectionAlign { + StringRef segmentName; + StringRef sectionName; + uint16_t align; + }; + + struct OrderFileNode { + StringRef fileFilter; + unsigned order; + }; + + static bool findOrderOrdinal(const std::vector &nodes, + const DefinedAtom *atom, unsigned &ordinal); + + static ArchInfo _s_archInfos[]; + + std::set _existingPaths; // For testing only. + StringRefVector _searchDirs; + StringRefVector _syslibRoots; + StringRefVector _frameworkDirs; + HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE; + bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog + bool _doNothing = false; // for -help and -v which just print info + bool _pie = false; + Arch _arch = arch_unknown; + OS _os = OS::macOSX; + uint32_t _osMinVersion = 0; + uint32_t _sdkVersion = 0; + uint64_t _sourceVersion = 0; + uint64_t _pageZeroSize = 0; + uint64_t _pageSize = 4096; + uint64_t _baseAddress = 0; + uint64_t _stackSize = 0; + uint32_t _compatibilityVersion = 0; + uint32_t _currentVersion = 0; + ObjCConstraint _objcConstraint = objc_unknown; + uint32_t _swiftVersion = 0; + StringRef _installName; + StringRefVector _rpaths; + bool _flatNamespace = false; + UndefinedMode _undefinedMode = UndefinedMode::error; + bool _deadStrippableDylib = false; + bool _printAtoms = false; + bool _testingFileUsage = false; + bool _keepPrivateExterns = false; + bool _demangle = false; + bool _mergeObjCCategories = true; + bool _generateVersionLoadCommand = false; + bool _generateFunctionStartsLoadCommand = false; + bool _generateDataInCodeLoadCommand = false; + StringRef _bundleLoader; + mutable std::unique_ptr _archHandler; + mutable std::unique_ptr _writer; + std::vector _sectAligns; + mutable llvm::StringMap _pathToDylibMap; + mutable std::vector _allDylibs; + mutable std::set _upwardDylibs; + mutable std::vector> _indirectDylibs; + mutable std::mutex _dylibsMutex; + ExportMode _exportMode = ExportMode::globals; + llvm::StringSet<> _exportedSymbols; + DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap; + std::unique_ptr _dependencyInfo; + llvm::StringMap> _orderFiles; + unsigned _orderFileEntries = 0; + File *_flatNamespaceFile = nullptr; + mach_o::SectCreateFile *_sectCreateFile = nullptr; +}; + +} // end namespace lld + +#endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h new file mode 100644 index 000000000..b26161a15 --- /dev/null +++ b/include/lld/ReaderWriter/YamlContext.h @@ -0,0 +1,42 @@ +//===- 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 { + const LinkingContext *_ctx = nullptr; + const Registry *_registry = nullptr; + File *_file = nullptr; + NormalizedFile *_normalizeMachOFile = nullptr; + StringRef _path; +}; + +} // end namespace lld + +#endif // LLD_READER_WRITER_YAML_CONTEXT_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 000000000..699f5e93f --- /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 000000000..3e142b66f --- /dev/null +++ b/lib/Config/CMakeLists.txt @@ -0,0 +1,9 @@ +add_lld_library(lldConfig + Version.cpp + + ADDITIONAL_HEADER_DIRS + ${LLD_INCLUDE_DIR}/lld/Config + + LINK_COMPONENTS + Support + ) diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp new file mode 100644 index 000000000..25544756f --- /dev/null +++ b/lib/Config/Version.cpp @@ -0,0 +1,43 @@ +//===- 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" + +using namespace llvm; + +// Returns an SVN repository path, which is usually "trunk". +static std::string getRepositoryPath() { + StringRef S = LLD_REPOSITORY_STRING; + size_t Pos = S.find("lld/"); + if (Pos != StringRef::npos) + return S.substr(Pos + 4); + return S; +} + +// Returns an SVN repository name, e.g., " (trunk 284614)" +// or an empty string if no repository info is available. +static std::string getRepository() { + std::string Repo = getRepositoryPath(); + std::string Rev = LLD_REVISION_STRING; + + if (Repo.empty() && Rev.empty()) + return ""; + if (!Repo.empty() && !Rev.empty()) + return " (" + Repo + " " + Rev + ")"; + return " (" + Repo + Rev + ")"; +} + +// Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)". +std::string lld::getLLDVersion() { + return "LLD " + std::string(LLD_VERSION_STRING) + getRepository(); +} diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt new file mode 100644 index 000000000..85046b93f --- /dev/null +++ b/lib/Core/CMakeLists.txt @@ -0,0 +1,30 @@ +if(NOT LLD_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_lld_library(lldCore + DefinedAtom.cpp + Error.cpp + File.cpp + LinkingContext.cpp + Reader.cpp + Reproduce.cpp + Resolver.cpp + SymbolTable.cpp + TargetOptionsCommandFlags.cpp + Writer.cpp + + ADDITIONAL_HEADER_DIRS + ${LLD_INCLUDE_DIR}/lld/Core + + LINK_COMPONENTS + BinaryFormat + MC + Support + + LINK_LIBS + ${LLVM_PTHREAD_LIB} + + DEPENDS + ${tablegen_deps} + ) diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp new file mode 100644 index 000000000..177cae7fc --- /dev/null +++ b/lib/Core/DefinedAtom.cpp @@ -0,0 +1,82 @@ +//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ErrorHandling.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" + +namespace lld { + +DefinedAtom::ContentPermissions DefinedAtom::permissions() const { + // By default base permissions on content type. + return permissions(this->contentType()); +} + +// Utility function for deriving permissions from content type +DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { + switch (type) { + case typeCode: + case typeResolver: + case typeBranchIsland: + case typeBranchShim: + case typeStub: + case typeStubHelper: + case typeMachHeader: + return permR_X; + + case typeConstant: + case typeCString: + case typeUTF16String: + case typeCFI: + case typeLSDA: + case typeLiteral4: + case typeLiteral8: + case typeLiteral16: + case typeDTraceDOF: + case typeCompactUnwindInfo: + case typeProcessedUnwindInfo: + case typeObjCImageInfo: + case typeObjCMethodList: + return permR__; + + case typeData: + case typeDataFast: + case typeZeroFill: + case typeZeroFillFast: + case typeObjC1Class: + case typeLazyPointer: + case typeLazyDylibPointer: + case typeNonLazyPointer: + case typeThunkTLV: + return permRW_; + + case typeGOT: + case typeConstData: + case typeCFString: + case typeInitializerPtr: + case typeTerminatorPtr: + case typeCStringPtr: + case typeObjCClassPtr: + case typeObjC2CategoryList: + case typeInterposingTuples: + case typeTLVInitialData: + case typeTLVInitialZeroFill: + case typeTLVInitializerPtr: + return permRW_L; + + case typeUnknown: + case typeTempLTO: + case typeSectCreate: + case typeDSOHandle: + return permUnknown; + } + llvm_unreachable("unknown content type"); +} + +} // namespace diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp new file mode 100644 index 000000000..6fc76f7ca --- /dev/null +++ b/lib/Core/Error.cpp @@ -0,0 +1,93 @@ +//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include + +using namespace lld; + +namespace { +class _YamlReaderErrorCategory : public std::error_category { +public: + const char* name() const noexcept override { + return "lld.yaml.reader"; + } + + std::string message(int ev) const override { + switch (static_cast(ev)) { + case YamlReaderError::unknown_keyword: + return "Unknown keyword found in yaml file"; + case YamlReaderError::illegal_value: + return "Bad value found in yaml file"; + } + llvm_unreachable("An enumerator of YamlReaderError does not have a " + "message defined."); + } +}; +} // end anonymous namespace + +const std::error_category &lld::YamlReaderCategory() { + static _YamlReaderErrorCategory o; + return o; +} + +namespace lld { + +/// Temporary class to enable make_dynamic_error_code() until +/// llvm::ErrorOr<> is updated to work with error encapsulations +/// other than error_code. +class dynamic_error_category : public std::error_category { +public: + ~dynamic_error_category() override = default; + + const char *name() const noexcept override { + return "lld.dynamic_error"; + } + + std::string message(int ev) const override { + assert(ev >= 0); + assert(ev < (int)_messages.size()); + // The value is an index into the string vector. + return _messages[ev]; + } + + int add(std::string msg) { + std::lock_guard 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); +} + +char GenericError::ID = 0; + +GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { } + +void GenericError::log(raw_ostream &OS) const { + OS << Msg; +} + +} // namespace lld diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp new file mode 100644 index 000000000..30ded091a --- /dev/null +++ b/lib/Core/File.cpp @@ -0,0 +1,29 @@ +//===- Core/File.cpp - A Container of Atoms -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include + +namespace lld { + +File::~File() = default; + +File::AtomVector File::_noDefinedAtoms; +File::AtomVector File::_noUndefinedAtoms; +File::AtomVector File::_noSharedLibraryAtoms; +File::AtomVector File::_noAbsoluteAtoms; + +std::error_code File::parse() { + std::lock_guard lock(_parseMutex); + if (!_lastError.hasValue()) + _lastError = doParse(); + return _lastError.getValue(); +} + +} // end namespace lld diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp new file mode 100644 index 000000000..5de863aa7 --- /dev/null +++ b/lib/Core/LinkingContext.cpp @@ -0,0 +1,70 @@ +//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/LinkingContext.h" +#include "lld/Core/File.h" +#include "lld/Core/Node.h" +#include "lld/Core/Simple.h" +#include "lld/Core/Writer.h" +#include + +namespace lld { + +LinkingContext::LinkingContext() = default; + +LinkingContext::~LinkingContext() = default; + +bool LinkingContext::validate(raw_ostream &diagnostics) { + return validateImpl(diagnostics); +} + +llvm::Error LinkingContext::writeFile(const File &linkedFile) const { + return this->writer().writeFile(linkedFile, _outputPath); +} + +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, + File::kindEntryObject)); + 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, File::kindUndefinedSymsObject)); + for (StringRef undefSym : _initialUndefinedSymbols) + undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( + *undefinedSymFile, undefSym))); + return std::move(undefinedSymFile); +} + +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)); +} + +} // end namespace lld diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp new file mode 100644 index 000000000..5d8bbbbfe --- /dev/null +++ b/lib/Core/Reader.cpp @@ -0,0 +1,114 @@ +//===- lib/Core/Reader.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Reader.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include + +using llvm::file_magic; +using llvm::identify_magic; + +namespace lld { + +YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default; + +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)); +} + +ErrorOr> +Registry::loadFile(std::unique_ptr mb) const { + // Get file magic. + StringRef content(mb->getBufferStart(), mb->getBufferSize()); + file_magic fileType = identify_magic(content); + + // Ask each registered reader if it can handle this file type or extension. + for (const std::unique_ptr &reader : _readers) { + if (!reader->canParse(fileType, mb->getMemBufferRef())) + continue; + return reader->loadFile(std::move(mb), *this); + } + + // No Reader could parse this file. + return make_error_code(llvm::errc::executable_format_error); +} + +static const Registry::KindStrings kindStrings[] = { + {Reference::kindLayoutAfter, "layout-after"}, + {Reference::kindAssociate, "associate"}, + LLD_KIND_STRING_END}; + +Registry::Registry() { + addKindTable(Reference::KindNamespace::all, Reference::KindArch::all, + kindStrings); +} + +bool Registry::handleTaggedDoc(llvm::yaml::IO &io, + const lld::File *&file) const { + for (const std::unique_ptr &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/Reproduce.cpp b/lib/Core/Reproduce.cpp new file mode 100644 index 000000000..e3629a93c --- /dev/null +++ b/lib/Core/Reproduce.cpp @@ -0,0 +1,66 @@ +//===- Reproduce.cpp - Utilities for creating reproducers -----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Reproduce.h" +#include "llvm/Option/Arg.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace lld; +using namespace llvm; +using namespace llvm::sys; + +// Makes a given pathname an absolute path first, and then remove +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", +// assuming that the current directory is "/home/john/bar". +// Returned string is a forward slash separated path even on Windows to avoid +// a mess with backslash-as-escape and backslash-as-path-separator. +std::string lld::relativeToRoot(StringRef Path) { + SmallString<128> Abs = Path; + if (fs::make_absolute(Abs)) + return Path; + path::remove_dots(Abs, /*remove_dot_dot=*/true); + + // This is Windows specific. root_name() returns a drive letter + // (e.g. "c:") or a UNC name (//net). We want to keep it as part + // of the result. + SmallString<128> Res; + StringRef Root = path::root_name(Abs); + if (Root.endswith(":")) + Res = Root.drop_back(); + else if (Root.startswith("//")) + Res = Root.substr(2); + + path::append(Res, path::relative_path(Abs)); + return path::convert_to_slash(Res); +} + +// Quote a given string if it contains a space character. +std::string lld::quote(StringRef S) { + if (S.find(' ') == StringRef::npos) + return S; + return ("\"" + S + "\"").str(); +} + +std::string lld::rewritePath(StringRef S) { + if (fs::exists(S)) + return relativeToRoot(S); + return S; +} + +std::string lld::toString(opt::Arg *Arg) { + std::string K = Arg->getSpelling(); + if (Arg->getNumValues() == 0) + return K; + std::string V = quote(Arg->getValue()); + if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) + return K + V; + return K + " " + V; +} diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp new file mode 100644 index 000000000..e7cfaaac7 --- /dev/null +++ b/lib/Core/Resolver.cpp @@ -0,0 +1,505 @@ +//===- Core/Resolver.cpp - Resolves Atom References -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/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/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +namespace lld { + +llvm::Expected Resolver::handleFile(File &file) { + if (auto ec = _ctx.handleLoadedFile(file)) + return std::move(ec); + bool undefAdded = false; + for (auto &atom : file.defined().owning_ptrs()) + doDefinedAtom(std::move(atom)); + for (auto &atom : file.undefined().owning_ptrs()) { + if (doUndefinedAtom(std::move(atom))) + undefAdded = true; + } + for (auto &atom : file.sharedLibrary().owning_ptrs()) + doSharedLibraryAtom(std::move(atom)); + for (auto &atom : file.absolute().owning_ptrs()) + doAbsoluteAtom(std::move(atom)); + return undefAdded; +} + +llvm::Expected Resolver::forEachUndefines(File &file, + UndefCallback callback) { + size_t i = _undefineIndex[&file]; + bool undefAdded = false; + do { + for (; i < _undefines.size(); ++i) { + StringRef undefName = _undefines[i]; + if (undefName.empty()) + continue; + const Atom *atom = _symbolTable.findByName(undefName); + if (!isa(atom) || _symbolTable.isCoalescedAway(atom)) { + // The symbol was resolved by some other file. Cache the result. + _undefines[i] = ""; + continue; + } + auto undefAddedOrError = callback(undefName); + if (auto ec = undefAddedOrError.takeError()) + return std::move(ec); + undefAdded |= undefAddedOrError.get(); + } + } while (i < _undefines.size()); + _undefineIndex[&file] = i; + return undefAdded; +} + +llvm::Expected Resolver::handleArchiveFile(File &file) { + ArchiveLibraryFile *archiveFile = cast(&file); + return forEachUndefines(file, + [&](StringRef undefName) -> llvm::Expected { + if (File *member = archiveFile->find(undefName)) { + member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + return handleFile(*member); + } + return false; + }); +} + +llvm::Error Resolver::handleSharedLibrary(File &file) { + // Add all the atoms from the shared library + SharedLibraryFile *sharedLibrary = cast(&file); + auto undefAddedOrError = handleFile(*sharedLibrary); + if (auto ec = undefAddedOrError.takeError()) + return ec; + undefAddedOrError = + forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected { + auto atom = sharedLibrary->exports(undefName); + if (atom.get()) + doSharedLibraryAtom(std::move(atom)); + return false; + }); + + if (auto ec = undefAddedOrError.takeError()) + return ec; + return llvm::Error::success(); +} + +bool Resolver::doUndefinedAtom(OwningAtomPtr atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " UndefinedAtom: " + << llvm::format("0x%09lX", atom.get()) + << ", name=" << atom.get()->name() << "\n"); + + // tell symbol table + bool newUndefAdded = _symbolTable.add(*atom.get()); + if (newUndefAdded) + _undefines.push_back(atom.get()->name()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); + + return newUndefAdded; +} + +// Called on each atom when a file is added. Returns true if a given +// atom is added to the symbol table. +void Resolver::doDefinedAtom(OwningAtomPtr atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " DefinedAtom: " + << llvm::format("0x%09lX", atom.get()) + << ", file=#" + << atom.get()->file().ordinal() + << ", atom=#" + << atom.get()->ordinal() + << ", name=" + << atom.get()->name() + << ", type=" + << atom.get()->contentType() + << "\n"); + + // An atom that should never be dead-stripped is a dead-strip root. + if (_ctx.deadStrip() && + atom.get()->deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(atom.get()); + } + + // add to list of known atoms + _symbolTable.add(*atom.get()); + _atoms.push_back(OwningAtomPtr(atom.release())); +} + +void Resolver::doSharedLibraryAtom(OwningAtomPtr atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " SharedLibraryAtom: " + << llvm::format("0x%09lX", atom.get()) + << ", name=" + << atom.get()->name() + << "\n"); + + // tell symbol table + _symbolTable.add(*atom.get()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); +} + +void Resolver::doAbsoluteAtom(OwningAtomPtr atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " AbsoluteAtom: " + << llvm::format("0x%09lX", atom.get()) + << ", name=" + << atom.get()->name() + << "\n"); + + // tell symbol table + if (atom.get()->scope() != Atom::scopeTranslationUnit) + _symbolTable.add(*atom.get()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); +} + +// Returns true if at least one of N previous files has created an +// undefined symbol. +bool Resolver::undefinesAdded(int begin, int end) { + std::vector> &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(); +} + +// Keep adding atoms until _ctx.getNextFile() returns an error. This +// function is where undefined atoms are resolved. +bool Resolver::resolveUndefines() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Resolving undefines:\n"); + ScopedTask task(getDefaultDomain(), "resolveUndefines"); + int index = 0; + std::set seen; + for (;;) { + bool undefAdded = false; + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "Loading file #" << index << "\n"); + File *file = getFile(index); + if (!file) + return true; + if (std::error_code ec = file->parse()) { + llvm::errs() << "Cannot open " + file->path() + << ": " << ec.message() << "\n"; + return false; + } + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "Loaded file: " << file->path() << "\n"); + switch (file->kind()) { + case File::kindErrorObject: + case File::kindNormalizedObject: + case File::kindMachObject: + case File::kindCEntryObject: + case File::kindHeaderObject: + case File::kindEntryObject: + case File::kindUndefinedSymsObject: + case File::kindStubHelperObject: + case File::kindResolverMergedObject: + case File::kindSectCreateObject: { + // The same file may be visited more than once if the file is + // in --start-group and --end-group. Only library files should + // be processed more than once. + if (seen.count(file)) + break; + seen.insert(file); + assert(!file->hasOrdinal()); + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + auto undefAddedOrError = handleFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); + break; + } + case File::kindArchiveLibrary: { + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + auto undefAddedOrError = handleArchiveFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); + break; + } + case File::kindSharedLibrary: + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + if (auto EC = handleSharedLibrary(*file)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + break; + } + _newUndefinesAdded[file] = undefAdded; + } +} + +// switch all references to undefined or coalesced away atoms +// to the new defined atom +void Resolver::updateReferences() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Updating references:\n"); + ScopedTask task(getDefaultDomain(), "updateReferences"); + for (const OwningAtomPtr &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) { + for (const Reference *ref : *defAtom) { + // A reference of type kindAssociate should't be updated. + // Instead, an atom having such reference will be removed + // if the target atom is coalesced away, so that they will + // go away as a group. + if (ref->kindNamespace() == lld::Reference::KindNamespace::all && + ref->kindValue() == lld::Reference::kindAssociate) { + if (_symbolTable.isCoalescedAway(atom.get())) + _deadAtoms.insert(ref->target()); + continue; + } + const Atom *newTarget = _symbolTable.replacement(ref->target()); + const_cast(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); +} + +// remove all atoms not actually used +void Resolver::deadStripOptimize() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Dead stripping unused atoms:\n"); + ScopedTask task(getDefaultDomain(), "deadStripOptimize"); + // only do this optimization with -dead_strip + if (!_ctx.deadStrip()) + return; + + // Some type of references prevent referring atoms to be dead-striped. + // Make a reverse map of such references before traversing the graph. + // While traversing the list of atoms, mark AbsoluteAtoms as live + // in order to avoid reclaim. + for (const OwningAtomPtr &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) + for (const Reference *ref : *defAtom) + if (isBackref(ref)) + _reverseRef.insert(std::make_pair(ref->target(), atom.get())); + if (const AbsoluteAtom *absAtom = dyn_cast(atom.get())) + markLive(absAtom); + } + + // By default, shared libraries are built with all globals as dead strip roots + if (_ctx.globalsAreDeadStripRoots()) + for (const OwningAtomPtr &atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) + if (defAtom->scope() == DefinedAtom::scopeGlobal) + _deadStripRoots.insert(defAtom); + + // Or, use list of names that are dead strip roots. + for (const StringRef &name : _ctx.deadStripRoots()) { + const Atom *symAtom = _symbolTable.findByName(name); + assert(symAtom); + _deadStripRoots.insert(symAtom); + } + + // mark all roots as live, and recursively all atoms they reference + for (const Atom *dsrAtom : _deadStripRoots) + markLive(dsrAtom); + + // now remove all non-live atoms from _atoms + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr &a) { + return _liveAtoms.count(a.get()) == 0; + }), + _atoms.end()); +} + +// error out if some undefines remain +bool Resolver::checkUndefines() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Checking for undefines:\n"); + + // build vector of remaining undefined symbols + std::vector 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() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Removing coalesced away atoms:\n"); + ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr &a) { + return _symbolTable.isCoalescedAway(a.get()) || + _deadAtoms.count(a.get()); + }), + _atoms.end()); +} + +bool Resolver::resolve() { + DEBUG_WITH_TYPE("resolver", + llvm::dbgs() << "******** Resolving atom references:\n"); + if (!resolveUndefines()) + return false; + updateReferences(); + deadStripOptimize(); + if (checkUndefines()) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Found undefines... "); + if (!_ctx.allowRemainingUndefines()) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we don't allow\n"); + return false; + } + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we are ok with\n"); + } + removeCoalescedAwayAtoms(); + _result->addAtoms(_atoms); + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Finished resolver\n"); + return true; +} + +void Resolver::MergedFile::addAtoms( + llvm::MutableArrayRef> all) { + ScopedTask task(getDefaultDomain(), "addAtoms"); + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); + + for (OwningAtomPtr &atom : all) { +#ifndef NDEBUG + if (auto *definedAtom = dyn_cast(atom.get())) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << llvm::format(" 0x%09lX", definedAtom) + << ", file=#" + << definedAtom->file().ordinal() + << ", atom=#" + << definedAtom->ordinal() + << ", name=" + << definedAtom->name() + << ", type=" + << definedAtom->contentType() + << "\n"); + } else { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << llvm::format(" 0x%09lX", atom.get()) + << ", name=" + << atom.get()->name() + << "\n"); + } +#endif + addAtom(*atom.release()); + } +} + +} // namespace lld diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp new file mode 100644 index 000000000..583c65acb --- /dev/null +++ b/lib/Core/SymbolTable.cpp @@ -0,0 +1,291 @@ +//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/SymbolTable.h" +#include "lld/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 { +bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const DefinedAtom &atom) { + if (!atom.name().empty() && + atom.scope() != DefinedAtom::scopeTranslationUnit) { + // Named atoms cannot be merged by content. + assert(atom.merge() != DefinedAtom::mergeByContent); + // Track named atoms that are not scoped to file (static). + return addByName(atom); + } + if (atom.merge() == DefinedAtom::mergeByContent) { + // Named atoms cannot be merged by content. + assert(atom.name().empty()); + // Currently only read-only constants can be merged. + if (atom.permissions() == DefinedAtom::permR__) + return addByContent(atom); + // TODO: support mergeByContent of data atoms by comparing content & fixups. + } + return false; +} + +enum NameCollisionResolution { + NCR_First, + NCR_Second, + NCR_DupDef, + NCR_DupUndef, + NCR_DupShLib, + NCR_Error +}; + +static NameCollisionResolution cases[4][4] = { + //regular absolute undef sharedLib + { + // first is regular + NCR_DupDef, NCR_Error, NCR_First, NCR_First + }, + { + // first is absolute + NCR_Error, NCR_Error, NCR_First, NCR_First + }, + { + // first is undef + NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second + }, + { + // first is sharedLib + NCR_Second, NCR_Second, NCR_First, NCR_DupShLib + } +}; + +static NameCollisionResolution collide(Atom::Definition first, + Atom::Definition second) { + return cases[first][second]; +} + +enum MergeResolution { + MCR_First, + MCR_Second, + MCR_Largest, + MCR_SameSize, + MCR_Error +}; + +static MergeResolution mergeCases[][6] = { + // no tentative weak weakAddress sameNameAndSize largest + {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no + {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative + {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak + {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress + {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize + {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest +}; + +static MergeResolution mergeSelect(DefinedAtom::Merge first, + DefinedAtom::Merge second) { + assert(first != DefinedAtom::mergeByContent); + assert(second != DefinedAtom::mergeByContent); + return mergeCases[first][second]; +} + +bool SymbolTable::addByName(const Atom &newAtom) { + StringRef name = newAtom.name(); + assert(!name.empty()); + const Atom *existing = findByName(name); + if (existing == nullptr) { + // Name is not in symbol table yet, add it associate with this atom. + _nameTable[name] = &newAtom; + return true; + } + + // Do nothing if the same object is added more than once. + if (existing == &newAtom) + return false; + + // Name is already in symbol table and associated with another atom. + bool useNew = true; + switch (collide(existing->definition(), newAtom.definition())) { + case NCR_First: + useNew = false; + break; + case NCR_Second: + useNew = true; + break; + case NCR_DupDef: { + const auto *existingDef = cast(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"; + LLVM_FALLTHROUGH; + } + case MCR_Error: + llvm::errs() << "Duplicate symbols: " + << existing->name() + << ":" + << existing->file().path() + << " and " + << newAtom.name() + << ":" + << newAtom.file().path() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + break; + } + break; + } + case NCR_DupUndef: { + const UndefinedAtom* existingUndef = cast(existing); + const UndefinedAtom* newUndef = cast(&newAtom); + + bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); + if (sameCanBeNull) + useNew = false; + else + useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); + break; + } + case NCR_DupShLib: { + useNew = false; + break; + } + case NCR_Error: + llvm::errs() << "SymbolTable: error while merging " << name << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + break; + } + + if (useNew) { + // Update name table to use new atom. + _nameTable[name] = &newAtom; + // Add existing atom to replacement table. + _replacedAtoms[existing] = &newAtom; + } else { + // New atom is not being used. Add it to replacement table. + _replacedAtoms[&newAtom] = existing; + } + return false; +} + +unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) { + auto content = atom->rawContent(); + return llvm::hash_combine(atom->size(), + atom->contentType(), + llvm::hash_combine_range(content.begin(), + content.end())); +} + +bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, + const DefinedAtom * const r) { + if (l == r) + return true; + if (l == getEmptyKey() || r == getEmptyKey()) + return false; + if (l == getTombstoneKey() || r == getTombstoneKey()) + return false; + if (l->contentType() != r->contentType()) + return false; + if (l->size() != r->size()) + return false; + if (l->sectionChoice() != r->sectionChoice()) + return false; + if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) { + if (!l->customSectionName().equals(r->customSectionName())) + return false; + } + ArrayRef 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; +} + +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; +} + +} // namespace lld diff --git a/lib/Core/TargetOptionsCommandFlags.cpp b/lib/Core/TargetOptionsCommandFlags.cpp new file mode 100644 index 000000000..e0f26761e --- /dev/null +++ b/lib/Core/TargetOptionsCommandFlags.cpp @@ -0,0 +1,32 @@ +//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file exists as a place for global variables defined in LLVM's +// CodeGen/CommandFlags.h. By putting the resulting object file in +// an archive and linking with it, the definitions will automatically be +// included when needed and skipped when already present. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/TargetOptionsCommandFlags.h" + +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/Target/TargetOptions.h" + +// Define an externally visible version of +// InitTargetOptionsFromCodeGenFlags, so that its functionality can be +// used without having to include llvm/CodeGen/CommandFlags.h, which +// would lead to multiple definitions of the command line flags. +llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { + return ::InitTargetOptionsFromCodeGenFlags(); +} + +llvm::CodeModel::Model lld::GetCodeModelFromCMModel() { + return CMModel; +} diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp new file mode 100644 index 000000000..51f95bc50 --- /dev/null +++ b/lib/Core/Writer.cpp @@ -0,0 +1,18 @@ +//===- lib/Core/Writer.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Writer.h" + +namespace lld { + +Writer::Writer() = default; + +Writer::~Writer() = default; + +} // end namespace lld diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt new file mode 100644 index 000000000..be7587286 --- /dev/null +++ b/lib/Driver/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td) +tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs) +add_public_tablegen_target(DriverOptionsTableGen) + +add_lld_library(lldDriver + DarwinLdDriver.cpp + + ADDITIONAL_HEADER_DIRS + ${LLD_INCLUDE_DIR}/lld/Driver + + LINK_COMPONENTS + Object + Option + Support + + LINK_LIBS + lldConfig + lldMachO + lldCore + lldReaderWriter + lldYAML + ) + +add_dependencies(lldDriver DriverOptionsTableGen) diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp new file mode 100644 index 000000000..f564d8cb8 --- /dev/null +++ b/lib/Driver/DarwinLdDriver.cpp @@ -0,0 +1,1239 @@ +//===- 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/ArchiveLibraryFile.h" +#include "lld/Core/Error.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Node.h" +#include "lld/Core/PassManager.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include +#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, VALUES) \ + OPT_##ID, +#include "DarwinLdOptions.inc" +#undef OPTION +}; + +// Create prefix string literals used in DarwinLdOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "DarwinLdOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in DarwinLdOptions.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "DarwinLdOptions.inc" +#undef OPTION +}; + +// Create OptTable class for parsing actual command line arguments +class DarwinLdOptTable : public llvm::opt::OptTable { +public: + DarwinLdOptTable() : OptTable(infoTable) {} +}; + +static std::vector> +makeErrorFile(StringRef path, std::error_code ec) { + std::vector> result; + result.push_back(llvm::make_unique(path, ec)); + return result; +} + +static std::vector> +parseMemberFiles(std::unique_ptr file) { + std::vector> members; + if (auto *archive = dyn_cast(file.get())) { + if (std::error_code ec = archive->parseAllMembers(members)) + return makeErrorFile(file->path(), ec); + } else { + members.push_back(std::move(file)); + } + return members; +} + +std::vector> +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); + ErrorOr> fileOrErr = + ctx.registry().loadFile(std::move(mbOrErr.get())); + if (std::error_code ec = fileOrErr.getError()) + return makeErrorFile(path, ec); + std::unique_ptr &file = fileOrErr.get(); + + // If file is a dylib, inform LinkingContext about it. + if (SharedLibraryFile *shl = dyn_cast(file.get())) { + if (std::error_code ec = shl->parse()) + return makeErrorFile(path, ec); + ctx.registerDylib(reinterpret_cast(shl), + upwardDylib); + } + if (wholeArchive) + return parseMemberFiles(std::move(file)); + std::vector> files; + files.push_back(std::move(file)); + return files; +} + +} // end anonymous namespace + +// Test may be running on Windows. Canonicalize the path +// separator to '/' to get consistent outputs for tests. +static std::string canonicalizePath(StringRef path) { + char sep = llvm::sys::path::get_separator().front(); + if (sep != '/') { + std::string fixedPath = path; + std::replace(fixedPath.begin(), fixedPath.end(), sep, '/'); + return fixedPath; + } else { + return path; + } +} + +static void addFile(StringRef path, MachOLinkingContext &ctx, + bool loadWholeArchive, + bool upwardDylib, 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 llvm::Error 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 llvm::errorCodeToError(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 llvm::make_error(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 llvm::Error::success(); +} + +/// Parse number assuming it is base 16, but allow 0x prefix. +static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { + if (numStr.startswith_lower("0x")) + numStr = numStr.drop_front(2); + return numStr.getAsInteger(16, baseAddress); +} + +static void parseLLVMOptions(const LinkingContext &ctx) { + // Honor -mllvm + if (!ctx.llvmOptions().empty()) { + unsigned numArgs = ctx.llvmOptions().size(); + auto **args = new const char *[numArgs + 2]; + args[0] = "lld (LLVM option parsing)"; + for (unsigned i = 0; i != numArgs; ++i) + args[i + 1] = ctx.llvmOptions()[i]; + args[numArgs + 1] = nullptr; + llvm::cl::ParseCommandLineOptions(numArgs + 1, args); + } +} + +namespace lld { +namespace mach_o { + +bool parse(llvm::ArrayRef args, MachOLinkingContext &ctx, + raw_ostream &diagnostics) { + // Parse command line options using DarwinLdOptions.td + DarwinLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + llvm::opt::InputArgList parsedArgs = + table.ParseArgs(args.slice(1), missingIndex, missingCount); + if (missingCount) { + 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; + bool isStaticExecutable = false; + if (llvm::opt::Arg *kind = parsedArgs.getLastArg( + OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { + switch (kind->getOption().getID()) { + case OPT_dylib: + fileType = llvm::MachO::MH_DYLIB; + break; + case OPT_relocatable: + fileType = llvm::MachO::MH_OBJECT; + break; + case OPT_bundle: + fileType = llvm::MachO::MH_BUNDLE; + break; + case OPT_static: + fileType = llvm::MachO::MH_EXECUTE; + isStaticExecutable = true; + break; + case OPT_preload: + fileType = llvm::MachO::MH_PRELOAD; + break; + } + } + + // Handle -arch xxx + MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown; + if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) { + arch = MachOLinkingContext::archFromName(archStr->getValue()); + if (arch == MachOLinkingContext::arch_unknown) { + 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(), args[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::unknown; + uint32_t minOSVersion = 0; + if (llvm::opt::Arg *minOS = + parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min, + OPT_ios_simulator_version_min)) { + switch (minOS->getOption().getID()) { + case OPT_macosx_version_min: + os = MachOLinkingContext::OS::macOSX; + if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), + minOSVersion)) { + 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 + } + + // Handle export_dynamic + // FIXME: Should we warn when this applies to something other than a static + // executable or dylib? Those are the only cases where this has an effect. + // Note, this has to come before ctx.configure() so that we get the correct + // value for _globalsAreDeadStripRoots. + bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic); + + // Now that there's enough information parsed in, let the linking context + // set up default values. + ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) + ctx.setEntrySymbolName(entry->getValue()); + + // Handle -o xxx + if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output)) + ctx.setOutputPath(outpath->getValue()); + else + ctx.setOutputPath("a.out"); + + // Handle -image_base XXX and -seg1addr XXXX + if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) { + uint64_t baseAddress; + if (parseNumberBase16(imageBase->getValue(), baseAddress)) { + 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 (" + << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; + return false; + } + + ctx.setBaseAddress(baseAddress); + } + + // Handle -dead_strip + if (parsedArgs.getLastArg(OPT_dead_strip)) + ctx.setDeadStripping(true); + + bool globalWholeArchive = false; + // Handle -all_load + if (parsedArgs.getLastArg(OPT_all_load)) + globalWholeArchive = true; + + // Handle -install_name + if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name)) + ctx.setInstallName(installName->getValue()); + else + ctx.setInstallName(ctx.outputPath()); + + // Handle -mark_dead_strippable_dylib + if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib)) + ctx.setDeadStrippableDylib(true); + + // Handle -compatibility_version and -current_version + if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) { + if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { + 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; + } + uint16_t align = 1 << llvm::countTrailingZeros(alignValue); + if (!llvm::isPowerOf2_64(alignValue)) { + diagnostics << "warning: alignment for '-sectalign " + << segName << " " << sectName + << llvm::format(" 0x%llX", alignValue) + << "' is not a power of two, using " + << llvm::format("0x%08X", align) << "\n"; + } + ctx.addSectionAlignment(segName, sectName, align); + } + + // Handle -mllvm + for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) { + ctx.appendLLVMOption(llvmArg->getValue()); + } + + // Handle -print_atoms + if (parsedArgs.getLastArg(OPT_print_atoms)) + ctx.setPrintAtoms(); + + // Handle -t (trace) option. + if (parsedArgs.getLastArg(OPT_t)) + ctx.setLogInputFiles(true); + + // Handle -demangle option. + if (parsedArgs.getLastArg(OPT_demangle)) + ctx.setDemangleSymbols(true); + + // Handle -keep_private_externs + if (parsedArgs.getLastArg(OPT_keep_private_externs)) { + ctx.setKeepPrivateExterns(true); + if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) + 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().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 obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only + if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { + diagnostics << "error: -objc_gc_compaction is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc)) { + diagnostics << "error: -objc_gc is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc_only)) { + diagnostics << "error: -objc_gc_only is not supported\n"; + return false; + } + + // Handle -pie or -no_pie + if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) { + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_EXECUTE: + switch (ctx.os()) { + case MachOLinkingContext::OS::macOSX: + if ((minOSVersion < 0x000A0500) && + (pie->getOption().getID() == OPT_pie)) { + 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; + } + } + + // Handle -version_load_command or -no_version_load_command + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command, + OPT_no_version_load_command)) { + flagOn = arg->getOption().getID() == OPT_version_load_command; + flagOff = arg->getOption().getID() == OPT_no_version_load_command; + } + + // default to adding version load command for dynamic code, + // static code must opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + ctx.setGenerateVersionLoadCommand(false); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle -function_starts or -no_function_starts + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_function_starts, + OPT_no_function_starts)) { + flagOn = arg->getOption().getID() == OPT_function_starts; + flagOff = arg->getOption().getID() == OPT_no_function_starts; + } + + // default to adding functions start for dynamic code, static code must + // opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + ctx.setGenerateFunctionStartsLoadCommand(false); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateFunctionStartsLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateFunctionStartsLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateFunctionStartsLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateFunctionStartsLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle -data_in_code_info or -no_data_in_code_info + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info, + OPT_no_data_in_code_info)) { + flagOn = arg->getOption().getID() == OPT_data_in_code_info; + flagOff = arg->getOption().getID() == OPT_no_data_in_code_info; + } + + // default to adding data in code for dynamic code, static code must + // opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateDataInCodeLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle sdk_version + if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) { + uint32_t sdkVersion = 0; + if (MachOLinkingContext::parsePackedVersion(arg->getValue(), + sdkVersion)) { + diagnostics << "error: malformed sdkVersion value\n"; + return false; + } + ctx.setSdkVersion(sdkVersion); + } else if (ctx.generateVersionLoadCommand()) { + // If we don't have an sdk version, but were going to emit a load command + // with min_version, then we need to give an warning as we have no sdk + // version to put in that command. + // FIXME: We need to decide whether to make this an error. + diagnostics << "warning: -sdk_version is required when emitting " + "min version load command. " + "Setting sdk version to match provided min version\n"; + ctx.setSdkVersion(ctx.osMinVersion()); + } + + // Handle source_version + if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) { + uint64_t version = 0; + if (MachOLinkingContext::parsePackedVersion(arg->getValue(), + version)) { + diagnostics << "error: malformed source_version value\n"; + return false; + } + ctx.setSourceVersion(version); + } + + // Handle stack_size + if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { + uint64_t stackSizeVal; + if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) { + diagnostics << "error: stack_size expects a hex number\n"; + return false; + } + if ((stackSizeVal % ctx.pageSize()) != 0) { + diagnostics << "error: stack_size must be a multiple of page size (" + << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; + return false; + } + + ctx.setStackSize(stackSizeVal); + } + + // Handle debug info handling options: -S + if (parsedArgs.hasArg(OPT_S)) + 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 -flat_namespace. + if (llvm::opt::Arg *ns = + parsedArgs.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) { + if (ns->getOption().getID() == OPT_flat_namespace) + ctx.setUseFlatNamespace(true); + } + + // Handle -undefined + if (llvm::opt::Arg *undef = parsedArgs.getLastArg(OPT_undefined)) { + MachOLinkingContext::UndefinedMode UndefMode; + if (StringRef(undef->getValue()).equals("error")) + UndefMode = MachOLinkingContext::UndefinedMode::error; + else if (StringRef(undef->getValue()).equals("warning")) + UndefMode = MachOLinkingContext::UndefinedMode::warning; + else if (StringRef(undef->getValue()).equals("suppress")) + UndefMode = MachOLinkingContext::UndefinedMode::suppress; + else if (StringRef(undef->getValue()).equals("dynamic_lookup")) + UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup; + else { + diagnostics << "error: invalid option to -undefined " + "[ warning | error | suppress | dynamic_lookup ]\n"; + return false; + } + + if (ctx.useFlatNamespace()) { + // If we're using -flat_namespace then 'warning', 'suppress' and + // 'dynamic_lookup' are all equivalent, so map them to 'suppress'. + if (UndefMode != MachOLinkingContext::UndefinedMode::error) + UndefMode = MachOLinkingContext::UndefinedMode::suppress; + } else { + // If we're using -twolevel_namespace then 'warning' and 'suppress' are + // illegal. Emit a diagnostic if they've been (mis)used. + if (UndefMode == MachOLinkingContext::UndefinedMode::warning || + UndefMode == MachOLinkingContext::UndefinedMode::suppress) { + diagnostics << "error: can't use -undefined warning or suppress with " + "-twolevel_namespace\n"; + return false; + } + } + + ctx.setUndefinedMode(UndefMode); + } + + // Handle -no_objc_category_merging. + if (parsedArgs.getLastArg(OPT_no_objc_category_merging)) + ctx.setMergeObjCCategories(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()); + } + } + + // Parse the LLVM options before we process files in case the file handling + // makes use of things like DEBUG(). + parseLLVMOptions(ctx); + + // Handle input files and sectcreate. + for (auto &arg : parsedArgs) { + bool upward; + llvm::Optional resolvedPath; + 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.getValue()) << '\n'; + } + addFile(resolvedPath.getValue(), 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.getValue()) << '\n'; + } + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, + upward, diagnostics); + break; + case OPT_filelist: + if (auto ec = loadFileList(arg->getValue(), + ctx, globalWholeArchive, + diagnostics)) { + handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { + diagnostics << "error: "; + EI.log(diagnostics); + diagnostics << ", processing '-filelist " << arg->getValue() << "'\n"; + }); + return false; + } + break; + case OPT_sectcreate: { + const char* seg = arg->getValue(0); + const char* sect = arg->getValue(1); + const char* fileName = arg->getValue(2); + + ErrorOr> contentOrErr = + MemoryBuffer::getFile(fileName); + + if (!contentOrErr) { + diagnostics << "error: can't open -sectcreate file " << fileName << "\n"; + return false; + } + + ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr)); + } + break; + } + } + + if (ctx.getNodes().empty()) { + diagnostics << "No input files\n"; + return false; + } + + // Validate the combination of options used. + return ctx.validate(diagnostics); +} + +static void createFiles(MachOLinkingContext &ctx, bool Implicit) { + std::vector> Files; + if (Implicit) + ctx.createImplicitFiles(Files); + else + ctx.createInternalFiles(Files); + for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique(std::move(*i))); + } +} + +/// This is where the link is actually performed. +bool link(llvm::ArrayRef args, raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (!parse(args, ctx, diagnostics)) + return false; + if (ctx.doNothing()) + return true; + if (ctx.getNodes().empty()) + return false; + + for (std::unique_ptr &ie : ctx.getNodes()) + if (FileNode *node = dyn_cast(ie.get())) + node->getFile()->parse(); + + createFiles(ctx, false /* Implicit */); + + // Give target a chance to add files + createFiles(ctx, true /* Implicit */); + + // Give target a chance to postprocess input files. + // Mach-O uses this chance to move all object files before library files. + ctx.finalizeInputFiles(); + + // Do core linking. + ScopedTask resolveTask(getDefaultDomain(), "Resolve"); + Resolver resolver(ctx); + if (!resolver.resolve()) + return false; + SimpleFile *merged = nullptr; + { + std::unique_ptr mergedFile = resolver.resultFile(); + merged = mergedFile.get(); + auto &members = ctx.getNodes(); + members.insert(members.begin(), + llvm::make_unique(std::move(mergedFile))); + } + resolveTask.end(); + + // Run passes on linked atoms. + ScopedTask passTask(getDefaultDomain(), "Passes"); + PassManager pm; + ctx.addPasses(pm); + if (auto ec = pm.runOnFile(*merged)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + diagnostics << "Failed to run passes on file '" << ctx.outputPath() + << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + return false; + } + + passTask.end(); + + // Give linked atoms to Writer to generate output file. + ScopedTask writeTask(getDefaultDomain(), "Write"); + if (auto ec = ctx.writeFile(*merged)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + diagnostics << "Failed to write file '" << ctx.outputPath() << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + return false; + } + + return true; +} + +} // end namespace mach_o +} // end namespace lld diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td new file mode 100644 index 000000000..fa07f3364 --- /dev/null +++ b/lib/Driver/DarwinLdOptions.td @@ -0,0 +1,242 @@ +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 sdk_version : Separate<["-"], "sdk_version">, + MetaVarName<"">, + HelpText<"SDK version">, Group; +def source_version : Separate<["-"], "source_version">, + MetaVarName<"">, + HelpText<"Source version">, Group; +def version_load_command : Flag<["-"], "version_load_command">, + HelpText<"Force generation of a version load command">, Group; +def no_version_load_command : Flag<["-"], "no_version_load_command">, + HelpText<"Disable generation of a version load command">, Group; +def function_starts : Flag<["-"], "function_starts">, + HelpText<"Force generation of a function starts load command">, + Group; +def no_function_starts : Flag<["-"], "no_function_starts">, + HelpText<"Disable generation of a function starts load command">, + Group; +def data_in_code_info : Flag<["-"], "data_in_code_info">, + HelpText<"Force generation of a data in code load command">, + Group; +def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">, + HelpText<"Disable generation of a data in code load command">, + Group; +def mllvm : Separate<["-"], "mllvm">, + MetaVarName<"