Import llvm-toolchain-3.9_3.9.1.orig-lld.tar.bz2
authorSylvestre Ledru <sylvestre@debian.org>
Wed, 14 Dec 2016 08:22:02 +0000 (08:22 +0000)
committerSylvestre Ledru <sylvestre@debian.org>
Wed, 14 Dec 2016 08:22:02 +0000 (08:22 +0000)
[dgit import orig llvm-toolchain-3.9_3.9.1.orig-lld.tar.bz2]

1118 files changed:
.arcconfig [new file with mode: 0644]
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CODE_OWNERS.TXT [new file with mode: 0644]
COFF/CMakeLists.txt [new file with mode: 0644]
COFF/Chunks.cpp [new file with mode: 0644]
COFF/Chunks.h [new file with mode: 0644]
COFF/Config.h [new file with mode: 0644]
COFF/DLL.cpp [new file with mode: 0644]
COFF/DLL.h [new file with mode: 0644]
COFF/Driver.cpp [new file with mode: 0644]
COFF/Driver.h [new file with mode: 0644]
COFF/DriverUtils.cpp [new file with mode: 0644]
COFF/Error.cpp [new file with mode: 0644]
COFF/Error.h [new file with mode: 0644]
COFF/ICF.cpp [new file with mode: 0644]
COFF/InputFiles.cpp [new file with mode: 0644]
COFF/InputFiles.h [new file with mode: 0644]
COFF/Librarian.cpp [new file with mode: 0644]
COFF/MarkLive.cpp [new file with mode: 0644]
COFF/ModuleDef.cpp [new file with mode: 0644]
COFF/Options.td [new file with mode: 0644]
COFF/PDB.cpp [new file with mode: 0644]
COFF/README.md [new file with mode: 0644]
COFF/SymbolTable.cpp [new file with mode: 0644]
COFF/SymbolTable.h [new file with mode: 0644]
COFF/Symbols.cpp [new file with mode: 0644]
COFF/Symbols.h [new file with mode: 0644]
COFF/Writer.cpp [new file with mode: 0644]
COFF/Writer.h [new file with mode: 0644]
ELF/CMakeLists.txt [new file with mode: 0644]
ELF/Config.h [new file with mode: 0644]
ELF/Driver.cpp [new file with mode: 0644]
ELF/Driver.h [new file with mode: 0644]
ELF/DriverUtils.cpp [new file with mode: 0644]
ELF/EhFrame.cpp [new file with mode: 0644]
ELF/EhFrame.h [new file with mode: 0644]
ELF/Error.cpp [new file with mode: 0644]
ELF/Error.h [new file with mode: 0644]
ELF/ICF.cpp [new file with mode: 0644]
ELF/ICF.h [new file with mode: 0644]
ELF/InputFiles.cpp [new file with mode: 0644]
ELF/InputFiles.h [new file with mode: 0644]
ELF/InputSection.cpp [new file with mode: 0644]
ELF/InputSection.h [new file with mode: 0644]
ELF/LTO.cpp [new file with mode: 0644]
ELF/LTO.h [new file with mode: 0644]
ELF/LinkerScript.cpp [new file with mode: 0644]
ELF/LinkerScript.h [new file with mode: 0644]
ELF/MarkLive.cpp [new file with mode: 0644]
ELF/Options.td [new file with mode: 0644]
ELF/OutputSections.cpp [new file with mode: 0644]
ELF/OutputSections.h [new file with mode: 0644]
ELF/README.md [new file with mode: 0644]
ELF/Relocations.cpp [new file with mode: 0644]
ELF/Relocations.h [new file with mode: 0644]
ELF/ScriptParser.cpp [new file with mode: 0644]
ELF/ScriptParser.h [new file with mode: 0644]
ELF/Strings.cpp [new file with mode: 0644]
ELF/Strings.h [new file with mode: 0644]
ELF/SymbolListFile.cpp [new file with mode: 0644]
ELF/SymbolListFile.h [new file with mode: 0644]
ELF/SymbolTable.cpp [new file with mode: 0644]
ELF/SymbolTable.h [new file with mode: 0644]
ELF/Symbols.cpp [new file with mode: 0644]
ELF/Symbols.h [new file with mode: 0644]
ELF/Target.cpp [new file with mode: 0644]
ELF/Target.h [new file with mode: 0644]
ELF/Thunks.cpp [new file with mode: 0644]
ELF/Thunks.h [new file with mode: 0644]
ELF/Writer.cpp [new file with mode: 0644]
ELF/Writer.h [new file with mode: 0644]
LICENSE.TXT [new file with mode: 0644]
README.md [new file with mode: 0644]
cmake/modules/FindVTune.cmake [new file with mode: 0644]
docs/AtomLLD.rst [new file with mode: 0644]
docs/C++11.rst [new file with mode: 0644]
docs/CMakeLists.txt [new file with mode: 0644]
docs/Driver.rst [new file with mode: 0644]
docs/NewLLD.rst [new file with mode: 0644]
docs/README.txt [new file with mode: 0644]
docs/Readers.rst [new file with mode: 0644]
docs/ReleaseNotes.rst [new file with mode: 0644]
docs/_static/favicon.ico [new file with mode: 0644]
docs/_templates/indexsidebar.html [new file with mode: 0644]
docs/_templates/layout.html [new file with mode: 0644]
docs/conf.py [new file with mode: 0644]
docs/design.rst [new file with mode: 0644]
docs/development.rst [new file with mode: 0644]
docs/getting_started.rst [new file with mode: 0644]
docs/hello.png [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/llvm-theme/layout.html [new file with mode: 0644]
docs/llvm-theme/static/contents.png [new file with mode: 0644]
docs/llvm-theme/static/llvm.css [new file with mode: 0644]
docs/llvm-theme/static/logo.png [new file with mode: 0644]
docs/llvm-theme/static/navigation.png [new file with mode: 0644]
docs/llvm-theme/theme.conf [new file with mode: 0644]
docs/make.bat [new file with mode: 0644]
docs/open_projects.rst [new file with mode: 0644]
docs/sphinx_intro.rst [new file with mode: 0644]
docs/windows_support.rst [new file with mode: 0644]
include/lld/Config/Version.h [new file with mode: 0644]
include/lld/Config/Version.inc.in [new file with mode: 0644]
include/lld/Core/AbsoluteAtom.h [new file with mode: 0644]
include/lld/Core/ArchiveLibraryFile.h [new file with mode: 0644]
include/lld/Core/Atom.h [new file with mode: 0644]
include/lld/Core/DefinedAtom.h [new file with mode: 0644]
include/lld/Core/Error.h [new file with mode: 0644]
include/lld/Core/File.h [new file with mode: 0644]
include/lld/Core/Instrumentation.h [new file with mode: 0644]
include/lld/Core/LLVM.h [new file with mode: 0644]
include/lld/Core/LinkingContext.h [new file with mode: 0644]
include/lld/Core/Node.h [new file with mode: 0644]
include/lld/Core/Parallel.h [new file with mode: 0644]
include/lld/Core/Pass.h [new file with mode: 0644]
include/lld/Core/PassManager.h [new file with mode: 0644]
include/lld/Core/Reader.h [new file with mode: 0644]
include/lld/Core/Reference.h [new file with mode: 0644]
include/lld/Core/Resolver.h [new file with mode: 0644]
include/lld/Core/SharedLibraryAtom.h [new file with mode: 0644]
include/lld/Core/SharedLibraryFile.h [new file with mode: 0644]
include/lld/Core/Simple.h [new file with mode: 0644]
include/lld/Core/SymbolTable.h [new file with mode: 0644]
include/lld/Core/TODO.txt [new file with mode: 0644]
include/lld/Core/UndefinedAtom.h [new file with mode: 0644]
include/lld/Core/Writer.h [new file with mode: 0644]
include/lld/Driver/Driver.h [new file with mode: 0644]
include/lld/ReaderWriter/MachOLinkingContext.h [new file with mode: 0644]
include/lld/ReaderWriter/YamlContext.h [new file with mode: 0644]
lib/CMakeLists.txt [new file with mode: 0644]
lib/Config/CMakeLists.txt [new file with mode: 0644]
lib/Config/Version.cpp [new file with mode: 0644]
lib/Core/CMakeLists.txt [new file with mode: 0644]
lib/Core/DefinedAtom.cpp [new file with mode: 0644]
lib/Core/Error.cpp [new file with mode: 0644]
lib/Core/File.cpp [new file with mode: 0644]
lib/Core/LinkingContext.cpp [new file with mode: 0644]
lib/Core/Reader.cpp [new file with mode: 0644]
lib/Core/Resolver.cpp [new file with mode: 0644]
lib/Core/SymbolTable.cpp [new file with mode: 0644]
lib/Core/Writer.cpp [new file with mode: 0644]
lib/Driver/CMakeLists.txt [new file with mode: 0644]
lib/Driver/DarwinLdDriver.cpp [new file with mode: 0644]
lib/Driver/DarwinLdOptions.td [new file with mode: 0644]
lib/ReaderWriter/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/FileArchive.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_arm.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_arm64.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_x86.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/Atoms.h [new file with mode: 0644]
lib/ReaderWriter/MachO/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/MachO/CompactUnwindPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ExecutableAtoms.h [new file with mode: 0644]
lib/ReaderWriter/MachO/File.h [new file with mode: 0644]
lib/ReaderWriter/MachO/FlatNamespaceFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/GOTPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/LayoutPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/LayoutPass.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachOLinkingContext.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachOPasses.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ObjCPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/SectCreateFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ShimPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/StubsPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/TLVPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/WriterMachO.cpp [new file with mode: 0644]
lib/ReaderWriter/YAML/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/YAML/ReaderWriterYAML.cpp [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/COFF/Inputs/armnt-executable.obj.yaml [new file with mode: 0644]
test/COFF/Inputs/armnt-executable.s [new file with mode: 0644]
test/COFF/Inputs/conflict.ll [new file with mode: 0644]
test/COFF/Inputs/entry-mangled.ll [new file with mode: 0644]
test/COFF/Inputs/export.ll [new file with mode: 0644]
test/COFF/Inputs/export.yaml [new file with mode: 0644]
test/COFF/Inputs/export2.yaml [new file with mode: 0644]
test/COFF/Inputs/hello32.yaml [new file with mode: 0644]
test/COFF/Inputs/hello64.asm [new file with mode: 0644]
test/COFF/Inputs/hello64.obj [new file with mode: 0644]
test/COFF/Inputs/import.yaml [new file with mode: 0644]
test/COFF/Inputs/imports-mangle.lib [new file with mode: 0644]
test/COFF/Inputs/include1a.yaml [new file with mode: 0644]
test/COFF/Inputs/include1b.yaml [new file with mode: 0644]
test/COFF/Inputs/include1c.yaml [new file with mode: 0644]
test/COFF/Inputs/library.lib [new file with mode: 0755]
test/COFF/Inputs/lto-chkstk-chkstk.s [new file with mode: 0644]
test/COFF/Inputs/lto-chkstk-foo.s [new file with mode: 0644]
test/COFF/Inputs/lto-comdat1.ll [new file with mode: 0644]
test/COFF/Inputs/lto-comdat2.ll [new file with mode: 0644]
test/COFF/Inputs/lto-dep.ll [new file with mode: 0644]
test/COFF/Inputs/machine-x64.yaml [new file with mode: 0644]
test/COFF/Inputs/machine-x86.yaml [new file with mode: 0644]
test/COFF/Inputs/manifestinput.test [new file with mode: 0644]
test/COFF/Inputs/resource.res [new file with mode: 0644]
test/COFF/Inputs/ret42.lib [new file with mode: 0644]
test/COFF/Inputs/ret42.obj [new file with mode: 0644]
test/COFF/Inputs/ret42.yaml [new file with mode: 0644]
test/COFF/Inputs/std32.lib [new file with mode: 0644]
test/COFF/Inputs/std64.lib [new file with mode: 0644]
test/COFF/Inputs/weak-external.ll [new file with mode: 0644]
test/COFF/Inputs/weak-external2.ll [new file with mode: 0644]
test/COFF/Inputs/weak-external3.ll [new file with mode: 0644]
test/COFF/alternatename.test [new file with mode: 0644]
test/COFF/ar-comdat.test [new file with mode: 0644]
test/COFF/armnt-blx23t.test [new file with mode: 0644]
test/COFF/armnt-branch24t.test [new file with mode: 0644]
test/COFF/armnt-entry-point.test [new file with mode: 0644]
test/COFF/armnt-imports.test [new file with mode: 0644]
test/COFF/armnt-mov32t-exec.test [new file with mode: 0644]
test/COFF/armnt-movt32t.test [new file with mode: 0644]
test/COFF/base.test [new file with mode: 0644]
test/COFF/baserel.test [new file with mode: 0644]
test/COFF/common.test [new file with mode: 0644]
test/COFF/conflict.test [new file with mode: 0644]
test/COFF/debug.test [new file with mode: 0644]
test/COFF/defparser.test [new file with mode: 0644]
test/COFF/delayimports.test [new file with mode: 0644]
test/COFF/delayimports32.test [new file with mode: 0644]
test/COFF/dll.test [new file with mode: 0644]
test/COFF/driver.test [new file with mode: 0644]
test/COFF/entry-inference.test [new file with mode: 0644]
test/COFF/entry-inference2.test [new file with mode: 0644]
test/COFF/entry-inference32.test [new file with mode: 0644]
test/COFF/entry-mangled.test [new file with mode: 0644]
test/COFF/entrylib.ll [new file with mode: 0644]
test/COFF/export-exe.test [new file with mode: 0644]
test/COFF/export.test [new file with mode: 0644]
test/COFF/export32.test [new file with mode: 0644]
test/COFF/failifmismatch.test [new file with mode: 0644]
test/COFF/filetype.test [new file with mode: 0644]
test/COFF/force.test [new file with mode: 0644]
test/COFF/heap.test [new file with mode: 0644]
test/COFF/hello32.test [new file with mode: 0644]
test/COFF/help.test [new file with mode: 0644]
test/COFF/icf-circular.test [new file with mode: 0644]
test/COFF/icf-circular2.test [new file with mode: 0644]
test/COFF/icf-different-align.test [new file with mode: 0644]
test/COFF/icf-local.test [new file with mode: 0644]
test/COFF/icf-simple.test [new file with mode: 0644]
test/COFF/imports-mangle.test [new file with mode: 0644]
test/COFF/imports.test [new file with mode: 0644]
test/COFF/include.test [new file with mode: 0644]
test/COFF/include2.test [new file with mode: 0644]
test/COFF/internal.test [new file with mode: 0644]
test/COFF/invalid-obj.test [new file with mode: 0644]
test/COFF/largeaddressaware.test [new file with mode: 0644]
test/COFF/libpath.test [new file with mode: 0644]
test/COFF/linkenv.test [new file with mode: 0644]
test/COFF/lldmap.test [new file with mode: 0644]
test/COFF/loadcfg.ll [new file with mode: 0644]
test/COFF/loadcfg.test [new file with mode: 0644]
test/COFF/loadcfg32.test [new file with mode: 0644]
test/COFF/locally-imported.test [new file with mode: 0644]
test/COFF/locally-imported32.test [new file with mode: 0644]
test/COFF/long-section-name.test [new file with mode: 0644]
test/COFF/lto-chkstk.ll [new file with mode: 0644]
test/COFF/lto-comdat.ll [new file with mode: 0644]
test/COFF/lto-linker-opts.ll [new file with mode: 0644]
test/COFF/lto-new-symbol.ll [new file with mode: 0644]
test/COFF/lto-opt-level.ll [new file with mode: 0644]
test/COFF/lto-parallel.ll [new file with mode: 0644]
test/COFF/lto.ll [new file with mode: 0644]
test/COFF/machine.test [new file with mode: 0644]
test/COFF/manifest.test [new file with mode: 0644]
test/COFF/manifestinput.test [new file with mode: 0644]
test/COFF/merge.test [new file with mode: 0644]
test/COFF/nodefaultlib.test [new file with mode: 0644]
test/COFF/noentry.test [new file with mode: 0644]
test/COFF/opt.test [new file with mode: 0644]
test/COFF/options.test [new file with mode: 0644]
test/COFF/order.test [new file with mode: 0644]
test/COFF/out.test [new file with mode: 0644]
test/COFF/reloc-arm.test [new file with mode: 0644]
test/COFF/reloc-x64.test [new file with mode: 0644]
test/COFF/reloc-x86.test [new file with mode: 0644]
test/COFF/resource.test [new file with mode: 0644]
test/COFF/responsefile.test [new file with mode: 0644]
test/COFF/safeseh.test [new file with mode: 0644]
test/COFF/section.test [new file with mode: 0644]
test/COFF/seh.test [new file with mode: 0644]
test/COFF/sort-debug.test [new file with mode: 0644]
test/COFF/stack.test [new file with mode: 0644]
test/COFF/subsystem-inference.test [new file with mode: 0644]
test/COFF/subsystem.test [new file with mode: 0644]
test/COFF/symtab.test [new file with mode: 0644]
test/COFF/tls.test [new file with mode: 0644]
test/COFF/tls32.test [new file with mode: 0644]
test/COFF/unwind.test [new file with mode: 0644]
test/COFF/version.test [new file with mode: 0644]
test/COFF/weak-external.test [new file with mode: 0644]
test/COFF/weak-external2.test [new file with mode: 0644]
test/COFF/weak-external3.test [new file with mode: 0644]
test/Driver/Inputs/libtest.a [new file with mode: 0644]
test/Driver/Inputs/usr/lib/i386/libtest.a [new file with mode: 0644]
test/Driver/Inputs/usr/lib/libtest.a [new file with mode: 0644]
test/ELF/Inputs/aarch64-condb-reloc.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-copy2.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tls-gdie.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tls-ie.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tstbr14-reloc.s [new file with mode: 0644]
test/ELF/Inputs/abs-hidden.s [new file with mode: 0644]
test/ELF/Inputs/abs.s [new file with mode: 0644]
test/ELF/Inputs/abs255.s [new file with mode: 0644]
test/ELF/Inputs/abs256.s [new file with mode: 0644]
test/ELF/Inputs/abs257.s [new file with mode: 0644]
test/ELF/Inputs/allow-multiple-definition.s [new file with mode: 0644]
test/ELF/Inputs/allow-shlib-undefined.s [new file with mode: 0644]
test/ELF/Inputs/archive.s [new file with mode: 0644]
test/ELF/Inputs/archive2.s [new file with mode: 0644]
test/ELF/Inputs/archive3.s [new file with mode: 0644]
test/ELF/Inputs/archive4.s [new file with mode: 0644]
test/ELF/Inputs/arm-plt-reloc.s [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-blx-targets.s [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-narrow-branch.o [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-narrow-branch.s [new file with mode: 0644]
test/ELF/Inputs/comdat.s [new file with mode: 0644]
test/ELF/Inputs/common.s [new file with mode: 0644]
test/ELF/Inputs/conflict.s [new file with mode: 0644]
test/ELF/Inputs/copy-in-shared.s [new file with mode: 0644]
test/ELF/Inputs/copy-rel-corrupted.s [new file with mode: 0644]
test/ELF/Inputs/copy-rel-pie.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority1.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority2.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority3.s [new file with mode: 0644]
test/ELF/Inputs/discard-merge-unnamed.o [new file with mode: 0644]
test/ELF/Inputs/duplicated-plt-entry.s [new file with mode: 0644]
test/ELF/Inputs/dynamic-reloc-weak.s [new file with mode: 0644]
test/ELF/Inputs/dynamic-reloc.s [new file with mode: 0644]
test/ELF/Inputs/ehframe-relocation.s [new file with mode: 0644]
test/ELF/Inputs/empty-ver.ver [new file with mode: 0644]
test/ELF/Inputs/far-arm-abs.s [new file with mode: 0644]
test/ELF/Inputs/far-arm-thumb-abs.s [new file with mode: 0644]
test/ELF/Inputs/gc-sections-weak.s [new file with mode: 0644]
test/ELF/Inputs/gnu-ifunc-gotpcrel.s [new file with mode: 0644]
test/ELF/Inputs/gotpc-relax-und-dso.s [new file with mode: 0644]
test/ELF/Inputs/icf2.s [new file with mode: 0644]
test/ELF/Inputs/invalid-binding.elf [new file with mode: 0644]
test/ELF/Inputs/invalid-cie-version2.elf [new file with mode: 0644]
test/ELF/Inputs/invalid-data-encoding.a [new file with mode: 0644]
test/ELF/Inputs/invalid-file-class.a [new file with mode: 0644]
test/ELF/Inputs/invalid-multiple-eh-relocs.elf [new file with mode: 0644]
test/ELF/Inputs/invalid-section-index.elf [new file with mode: 0644]
test/ELF/Inputs/invalid-shentsize-zero.elf [new file with mode: 0644]
test/ELF/Inputs/invalid-shstrndx.so [new file with mode: 0755]
test/ELF/Inputs/invalid-symtab-sh_info.elf [new file with mode: 0644]
test/ELF/Inputs/libsearch-dyn.s [new file with mode: 0644]
test/ELF/Inputs/libsearch-st.s [new file with mode: 0644]
test/ELF/Inputs/llvm33-rela-outside-group.o [new file with mode: 0644]
test/ELF/Inputs/merge.s [new file with mode: 0644]
test/ELF/Inputs/mips-align-err.s [new file with mode: 0644]
test/ELF/Inputs/mips-dynamic.s [new file with mode: 0644]
test/ELF/Inputs/mips-gp-disp.so [new file with mode: 0644]
test/ELF/Inputs/mips-gprel32-gp0.o [new file with mode: 0644]
test/ELF/Inputs/mips-nonalloc.s [new file with mode: 0644]
test/ELF/Inputs/mips-options.o [new file with mode: 0644]
test/ELF/Inputs/mips-pic.s [new file with mode: 0644]
test/ELF/Inputs/mips-sto-pic.o [new file with mode: 0644]
test/ELF/Inputs/mips-tls.s [new file with mode: 0644]
test/ELF/Inputs/no-symtab.o [new file with mode: 0644]
test/ELF/Inputs/plt-aarch64.s [new file with mode: 0644]
test/ELF/Inputs/ppc64-addr16-error.s [new file with mode: 0644]
test/ELF/Inputs/progname-ver.so [new file with mode: 0755]
test/ELF/Inputs/protected-shared.s [new file with mode: 0644]
test/ELF/Inputs/relocatable-ehframe.s [new file with mode: 0644]
test/ELF/Inputs/relocatable.s [new file with mode: 0644]
test/ELF/Inputs/relocatable2.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-alias.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-align.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-arm.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy.s [new file with mode: 0644]
test/ELF/Inputs/relocation-size-shared.s [new file with mode: 0644]
test/ELF/Inputs/resolution-shared.s [new file with mode: 0644]
test/ELF/Inputs/resolution.s [new file with mode: 0644]
test/ELF/Inputs/shared-ppc64.s [new file with mode: 0644]
test/ELF/Inputs/shared.s [new file with mode: 0644]
test/ELF/Inputs/shared2.s [new file with mode: 0644]
test/ELF/Inputs/shared3.s [new file with mode: 0644]
test/ELF/Inputs/start-lib-comdat.s [new file with mode: 0644]
test/ELF/Inputs/start-lib1.s [new file with mode: 0644]
test/ELF/Inputs/start-lib2.s [new file with mode: 0644]
test/ELF/Inputs/symbol-override.s [new file with mode: 0644]
test/ELF/Inputs/tls-got-entry.s [new file with mode: 0644]
test/ELF/Inputs/tls-got.s [new file with mode: 0644]
test/ELF/Inputs/tls-in-archive.s [new file with mode: 0644]
test/ELF/Inputs/tls-mismatch.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-gdie.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-gdiele-i686.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-iele-i686-nopic.s [new file with mode: 0644]
test/ELF/Inputs/trace-ar1.s [new file with mode: 0644]
test/ELF/Inputs/trace-ar2.s [new file with mode: 0644]
test/ELF/Inputs/trace-symbols-foo-strong.s [new file with mode: 0644]
test/ELF/Inputs/trace-symbols-foo-weak.s [new file with mode: 0644]
test/ELF/Inputs/undef-with-plt-addr.s [new file with mode: 0644]
test/ELF/Inputs/undef.s [new file with mode: 0644]
test/ELF/Inputs/unresolved-symbols.s [new file with mode: 0644]
test/ELF/Inputs/verdef-defaultver.s [new file with mode: 0644]
test/ELF/Inputs/verdef.s [new file with mode: 0644]
test/ELF/Inputs/verneed.so.sh [new file with mode: 0755]
test/ELF/Inputs/verneed1.so [new file with mode: 0755]
test/ELF/Inputs/verneed2.so [new file with mode: 0755]
test/ELF/Inputs/version-script-err.script [new file with mode: 0644]
test/ELF/Inputs/version-undef-sym.so [new file with mode: 0755]
test/ELF/Inputs/version-use.script [new file with mode: 0644]
test/ELF/Inputs/version-use.so [new file with mode: 0755]
test/ELF/Inputs/visibility.s [new file with mode: 0644]
test/ELF/Inputs/warn-common.s [new file with mode: 0644]
test/ELF/Inputs/warn-common2.s [new file with mode: 0644]
test/ELF/Inputs/whole-archive.s [new file with mode: 0644]
test/ELF/Inputs/wrap.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-relax-offset.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-error.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-tls-gd-got.s [new file with mode: 0644]
test/ELF/aarch64-abs16.s [new file with mode: 0644]
test/ELF/aarch64-abs32.s [new file with mode: 0644]
test/ELF/aarch64-abs64-dyn.s [new file with mode: 0644]
test/ELF/aarch64-call26-error.s [new file with mode: 0644]
test/ELF/aarch64-condb-reloc.s [new file with mode: 0644]
test/ELF/aarch64-copy.s [new file with mode: 0644]
test/ELF/aarch64-copy2.s [new file with mode: 0644]
test/ELF/aarch64-data-relocs.s [new file with mode: 0644]
test/ELF/aarch64-fpic-abs16.s [new file with mode: 0644]
test/ELF/aarch64-fpic-add_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-adr_prel_lo21.s [new file with mode: 0644]
test/ELF/aarch64-fpic-adr_prel_pg_hi21.s [new file with mode: 0644]
test/ELF/aarch64-fpic-got.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel16.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel32.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel64.s [new file with mode: 0644]
test/ELF/aarch64-gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/aarch64-gnu-ifunc.s [new file with mode: 0644]
test/ELF/aarch64-got-relocations.s [new file with mode: 0644]
test/ELF/aarch64-got.s [new file with mode: 0644]
test/ELF/aarch64-hi21-error.s [new file with mode: 0644]
test/ELF/aarch64-jump26-error.s [new file with mode: 0644]
test/ELF/aarch64-lo21-error.s [new file with mode: 0644]
test/ELF/aarch64-prel16.s [new file with mode: 0644]
test/ELF/aarch64-prel32.s [new file with mode: 0644]
test/ELF/aarch64-relative.s [new file with mode: 0644]
test/ELF/aarch64-relocs.s [new file with mode: 0644]
test/ELF/aarch64-tls-gdie.s [new file with mode: 0644]
test/ELF/aarch64-tls-gdle.s [new file with mode: 0644]
test/ELF/aarch64-tls-ie.s [new file with mode: 0644]
test/ELF/aarch64-tls-iele.s [new file with mode: 0644]
test/ELF/aarch64-tls-le.s [new file with mode: 0644]
test/ELF/aarch64-tls-pie.s [new file with mode: 0644]
test/ELF/aarch64-tls-static.s [new file with mode: 0644]
test/ELF/aarch64-tlsdesc.s [new file with mode: 0644]
test/ELF/aarch64-tstbr14-reloc.s [new file with mode: 0644]
test/ELF/abs-hidden.s [new file with mode: 0644]
test/ELF/allow-multiple-definition.s [new file with mode: 0644]
test/ELF/allow-shlib-undefined.s [new file with mode: 0644]
test/ELF/amdgpu-entry.s [new file with mode: 0644]
test/ELF/amdgpu-globals.s [new file with mode: 0644]
test/ELF/amdgpu-kernels.s [new file with mode: 0644]
test/ELF/amdgpu-relocs.s [new file with mode: 0644]
test/ELF/archive.s [new file with mode: 0644]
test/ELF/arm-abs32-dyn.s [new file with mode: 0644]
test/ELF/arm-attributes-remove.s [new file with mode: 0644]
test/ELF/arm-blx.s [new file with mode: 0644]
test/ELF/arm-branch-error.s [new file with mode: 0644]
test/ELF/arm-branch.s [new file with mode: 0644]
test/ELF/arm-copy.s [new file with mode: 0644]
test/ELF/arm-data-prel.s [new file with mode: 0644]
test/ELF/arm-data-relocs.s [new file with mode: 0644]
test/ELF/arm-fpic-got.s [new file with mode: 0644]
test/ELF/arm-gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/arm-gnu-ifunc.s [new file with mode: 0644]
test/ELF/arm-got-relative.s [new file with mode: 0644]
test/ELF/arm-gotoff.s [new file with mode: 0644]
test/ELF/arm-mov-relocs.s [new file with mode: 0644]
test/ELF/arm-plt-reloc.s [new file with mode: 0644]
test/ELF/arm-thumb-blx.s [new file with mode: 0644]
test/ELF/arm-thumb-branch-error.s [new file with mode: 0644]
test/ELF/arm-thumb-branch.s [new file with mode: 0644]
test/ELF/arm-thumb-interwork-thunk.s [new file with mode: 0644]
test/ELF/arm-thumb-narrow-branch-check.s [new file with mode: 0644]
test/ELF/arm-thumb-plt-reloc.s [new file with mode: 0644]
test/ELF/as-needed-no-reloc.s [new file with mode: 0644]
test/ELF/as-needed.s [new file with mode: 0644]
test/ELF/avoid-empty-program-headers.s [new file with mode: 0644]
test/ELF/basic-aarch64.s [new file with mode: 0644]
test/ELF/basic-freebsd.s [new file with mode: 0644]
test/ELF/basic-mips.s [new file with mode: 0644]
test/ELF/basic-ppc.s [new file with mode: 0644]
test/ELF/basic.s [new file with mode: 0644]
test/ELF/basic32.s [new file with mode: 0644]
test/ELF/basic64be.s [new file with mode: 0644]
test/ELF/bss.s [new file with mode: 0644]
test/ELF/bsymbolic-undef.s [new file with mode: 0644]
test/ELF/bsymbolic.s [new file with mode: 0644]
test/ELF/build-id.s [new file with mode: 0644]
test/ELF/combrelocs.s [new file with mode: 0644]
test/ELF/comdat.s [new file with mode: 0644]
test/ELF/common.s [new file with mode: 0644]
test/ELF/compressed-debug-input.s [new file with mode: 0644]
test/ELF/conflict.s [new file with mode: 0644]
test/ELF/copy-errors.s [new file with mode: 0644]
test/ELF/copy-in-shared.s [new file with mode: 0644]
test/ELF/copy-rel-corrupted.s [new file with mode: 0644]
test/ELF/copy-rel-pie-error.s [new file with mode: 0644]
test/ELF/copy-rel-pie.s [new file with mode: 0644]
test/ELF/ctors_dtors_priority.s [new file with mode: 0644]
test/ELF/default-output.s [new file with mode: 0644]
test/ELF/discard-locals.s [new file with mode: 0644]
test/ELF/discard-merge-locals.s [new file with mode: 0644]
test/ELF/discard-merge-unnamed.s [new file with mode: 0644]
test/ELF/discard-none.s [new file with mode: 0644]
test/ELF/dont-export-hidden.s [new file with mode: 0644]
test/ELF/driver.test [new file with mode: 0644]
test/ELF/dt_flags.s [new file with mode: 0644]
test/ELF/dt_tags.s [new file with mode: 0644]
test/ELF/duplicate-internal.s [new file with mode: 0644]
test/ELF/duplicated-plt-entry.s [new file with mode: 0644]
test/ELF/dynamic-list.s [new file with mode: 0644]
test/ELF/dynamic-reloc-in-ro.s [new file with mode: 0644]
test/ELF/dynamic-reloc-index.s [new file with mode: 0644]
test/ELF/dynamic-reloc-weak.s [new file with mode: 0644]
test/ELF/dynamic-reloc.s [new file with mode: 0644]
test/ELF/dynamic.s [new file with mode: 0644]
test/ELF/dynsym-pie.s [new file with mode: 0644]
test/ELF/edata-etext.s [new file with mode: 0644]
test/ELF/eh-align-cie.s [new file with mode: 0644]
test/ELF/eh-frame-dyn-rel.s [new file with mode: 0644]
test/ELF/eh-frame-gc.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-abs-fde.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-augmentation.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-icf.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-no-out.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-no-out2.s [new file with mode: 0644]
test/ELF/eh-frame-hdr.s [new file with mode: 0644]
test/ELF/eh-frame-marker.s [new file with mode: 0644]
test/ELF/eh-frame-merge.s [new file with mode: 0644]
test/ELF/eh-frame-multilpe-cie.s [new file with mode: 0644]
test/ELF/eh-frame-plt.s [new file with mode: 0644]
test/ELF/eh-frame-rel.s [new file with mode: 0644]
test/ELF/eh-frame-type.test [new file with mode: 0644]
test/ELF/ehframe-relocation.s [new file with mode: 0644]
test/ELF/empty-archive.s [new file with mode: 0644]
test/ELF/empty-ver.s [new file with mode: 0644]
test/ELF/emulation.s [new file with mode: 0644]
test/ELF/end-preserve.s [new file with mode: 0644]
test/ELF/end-update.s [new file with mode: 0644]
test/ELF/end.s [new file with mode: 0644]
test/ELF/entry.s [new file with mode: 0644]
test/ELF/fatal-warnings.s [new file with mode: 0644]
test/ELF/file-sym.s [new file with mode: 0644]
test/ELF/gc-merge-local-sym.s [new file with mode: 0644]
test/ELF/gc-sections-eh.s [new file with mode: 0644]
test/ELF/gc-sections-local-sym.s [new file with mode: 0644]
test/ELF/gc-sections-lsda.s [new file with mode: 0644]
test/ELF/gc-sections-merge-addend.s [new file with mode: 0644]
test/ELF/gc-sections-merge-implicit-addend.s [new file with mode: 0644]
test/ELF/gc-sections-merge.s [new file with mode: 0644]
test/ELF/gc-sections-print.s [new file with mode: 0644]
test/ELF/gc-sections-protected.s [new file with mode: 0644]
test/ELF/gc-sections-shared.s [new file with mode: 0644]
test/ELF/gc-sections-weak.s [new file with mode: 0644]
test/ELF/gc-sections.s [new file with mode: 0644]
test/ELF/global_offset_table.s [new file with mode: 0644]
test/ELF/global_offset_table_shared.s [new file with mode: 0644]
test/ELF/gnu-hash-table.s [new file with mode: 0644]
test/ELF/gnu-ifunc-gotpcrel.s [new file with mode: 0644]
test/ELF/gnu-ifunc-i386.s [new file with mode: 0644]
test/ELF/gnu-ifunc-nosym-i386.s [new file with mode: 0644]
test/ELF/gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/gnu-ifunc-relative.s [new file with mode: 0644]
test/ELF/gnu-ifunc.s [new file with mode: 0644]
test/ELF/gnu-unique.s [new file with mode: 0644]
test/ELF/gnustack.s [new file with mode: 0644]
test/ELF/got-aarch64.s [new file with mode: 0644]
test/ELF/got-i386.s [new file with mode: 0644]
test/ELF/got-plt-header.s [new file with mode: 0644]
test/ELF/got.s [new file with mode: 0644]
test/ELF/gotpc-relax-nopic.s [new file with mode: 0644]
test/ELF/gotpc-relax-und-dso.s [new file with mode: 0644]
test/ELF/gotpc-relax.s [new file with mode: 0644]
test/ELF/gotpcrelx.s [new file with mode: 0644]
test/ELF/i386-got-and-copy.s [new file with mode: 0644]
test/ELF/i386-gotpc.s [new file with mode: 0644]
test/ELF/i386-merge.s [new file with mode: 0644]
test/ELF/i386-relative.s [new file with mode: 0644]
test/ELF/i386-relax-reloc.s [new file with mode: 0644]
test/ELF/i386-tls-ie-shared.s [new file with mode: 0644]
test/ELF/icf1.s [new file with mode: 0644]
test/ELF/icf2.s [new file with mode: 0644]
test/ELF/icf3.s [new file with mode: 0644]
test/ELF/icf4.s [new file with mode: 0644]
test/ELF/icf5.s [new file with mode: 0644]
test/ELF/icf6.s [new file with mode: 0644]
test/ELF/icf7.s [new file with mode: 0644]
test/ELF/image-base.s [new file with mode: 0644]
test/ELF/incompatible-ar-first.s [new file with mode: 0644]
test/ELF/incompatible.s [new file with mode: 0644]
test/ELF/init-fini.s [new file with mode: 0644]
test/ELF/init_fini_priority.s [new file with mode: 0644]
test/ELF/invalid-cie-length.s [new file with mode: 0644]
test/ELF/invalid-cie-length2.s [new file with mode: 0644]
test/ELF/invalid-cie-length3.s [new file with mode: 0644]
test/ELF/invalid-cie-length4.s [new file with mode: 0644]
test/ELF/invalid-cie-length5.s [new file with mode: 0644]
test/ELF/invalid-cie-reference.s [new file with mode: 0644]
test/ELF/invalid-dynamic-list.test [new file with mode: 0644]
test/ELF/invalid-elf.test [new file with mode: 0644]
test/ELF/invalid-fde-rel.s [new file with mode: 0644]
test/ELF/invalid-linkerscript.test [new file with mode: 0644]
test/ELF/invalid-relocations.test [new file with mode: 0644]
test/ELF/libsearch.s [new file with mode: 0644]
test/ELF/linkerscript-align.s [new file with mode: 0644]
test/ELF/linkerscript-diagnostic.s [new file with mode: 0644]
test/ELF/linkerscript-locationcounter.s [new file with mode: 0644]
test/ELF/linkerscript-orphans.s [new file with mode: 0644]
test/ELF/linkerscript-ouputformat.s [new file with mode: 0644]
test/ELF/linkerscript-outputarch.s [new file with mode: 0644]
test/ELF/linkerscript-phdr-check.s [new file with mode: 0644]
test/ELF/linkerscript-repsection-va.s [new file with mode: 0644]
test/ELF/linkerscript-sections-keep.s [new file with mode: 0644]
test/ELF/linkerscript-sections-padding.s [new file with mode: 0644]
test/ELF/linkerscript-sections.s [new file with mode: 0644]
test/ELF/linkerscript-symbol-conflict.s [new file with mode: 0644]
test/ELF/linkerscript-symbols.s [new file with mode: 0644]
test/ELF/linkerscript-va.s [new file with mode: 0644]
test/ELF/linkerscript.s [new file with mode: 0644]
test/ELF/linkerscript2.s [new file with mode: 0644]
test/ELF/lit.local.cfg [new file with mode: 0644]
test/ELF/llvm33-rela-outside-group.s [new file with mode: 0644]
test/ELF/local-dynamic.s [new file with mode: 0644]
test/ELF/local-got-pie.s [new file with mode: 0644]
test/ELF/local-got-shared.s [new file with mode: 0644]
test/ELF/local-got.s [new file with mode: 0644]
test/ELF/local-undefined-symbol.s [new file with mode: 0644]
test/ELF/local.s [new file with mode: 0644]
test/ELF/lto/Inputs/archive-2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/archive-3.ll [new file with mode: 0644]
test/ELF/lto/Inputs/archive.ll [new file with mode: 0644]
test/ELF/lto/Inputs/available-externally.ll [new file with mode: 0644]
test/ELF/lto/Inputs/comdat.s [new file with mode: 0644]
test/ELF/lto/Inputs/common.s [new file with mode: 0644]
test/ELF/lto/Inputs/drop-debug-info.bc [new file with mode: 0644]
test/ELF/lto/Inputs/drop-linkage.ll [new file with mode: 0644]
test/ELF/lto/Inputs/dynsym.s [new file with mode: 0644]
test/ELF/lto/Inputs/internalize-exportdyn.ll [new file with mode: 0644]
test/ELF/lto/Inputs/internalize-undef.ll [new file with mode: 0644]
test/ELF/lto/Inputs/irmover-error.ll [new file with mode: 0644]
test/ELF/lto/Inputs/linkonce-odr.ll [new file with mode: 0644]
test/ELF/lto/Inputs/linkonce.ll [new file with mode: 0644]
test/ELF/lto/Inputs/resolution.s [new file with mode: 0644]
test/ELF/lto/Inputs/save-temps.ll [new file with mode: 0644]
test/ELF/lto/Inputs/shared.s [new file with mode: 0644]
test/ELF/lto/Inputs/start-lib1.ll [new file with mode: 0644]
test/ELF/lto/Inputs/start-lib2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/tls-mixed.s [new file with mode: 0644]
test/ELF/lto/Inputs/type-merge.ll [new file with mode: 0644]
test/ELF/lto/Inputs/type-merge2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/undef-mixed.s [new file with mode: 0644]
test/ELF/lto/Inputs/unnamed-addr-lib.s [new file with mode: 0644]
test/ELF/lto/Inputs/visibility.s [new file with mode: 0644]
test/ELF/lto/archive-2.ll [new file with mode: 0644]
test/ELF/lto/archive-3.ll [new file with mode: 0644]
test/ELF/lto/archive.ll [new file with mode: 0644]
test/ELF/lto/asmundef.ll [new file with mode: 0644]
test/ELF/lto/available-externally.ll [new file with mode: 0644]
test/ELF/lto/combined-lto-object-name.ll [new file with mode: 0644]
test/ELF/lto/comdat.ll [new file with mode: 0644]
test/ELF/lto/comdat2.ll [new file with mode: 0644]
test/ELF/lto/common.ll [new file with mode: 0644]
test/ELF/lto/common2.ll [new file with mode: 0644]
test/ELF/lto/ctors.ll [new file with mode: 0644]
test/ELF/lto/discard-value-names.ll [new file with mode: 0644]
test/ELF/lto/drop-debug-info.ll [new file with mode: 0644]
test/ELF/lto/drop-linkage.ll [new file with mode: 0644]
test/ELF/lto/duplicated.ll [new file with mode: 0644]
test/ELF/lto/dynamic-list.ll [new file with mode: 0644]
test/ELF/lto/dynsym.ll [new file with mode: 0644]
test/ELF/lto/inline-asm.ll [new file with mode: 0644]
test/ELF/lto/internalize-basic.ll [new file with mode: 0644]
test/ELF/lto/internalize-exportdyn.ll [new file with mode: 0644]
test/ELF/lto/internalize-llvmused.ll [new file with mode: 0644]
test/ELF/lto/internalize-undef.ll [new file with mode: 0644]
test/ELF/lto/internalize-version-script.ll [new file with mode: 0644]
test/ELF/lto/invalid-bitcode.ll [new file with mode: 0644]
test/ELF/lto/irmover-error.ll [new file with mode: 0644]
test/ELF/lto/linkage.ll [new file with mode: 0644]
test/ELF/lto/linkonce-odr.ll [new file with mode: 0644]
test/ELF/lto/linkonce.ll [new file with mode: 0644]
test/ELF/lto/lto-start.ll [new file with mode: 0644]
test/ELF/lto/ltopasses-basic.ll [new file with mode: 0644]
test/ELF/lto/ltopasses-custom.ll [new file with mode: 0644]
test/ELF/lto/metadata.ll [new file with mode: 0644]
test/ELF/lto/mix-platforms.ll [new file with mode: 0644]
test/ELF/lto/module-asm.ll [new file with mode: 0644]
test/ELF/lto/opt-level.ll [new file with mode: 0644]
test/ELF/lto/parallel-internalize.ll [new file with mode: 0644]
test/ELF/lto/parallel.ll [new file with mode: 0644]
test/ELF/lto/pic.ll [new file with mode: 0644]
test/ELF/lto/relax-relocs.ll [new file with mode: 0644]
test/ELF/lto/resolution.ll [new file with mode: 0644]
test/ELF/lto/save-temps.ll [new file with mode: 0644]
test/ELF/lto/shlib-undefined.ll [new file with mode: 0644]
test/ELF/lto/start-lib.ll [new file with mode: 0644]
test/ELF/lto/tls-mixed.ll [new file with mode: 0644]
test/ELF/lto/tls-preserve.ll [new file with mode: 0644]
test/ELF/lto/type-merge.ll [new file with mode: 0644]
test/ELF/lto/type-merge2.ll [new file with mode: 0644]
test/ELF/lto/undef-mixed.ll [new file with mode: 0644]
test/ELF/lto/undef-weak.ll [new file with mode: 0644]
test/ELF/lto/undef.ll [new file with mode: 0644]
test/ELF/lto/undefined-puts.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr-comdat.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr-lib.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr.ll [new file with mode: 0644]
test/ELF/lto/verify-invalid.ll [new file with mode: 0644]
test/ELF/lto/version-script.ll [new file with mode: 0644]
test/ELF/lto/visibility.ll [new file with mode: 0644]
test/ELF/lto/weak.ll [new file with mode: 0644]
test/ELF/many-sections.s [new file with mode: 0644]
test/ELF/merge-invalid-size.s [new file with mode: 0644]
test/ELF/merge-shared-str.s [new file with mode: 0644]
test/ELF/merge-shared.s [new file with mode: 0644]
test/ELF/merge-string-align.s [new file with mode: 0644]
test/ELF/merge-string-error.s [new file with mode: 0644]
test/ELF/merge-string-no-null.s [new file with mode: 0644]
test/ELF/merge-string.s [new file with mode: 0644]
test/ELF/merge-sym.s [new file with mode: 0644]
test/ELF/merge.s [new file with mode: 0644]
test/ELF/mips-26.s [new file with mode: 0644]
test/ELF/mips-32.s [new file with mode: 0644]
test/ELF/mips-64-disp.s [new file with mode: 0644]
test/ELF/mips-64-got.s [new file with mode: 0644]
test/ELF/mips-64-gprel-so.s [new file with mode: 0644]
test/ELF/mips-64-rels.s [new file with mode: 0644]
test/ELF/mips-64.s [new file with mode: 0644]
test/ELF/mips-align-err.s [new file with mode: 0644]
test/ELF/mips-call16.s [new file with mode: 0644]
test/ELF/mips-dynamic.s [new file with mode: 0644]
test/ELF/mips-dynsym-sort.s [new file with mode: 0644]
test/ELF/mips-elf-flags.s [new file with mode: 0644]
test/ELF/mips-gnu-hash.s [new file with mode: 0644]
test/ELF/mips-got-and-copy.s [new file with mode: 0644]
test/ELF/mips-got-extsym.s [new file with mode: 0644]
test/ELF/mips-got-redundant.s [new file with mode: 0644]
test/ELF/mips-got-relocs.s [new file with mode: 0644]
test/ELF/mips-got-weak.s [new file with mode: 0644]
test/ELF/mips-got16.s [new file with mode: 0644]
test/ELF/mips-gp-disp.s [new file with mode: 0644]
test/ELF/mips-gp-local.s [new file with mode: 0644]
test/ELF/mips-gprel32-relocs-gp0.test [new file with mode: 0644]
test/ELF/mips-gprel32-relocs.s [new file with mode: 0644]
test/ELF/mips-hilo-gp-disp.s [new file with mode: 0644]
test/ELF/mips-hilo-hi-only.s [new file with mode: 0644]
test/ELF/mips-hilo.s [new file with mode: 0644]
test/ELF/mips-jalr.test [new file with mode: 0644]
test/ELF/mips-lo16-not-relative.s [new file with mode: 0644]
test/ELF/mips-nonalloc.s [new file with mode: 0644]
test/ELF/mips-npic-call-pic.s [new file with mode: 0644]
test/ELF/mips-options-r.test [new file with mode: 0644]
test/ELF/mips-options.s [new file with mode: 0644]
test/ELF/mips-pc-relocs.s [new file with mode: 0644]
test/ELF/mips-plt-copy.s [new file with mode: 0644]
test/ELF/mips-reginfo.s [new file with mode: 0644]
test/ELF/mips-sto-plt.s [new file with mode: 0644]
test/ELF/mips-tls-64.s [new file with mode: 0644]
test/ELF/mips-tls-hilo.s [new file with mode: 0644]
test/ELF/mips-tls.s [new file with mode: 0644]
test/ELF/new-dtags.test [new file with mode: 0644]
test/ELF/no-augmentation.s [new file with mode: 0644]
test/ELF/no-inhibit-exec.s [new file with mode: 0644]
test/ELF/no-obj.s [new file with mode: 0644]
test/ELF/no-plt-shared.s [new file with mode: 0644]
test/ELF/no-symtab.s [new file with mode: 0644]
test/ELF/no-undefined.s [new file with mode: 0644]
test/ELF/noplt-pie.s [new file with mode: 0644]
test/ELF/note.s [new file with mode: 0644]
test/ELF/output-section.s [new file with mode: 0644]
test/ELF/phdr-align.s [new file with mode: 0644]
test/ELF/pie-weak.s [new file with mode: 0644]
test/ELF/pie.s [new file with mode: 0644]
test/ELF/plt-aarch64.s [new file with mode: 0644]
test/ELF/plt-i686.s [new file with mode: 0644]
test/ELF/plt.s [new file with mode: 0644]
test/ELF/ppc-relocs.s [new file with mode: 0644]
test/ELF/ppc64-addr16-error.s [new file with mode: 0644]
test/ELF/ppc64-rel-calls.s [new file with mode: 0644]
test/ELF/ppc64-relocs.s [new file with mode: 0644]
test/ELF/ppc64-shared-rel-toc.s [new file with mode: 0644]
test/ELF/ppc64-toc-restore.s [new file with mode: 0644]
test/ELF/ppc64-weak-undef-call-shared.s [new file with mode: 0644]
test/ELF/ppc64-weak-undef-call.s [new file with mode: 0644]
test/ELF/pre_init_fini_array.s [new file with mode: 0644]
test/ELF/pre_init_fini_array_missing.s [new file with mode: 0644]
test/ELF/progname.s [new file with mode: 0644]
test/ELF/program-header-layout.s [new file with mode: 0644]
test/ELF/protected-shared.s [new file with mode: 0644]
test/ELF/rel-offset.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc-pie.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc-ppc64.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc.s [new file with mode: 0644]
test/ELF/relocatable-bss.s [new file with mode: 0644]
test/ELF/relocatable-ehframe.s [new file with mode: 0644]
test/ELF/relocatable-reloc.s [new file with mode: 0644]
test/ELF/relocatable-symbols.s [new file with mode: 0644]
test/ELF/relocatable.s [new file with mode: 0644]
test/ELF/relocation-absolute.s [new file with mode: 0644]
test/ELF/relocation-common.s [new file with mode: 0644]
test/ELF/relocation-copy-alias.s [new file with mode: 0644]
test/ELF/relocation-copy-align.s [new file with mode: 0644]
test/ELF/relocation-copy-flags.s [new file with mode: 0644]
test/ELF/relocation-copy-i686.s [new file with mode: 0644]
test/ELF/relocation-copy.s [new file with mode: 0644]
test/ELF/relocation-i686.s [new file with mode: 0644]
test/ELF/relocation-in-merge.s [new file with mode: 0644]
test/ELF/relocation-local.s [new file with mode: 0644]
test/ELF/relocation-non-alloc.s [new file with mode: 0644]
test/ELF/relocation-past-merge-end.s [new file with mode: 0644]
test/ELF/relocation-relative-absolute.s [new file with mode: 0644]
test/ELF/relocation-relative-synthetic.s [new file with mode: 0644]
test/ELF/relocation-relative-weak.s [new file with mode: 0644]
test/ELF/relocation-shared.s [new file with mode: 0644]
test/ELF/relocation-size-shared.s [new file with mode: 0644]
test/ELF/relocation-size.s [new file with mode: 0644]
test/ELF/relocation-undefined-weak.s [new file with mode: 0644]
test/ELF/relocation.s [new file with mode: 0644]
test/ELF/relro-tls.s [new file with mode: 0644]
test/ELF/relro.s [new file with mode: 0644]
test/ELF/reproduce-error.s [new file with mode: 0644]
test/ELF/reproduce-linkerscript.s [new file with mode: 0644]
test/ELF/reproduce-thin-archive.s [new file with mode: 0644]
test/ELF/reproduce-windows.s [new file with mode: 0644]
test/ELF/reproduce.s [new file with mode: 0644]
test/ELF/resolution-shared.s [new file with mode: 0644]
test/ELF/resolution.s [new file with mode: 0644]
test/ELF/section-align-0.test [new file with mode: 0644]
test/ELF/section-layout.s [new file with mode: 0644]
test/ELF/section-name.s [new file with mode: 0644]
test/ELF/section-symbol.s [new file with mode: 0644]
test/ELF/shared-be.s [new file with mode: 0644]
test/ELF/shared.s [new file with mode: 0644]
test/ELF/soname.s [new file with mode: 0644]
test/ELF/soname2.s [new file with mode: 0644]
test/ELF/splitstacks.s [new file with mode: 0644]
test/ELF/start-lib-comdat.s [new file with mode: 0644]
test/ELF/start-lib.s [new file with mode: 0644]
test/ELF/startstop-gccollect.s [new file with mode: 0644]
test/ELF/startstop-shared.s [new file with mode: 0644]
test/ELF/startstop.s [new file with mode: 0644]
test/ELF/string-gc.s [new file with mode: 0644]
test/ELF/string-table.s [new file with mode: 0644]
test/ELF/strip-all.s [new file with mode: 0644]
test/ELF/strip-debug.s [new file with mode: 0644]
test/ELF/symbol-override.s [new file with mode: 0644]
test/ELF/symbols.s [new file with mode: 0644]
test/ELF/sysroot.s [new file with mode: 0644]
test/ELF/tail-merge-string-align.s [new file with mode: 0644]
test/ELF/tls-align.s [new file with mode: 0644]
test/ELF/tls-archive.s [new file with mode: 0644]
test/ELF/tls-dynamic-i686.s [new file with mode: 0644]
test/ELF/tls-dynamic.s [new file with mode: 0644]
test/ELF/tls-error.s [new file with mode: 0644]
test/ELF/tls-got-entry.s [new file with mode: 0644]
test/ELF/tls-got.s [new file with mode: 0644]
test/ELF/tls-i686.s [new file with mode: 0644]
test/ELF/tls-in-archive.s [new file with mode: 0644]
test/ELF/tls-initial-exec-local.s [new file with mode: 0644]
test/ELF/tls-mismatch.s [new file with mode: 0644]
test/ELF/tls-offset.s [new file with mode: 0644]
test/ELF/tls-opt-gdie.s [new file with mode: 0644]
test/ELF/tls-opt-gdiele-i686.s [new file with mode: 0644]
test/ELF/tls-opt-i686.s [new file with mode: 0644]
test/ELF/tls-opt-iele-i686-nopic.s [new file with mode: 0644]
test/ELF/tls-opt-local.s [new file with mode: 0644]
test/ELF/tls-opt-no-plt.s [new file with mode: 0644]
test/ELF/tls-opt.s [new file with mode: 0644]
test/ELF/tls-static.s [new file with mode: 0644]
test/ELF/tls-two-relocs.s [new file with mode: 0644]
test/ELF/tls.s [new file with mode: 0644]
test/ELF/trace-ar.s [new file with mode: 0644]
test/ELF/trace-symbols.s [new file with mode: 0644]
test/ELF/trace.s [new file with mode: 0644]
test/ELF/undef-shared.s [new file with mode: 0644]
test/ELF/undef-start.s [new file with mode: 0644]
test/ELF/undef-version-script.s [new file with mode: 0644]
test/ELF/undef-with-plt-addr-i686.s [new file with mode: 0644]
test/ELF/undef-with-plt-addr.s [new file with mode: 0644]
test/ELF/undef.s [new file with mode: 0644]
test/ELF/undefined-opt.s [new file with mode: 0644]
test/ELF/unresolved-symbols.s [new file with mode: 0644]
test/ELF/user_def_init_array_start.s [new file with mode: 0644]
test/ELF/verdef-defaultver.s [new file with mode: 0644]
test/ELF/verdef-dependency.s [new file with mode: 0644]
test/ELF/verdef.s [new file with mode: 0644]
test/ELF/verneed-as-needed-weak.s [new file with mode: 0644]
test/ELF/verneed-local.s [new file with mode: 0644]
test/ELF/verneed.s [new file with mode: 0644]
test/ELF/version-script-err.s [new file with mode: 0644]
test/ELF/version-script-extern.s [new file with mode: 0644]
test/ELF/version-script-noundef.s [new file with mode: 0644]
test/ELF/version-script.s [new file with mode: 0644]
test/ELF/version-undef-sym.s [new file with mode: 0644]
test/ELF/version-use.s [new file with mode: 0644]
test/ELF/version-wildcard.test [new file with mode: 0644]
test/ELF/visibility.s [new file with mode: 0644]
test/ELF/warn-common.s [new file with mode: 0644]
test/ELF/weak-undef-hidden.s [new file with mode: 0644]
test/ELF/weak-undef-shared.s [new file with mode: 0644]
test/ELF/weak-undef.s [new file with mode: 0644]
test/ELF/whole-archive.s [new file with mode: 0644]
test/ELF/wildcards.s [new file with mode: 0644]
test/ELF/wrap.s [new file with mode: 0644]
test/ELF/writable-merge.s [new file with mode: 0644]
test/ELF/x86-64-dyn-rel-error.s [new file with mode: 0644]
test/ELF/x86-64-dyn-rel-error2.s [new file with mode: 0644]
test/ELF/x86-64-rela.s [new file with mode: 0644]
test/ELF/x86-64-relax-offset.s [new file with mode: 0644]
test/ELF/x86-64-reloc-32-fpic.s [new file with mode: 0644]
test/ELF/x86-64-reloc-error.s [new file with mode: 0644]
test/ELF/x86-64-reloc-pc32-fpic.s [new file with mode: 0644]
test/ELF/x86-64-reloc-range.s [new file with mode: 0644]
test/ELF/x86-64-tls-gd-got.s [new file with mode: 0644]
test/ELF/x86-64-tls-gd-local.s [new file with mode: 0644]
test/ELF/x86-64-tls-pie.s [new file with mode: 0644]
test/ELF/zdefs.s [new file with mode: 0644]
test/Unit/lit.cfg [new file with mode: 0644]
test/Unit/lit.site.cfg.in [new file with mode: 0644]
test/darwin/Inputs/native-and-mach-o.objtxt [new file with mode: 0644]
test/darwin/Inputs/native-and-mach-o2.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc_compaction.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc_only.objtxt [new file with mode: 0644]
test/darwin/native-and-mach-o.objtxt [new file with mode: 0644]
test/lit.cfg [new file with mode: 0644]
test/lit.site.cfg.in [new file with mode: 0644]
test/mach-o/Inputs/DependencyDump.py [new file with mode: 0755]
test/mach-o/Inputs/PIE.yaml [new file with mode: 0644]
test/mach-o/Inputs/arm-interworking.yaml [new file with mode: 0644]
test/mach-o/Inputs/arm-shims.yaml [new file with mode: 0644]
test/mach-o/Inputs/bar.yaml [new file with mode: 0644]
test/mach-o/Inputs/cstring-sections.yaml [new file with mode: 0644]
test/mach-o/Inputs/exported_symbols_list.exp [new file with mode: 0644]
test/mach-o/Inputs/full.filelist [new file with mode: 0644]
test/mach-o/Inputs/got-order.yaml [new file with mode: 0644]
test/mach-o/Inputs/got-order2.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-arm64.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-armv6.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-armv7.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-x86.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-x86_64.yaml [new file with mode: 0644]
test/mach-o/Inputs/hw.raw_bytes [new file with mode: 0644]
test/mach-o/Inputs/interposing-section.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64-2.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64-3.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64.yaml [new file with mode: 0644]
test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib [new file with mode: 0755]
test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a [new file with mode: 0644]
test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o [new file with mode: 0644]
test/mach-o/Inputs/libSystem.yaml [new file with mode: 0644]
test/mach-o/Inputs/libbar.a [new file with mode: 0644]
test/mach-o/Inputs/libfoo.a [new file with mode: 0644]
test/mach-o/Inputs/linker-as-ld.yaml [new file with mode: 0644]
test/mach-o/Inputs/no-version-min-load-command-object.yaml [new file with mode: 0644]
test/mach-o/Inputs/order_file-basic.order [new file with mode: 0644]
test/mach-o/Inputs/partial.filelist [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal.yaml [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml [new file with mode: 0644]
test/mach-o/Inputs/swift-version-1.yaml [new file with mode: 0644]
test/mach-o/Inputs/unwind-info-simple-arm64.yaml [new file with mode: 0644]
test/mach-o/Inputs/use-dylib-install-names.yaml [new file with mode: 0644]
test/mach-o/Inputs/use-simple-dylib.yaml [new file with mode: 0644]
test/mach-o/Inputs/write-final-sections.yaml [new file with mode: 0644]
test/mach-o/Inputs/wrong-arch-error.yaml [new file with mode: 0644]
test/mach-o/PIE.yaml [new file with mode: 0644]
test/mach-o/align_text.yaml [new file with mode: 0644]
test/mach-o/arm-interworking-movw.yaml [new file with mode: 0644]
test/mach-o/arm-interworking.yaml [new file with mode: 0644]
test/mach-o/arm-shims.yaml [new file with mode: 0644]
test/mach-o/arm-subsections-via-symbols.yaml [new file with mode: 0644]
test/mach-o/arm64-reloc-negDelta32-fixup.yaml [new file with mode: 0644]
test/mach-o/arm64-relocs-errors-delta64-offset.yaml [new file with mode: 0644]
test/mach-o/arm64-section-order.yaml [new file with mode: 0644]
test/mach-o/cstring-sections.yaml [new file with mode: 0644]
test/mach-o/data-in-code-load-command.yaml [new file with mode: 0644]
test/mach-o/data-only-dylib.yaml [new file with mode: 0644]
test/mach-o/dead-strip-globals.yaml [new file with mode: 0644]
test/mach-o/demangle.yaml [new file with mode: 0644]
test/mach-o/dependency_info.yaml [new file with mode: 0644]
test/mach-o/do-not-emit-unwind-fde-arm64.yaml [new file with mode: 0644]
test/mach-o/dso_handle.yaml [new file with mode: 0644]
test/mach-o/dylib-install-names.yaml [new file with mode: 0644]
test/mach-o/eh-frame-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/error-simulator-vs-macosx.yaml [new file with mode: 0644]
test/mach-o/exe-offsets.yaml [new file with mode: 0644]
test/mach-o/exe-segment-overlap.yaml [new file with mode: 0644]
test/mach-o/executable-exports.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-dylib.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-obj.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-undef.yaml [new file with mode: 0644]
test/mach-o/fat-archive.yaml [new file with mode: 0644]
test/mach-o/filelist.yaml [new file with mode: 0644]
test/mach-o/flat_namespace_undef_error.yaml [new file with mode: 0644]
test/mach-o/flat_namespace_undef_suppress.yaml [new file with mode: 0644]
test/mach-o/force_load-dylib.yaml [new file with mode: 0644]
test/mach-o/force_load-x86_64.yaml [new file with mode: 0644]
test/mach-o/framework-user-paths.yaml [new file with mode: 0644]
test/mach-o/function-starts-load-command.yaml [new file with mode: 0644]
test/mach-o/gcc_except_tab-got-arm64.yaml [new file with mode: 0644]
test/mach-o/got-order.yaml [new file with mode: 0644]
test/mach-o/hello-world-arm64.yaml [new file with mode: 0644]
test/mach-o/hello-world-armv6.yaml [new file with mode: 0644]
test/mach-o/hello-world-armv7.yaml [new file with mode: 0644]
test/mach-o/hello-world-x86.yaml [new file with mode: 0644]
test/mach-o/hello-world-x86_64.yaml [new file with mode: 0644]
test/mach-o/image-base.yaml [new file with mode: 0644]
test/mach-o/infer-arch.yaml [new file with mode: 0644]
test/mach-o/interposing-section.yaml [new file with mode: 0644]
test/mach-o/keep_private_externs.yaml [new file with mode: 0644]
test/mach-o/lazy-bind-x86_64.yaml [new file with mode: 0644]
test/mach-o/lib-search-paths.yaml [new file with mode: 0644]
test/mach-o/library-order.yaml [new file with mode: 0644]
test/mach-o/library-rescan.yaml [new file with mode: 0644]
test/mach-o/libresolve-bizarre-root-override.yaml [new file with mode: 0644]
test/mach-o/libresolve-multiple-syslibroots.yaml [new file with mode: 0644]
test/mach-o/libresolve-one-syslibroot.yaml [new file with mode: 0644]
test/mach-o/libresolve-simple.yaml [new file with mode: 0644]
test/mach-o/libresolve-user-paths.yaml [new file with mode: 0644]
test/mach-o/libresolve-z.yaml [new file with mode: 0644]
test/mach-o/linker-as-ld.yaml [new file with mode: 0644]
test/mach-o/lit.local.cfg [new file with mode: 0644]
test/mach-o/mach_header-cpusubtype.yaml [new file with mode: 0644]
test/mach-o/mh_bundle_header.yaml [new file with mode: 0644]
test/mach-o/mh_dylib_header.yaml [new file with mode: 0644]
test/mach-o/objc-category-list-atom.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-host-vs-simulator.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-invalid-size.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-invalid-version.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-mismatched-swift-version.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-pass-output.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-simulator-vs-host.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-unsupported-gc.yaml [new file with mode: 0644]
test/mach-o/objc_export_list.yaml [new file with mode: 0644]
test/mach-o/order_file-basic.yaml [new file with mode: 0644]
test/mach-o/parse-aliases.yaml [new file with mode: 0644]
test/mach-o/parse-arm-relocs.yaml [new file with mode: 0644]
test/mach-o/parse-cfstring32.yaml [new file with mode: 0644]
test/mach-o/parse-cfstring64.yaml [new file with mode: 0644]
test/mach-o/parse-compact-unwind32.yaml [new file with mode: 0644]
test/mach-o/parse-compact-unwind64.yaml [new file with mode: 0644]
test/mach-o/parse-data-in-code-armv7.yaml [new file with mode: 0644]
test/mach-o/parse-data-in-code-x86.yaml [new file with mode: 0644]
test/mach-o/parse-data-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/parse-data-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-data.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-x86-anon.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-x86-labeled.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame.yaml [new file with mode: 0644]
test/mach-o/parse-function.yaml [new file with mode: 0644]
test/mach-o/parse-initializers32.yaml [new file with mode: 0644]
test/mach-o/parse-initializers64.yaml [new file with mode: 0644]
test/mach-o/parse-literals-error.yaml [new file with mode: 0644]
test/mach-o/parse-literals.yaml [new file with mode: 0644]
test/mach-o/parse-non-lazy-pointers.yaml [new file with mode: 0644]
test/mach-o/parse-relocs-x86.yaml [new file with mode: 0644]
test/mach-o/parse-section-no-symbol.yaml [new file with mode: 0644]
test/mach-o/parse-tentative-defs.yaml [new file with mode: 0644]
test/mach-o/parse-text-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/parse-text-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-tlv-relocs-x86-64.yaml [new file with mode: 0644]
test/mach-o/re-exported-dylib-ordinal.yaml [new file with mode: 0644]
test/mach-o/rpath.yaml [new file with mode: 0644]
test/mach-o/run-tlv-pass-x86-64.yaml [new file with mode: 0644]
test/mach-o/sdk-version-error.yaml [new file with mode: 0644]
test/mach-o/sectalign.yaml [new file with mode: 0644]
test/mach-o/sectattrs.yaml [new file with mode: 0644]
test/mach-o/sectcreate.yaml [new file with mode: 0644]
test/mach-o/seg-protection-arm64.yaml [new file with mode: 0644]
test/mach-o/seg-protection-x86_64.yaml [new file with mode: 0644]
test/mach-o/source-version.yaml [new file with mode: 0644]
test/mach-o/stack-size.yaml [new file with mode: 0644]
test/mach-o/subsections-via-symbols-default.yaml [new file with mode: 0644]
test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml [new file with mode: 0644]
test/mach-o/twolevel_namespace_undef_warning_suppress.yaml [new file with mode: 0644]
test/mach-o/unwind-info-simple-arm64.yaml [new file with mode: 0644]
test/mach-o/unwind-info-simple-x86_64.yaml [new file with mode: 0644]
test/mach-o/upward-dylib-load-command.yaml [new file with mode: 0644]
test/mach-o/upward-dylib-paths.yaml [new file with mode: 0644]
test/mach-o/usage.yaml [new file with mode: 0644]
test/mach-o/use-simple-dylib.yaml [new file with mode: 0644]
test/mach-o/version-min-load-command-object.yaml [new file with mode: 0644]
test/mach-o/version-min-load-command.yaml [new file with mode: 0644]
test/mach-o/write-final-sections.yaml [new file with mode: 0644]
test/mach-o/wrong-arch-error.yaml [new file with mode: 0644]
tools/lld/CMakeLists.txt [new file with mode: 0644]
tools/lld/lld.cpp [new file with mode: 0644]
unittests/CMakeLists.txt [new file with mode: 0644]
unittests/CoreTests/CMakeLists.txt [new file with mode: 0644]
unittests/CoreTests/ParallelTest.cpp [new file with mode: 0644]
unittests/DriverTests/CMakeLists.txt [new file with mode: 0644]
unittests/DriverTests/DarwinLdDriverTest.cpp [new file with mode: 0644]
unittests/MachOTests/CMakeLists.txt [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileYAMLTests.cpp [new file with mode: 0644]
unittests/MachOTests/empty_obj_x86_armv7.txt [new file with mode: 0644]

diff --git a/.arcconfig b/.arcconfig
new file mode 100644 (file)
index 0000000..ebf4a4a
--- /dev/null
@@ -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 (file)
index 0000000..9b3aa8b
--- /dev/null
@@ -0,0 +1 @@
+BasedOnStyle: LLVM
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0a288ee
--- /dev/null
@@ -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 (file)
index 0000000..46ca748
--- /dev/null
@@ -0,0 +1,106 @@
+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")
+
+option(LLD_USE_VTUNE
+       "Enable VTune user task tracking."
+       OFF)
+if (LLD_USE_VTUNE)
+  find_package(VTune)
+  if (VTUNE_FOUND)
+    include_directories(${VTune_INCLUDE_DIRS})
+    list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
+    add_definitions(-DLLD_HAS_VTUNE)
+  endif()
+endif()
+
+
+if (MSVC)
+  add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
+  add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
+endif()
+
+include_directories(BEFORE
+  ${CMAKE_CURRENT_BINARY_DIR}/include
+  ${CMAKE_CURRENT_SOURCE_DIR}/include
+  )
+
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+  install(DIRECTORY include/
+    DESTINATION include
+    FILES_MATCHING
+    PATTERN "*.h"
+    PATTERN ".svn" EXCLUDE
+    )
+endif()
+
+macro(add_lld_library name)
+  add_llvm_library(${name} ${ARGN})
+  set_target_properties(${name} PROPERTIES FOLDER "lld libraries")
+endmacro(add_lld_library)
+
+
+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 (file)
index 0000000..292967e
--- /dev/null
@@ -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 (file)
index 0000000..ad5b6fd
--- /dev/null
@@ -0,0 +1,36 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(COFFOptionsTableGen)
+
+add_lld_library(lldCOFF
+  Chunks.cpp
+  DLL.cpp
+  Driver.cpp
+  DriverUtils.cpp
+  Error.cpp
+  ICF.cpp
+  InputFiles.cpp
+  Librarian.cpp
+  MarkLive.cpp
+  ModuleDef.cpp
+  PDB.cpp
+  SymbolTable.cpp
+  Symbols.cpp
+  Writer.cpp
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  Core
+  LTO
+  LibDriver
+  Object
+  MC
+  MCDisassembler
+  Target
+  Option
+  Support
+
+  LINK_LIBS ${PTHREAD_LIB}
+  )
+
+add_dependencies(lldCOFF COFFOptionsTableGen intrinsics_gen)
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
new file mode 100644 (file)
index 0000000..1c1b181
--- /dev/null
@@ -0,0 +1,337 @@
+//===- Chunks.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
+    : Chunk(SectionKind), Repl(this), File(F), Header(H),
+      Relocs(File->getCOFFObj()->getRelocations(Header)),
+      NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+  // Initialize SectionName.
+  File->getCOFFObj()->getSectionName(Header, SectionName);
+
+  Align = Header->getAlignment();
+
+  // Only COMDAT sections are subject of dead-stripping.
+  Live = !isCOMDAT();
+}
+
+static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
+static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
+static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
+static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
+
+void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
+                               uint64_t P) const {
+  uint64_t S = Sym->getRVA();
+  switch (Type) {
+  case IMAGE_REL_AMD64_ADDR32:   add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_AMD64_ADDR64:   add64(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
+  case IMAGE_REL_AMD64_REL32:    add32(Off, S - P - 4); break;
+  case IMAGE_REL_AMD64_REL32_1:  add32(Off, S - P - 5); break;
+  case IMAGE_REL_AMD64_REL32_2:  add32(Off, S - P - 6); break;
+  case IMAGE_REL_AMD64_REL32_3:  add32(Off, S - P - 7); break;
+  case IMAGE_REL_AMD64_REL32_4:  add32(Off, S - P - 8); break;
+  case IMAGE_REL_AMD64_REL32_5:  add32(Off, S - P - 9); break;
+  case IMAGE_REL_AMD64_SECTION:  add16(Off, Sym->getSectionIndex()); break;
+  case IMAGE_REL_AMD64_SECREL:   add32(Off, Sym->getSecrel()); break;
+  default:
+    fatal("unsupported relocation type");
+  }
+}
+
+void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
+                               uint64_t P) const {
+  uint64_t S = Sym->getRVA();
+  switch (Type) {
+  case IMAGE_REL_I386_ABSOLUTE: break;
+  case IMAGE_REL_I386_DIR32:    add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_I386_DIR32NB:  add32(Off, S); break;
+  case IMAGE_REL_I386_REL32:    add32(Off, S - P - 4); break;
+  case IMAGE_REL_I386_SECTION:  add16(Off, Sym->getSectionIndex()); break;
+  case IMAGE_REL_I386_SECREL:   add32(Off, Sym->getSecrel()); break;
+  default:
+    fatal("unsupported relocation type");
+  }
+}
+
+static void applyMOV(uint8_t *Off, uint16_t V) {
+  or16(Off, ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
+  or16(Off + 2, ((V & 0x700) << 4) | (V & 0xff));
+}
+
+static void applyMOV32T(uint8_t *Off, uint32_t V) {
+  applyMOV(Off, V);           // set MOVW operand
+  applyMOV(Off + 4, V >> 16); // set MOVT operand
+}
+
+static void applyBranch20T(uint8_t *Off, int32_t V) {
+  uint32_t S = V < 0 ? 1 : 0;
+  uint32_t J1 = (V >> 19) & 1;
+  uint32_t J2 = (V >> 18) & 1;
+  or16(Off, (S << 10) | ((V >> 12) & 0x3f));
+  or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+static void applyBranch24T(uint8_t *Off, int32_t V) {
+  uint32_t S = V < 0 ? 1 : 0;
+  uint32_t J1 = ((~V >> 23) & 1) ^ S;
+  uint32_t J2 = ((~V >> 22) & 1) ^ S;
+  or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
+  or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
+                               uint64_t P) const {
+  uint64_t S = Sym->getRVA();
+  // Pointer to thumb code must have the LSB set.
+  if (Sym->isExecutable())
+    S |= 1;
+  switch (Type) {
+  case IMAGE_REL_ARM_ADDR32:    add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_ARM_ADDR32NB:  add32(Off, S); break;
+  case IMAGE_REL_ARM_MOV32T:    applyMOV32T(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break;
+  case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break;
+  case IMAGE_REL_ARM_BLX23T:    applyBranch24T(Off, S - P - 4); break;
+  default:
+    fatal("unsupported relocation type");
+  }
+}
+
+void SectionChunk::writeTo(uint8_t *Buf) const {
+  if (!hasData())
+    return;
+  // Copy section contents from source object file to output file.
+  ArrayRef<uint8_t> A = getContents();
+  memcpy(Buf + OutputSectionOff, A.data(), A.size());
+
+  // Apply relocations.
+  for (const coff_relocation &Rel : Relocs) {
+    uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+    SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl();
+    Defined *Sym = cast<Defined>(Body);
+    uint64_t P = RVA + Rel.VirtualAddress;
+    switch (Config->Machine) {
+    case AMD64:
+      applyRelX64(Off, Rel.Type, Sym, P);
+      break;
+    case I386:
+      applyRelX86(Off, Rel.Type, Sym, P);
+      break;
+    case ARMNT:
+      applyRelARM(Off, Rel.Type, Sym, P);
+      break;
+    default:
+      llvm_unreachable("unknown machine type");
+    }
+  }
+}
+
+void SectionChunk::addAssociative(SectionChunk *Child) {
+  AssocChildren.push_back(Child);
+}
+
+static uint8_t getBaserelType(const coff_relocation &Rel) {
+  switch (Config->Machine) {
+  case AMD64:
+    if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+      return IMAGE_REL_BASED_DIR64;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  case I386:
+    if (Rel.Type == IMAGE_REL_I386_DIR32)
+      return IMAGE_REL_BASED_HIGHLOW;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  case ARMNT:
+    if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+      return IMAGE_REL_BASED_HIGHLOW;
+    if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+      return IMAGE_REL_BASED_ARM_MOV32T;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  default:
+    llvm_unreachable("unknown machine type");
+  }
+}
+
+// Windows-specific.
+// Collect all locations that contain absolute addresses, which need to be
+// fixed by the loader if load-time relocation is needed.
+// Only called when base relocation is enabled.
+void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
+  for (const coff_relocation &Rel : Relocs) {
+    uint8_t Ty = getBaserelType(Rel);
+    if (Ty == IMAGE_REL_BASED_ABSOLUTE)
+      continue;
+    SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl();
+    if (isa<DefinedAbsolute>(Body))
+      continue;
+    Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
+  }
+}
+
+bool SectionChunk::hasData() const {
+  return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+}
+
+uint32_t SectionChunk::getPermissions() const {
+  return Header->Characteristics & PermMask;
+}
+
+bool SectionChunk::isCOMDAT() const {
+  return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
+}
+
+void SectionChunk::printDiscardedMessage() const {
+  // Removed by dead-stripping. If it's removed by ICF, ICF already
+  // printed out the name, so don't repeat that here.
+  if (Sym && this == Repl)
+    llvm::outs() << "Discarded " << Sym->getName() << "\n";
+}
+
+StringRef SectionChunk::getDebugName() {
+  if (Sym)
+    return Sym->getName();
+  return "";
+}
+
+ArrayRef<uint8_t> SectionChunk::getContents() const {
+  ArrayRef<uint8_t> A;
+  File->getCOFFObj()->getSectionContents(Header, A);
+  return A;
+}
+
+void SectionChunk::replace(SectionChunk *Other) {
+  Other->Repl = Repl;
+  Other->Live = false;
+}
+
+CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
+  // Common symbols are aligned on natural boundaries up to 32 bytes.
+  // This is what MSVC link.exe does.
+  Align = std::min(uint64_t(32), NextPowerOf2(Sym.getValue()));
+}
+
+uint32_t CommonChunk::getPermissions() const {
+  return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+         IMAGE_SCN_MEM_WRITE;
+}
+
+void StringChunk::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
+}
+
+ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
+  // Intel Optimization Manual says that all branch targets
+  // should be 16-byte aligned. MSVC linker does this too.
+  Align = 16;
+}
+
+void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+  // The first two bytes is a JMP instruction. Fill its operand.
+  write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize());
+}
+
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
+  Res->emplace_back(getRVA() + 2);
+}
+
+void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+  // The first two bytes is a JMP instruction. Fill its operand.
+  write32le(Buf + OutputSectionOff + 2,
+            ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
+  Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
+}
+
+void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM));
+  // Fix mov.w and mov.t operands.
+  applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void LocalImportChunk::getBaserels(std::vector<Baserel> *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<ulittle32_t *>(Buf + OutputSectionOff);
+  size_t Cnt = 0;
+  for (Defined *D : Syms)
+    Begin[Cnt++] = D->getRVA();
+  std::sort(Begin, Begin + Cnt);
+}
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
+  // Block header consists of 4 byte page RVA and 4 byte block size.
+  // Each entry is 2 byte. Last entry may be padding.
+  Data.resize(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 (file)
index 0000000..cd0e2e6
--- /dev/null
@@ -0,0 +1,332 @@
+//===- Chunks.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CHUNKS_H
+#define LLD_COFF_CHUNKS_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::ImportDirectoryTableEntry;
+using llvm::object::COFFSymbolRef;
+using llvm::object::SectionRef;
+using llvm::object::coff_relocation;
+using llvm::object::coff_section;
+using llvm::sys::fs::file_magic;
+
+class Baserel;
+class Defined;
+class DefinedImportData;
+class DefinedRegular;
+class ObjectFile;
+class OutputSection;
+class SymbolBody;
+
+// Mask for section types (code, data, bss, disacardable, etc.)
+// and permissions (writable, readable or executable).
+const uint32_t PermMask = 0xFF0000F0;
+
+// A Chunk represents a chunk of data that will occupy space in the
+// output (if the resolver chose that). It may or may not be backed by
+// a section of an input file. It could be linker-created data, or
+// doesn't even have actual data (if common or bss).
+class Chunk {
+public:
+  enum Kind { SectionKind, OtherKind };
+  Kind kind() const { return ChunkKind; }
+  virtual ~Chunk() = default;
+
+  // Returns the size of this chunk (even if this is a common or BSS.)
+  virtual size_t getSize() const = 0;
+
+  // Write this chunk to a mmap'ed file, assuming Buf is pointing to
+  // beginning of the file. Because this function may use RVA values
+  // of other chunks for relocations, you need to set them properly
+  // before calling this function.
+  virtual void writeTo(uint8_t *Buf) const {}
+
+  // The writer sets and uses the addresses.
+  uint64_t getRVA() const { return RVA; }
+  uint32_t getAlign() const { return Align; }
+  void setRVA(uint64_t V) { RVA = V; }
+  void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; }
+
+  // Returns true if this has non-zero data. BSS chunks return
+  // false. If false is returned, the space occupied by this chunk
+  // will be filled with zeros.
+  virtual bool hasData() const { return true; }
+
+  // Returns readable/writable/executable bits.
+  virtual uint32_t getPermissions() const { return 0; }
+
+  // Returns the section name if this is a section chunk.
+  // It is illegal to call this function on non-section chunks.
+  virtual StringRef getSectionName() const {
+    llvm_unreachable("unimplemented getSectionName");
+  }
+
+  // An output section has pointers to chunks in the section, and each
+  // chunk has a back pointer to an output section.
+  void setOutputSection(OutputSection *O) { Out = O; }
+  OutputSection *getOutputSection() { return Out; }
+
+  // Windows-specific.
+  // Collect all locations that contain absolute addresses for base relocations.
+  virtual void getBaserels(std::vector<Baserel> *Res) {}
+
+  // Returns a human-readable name of this chunk. Chunks are unnamed chunks of
+  // bytes, so this is used only for logging or debugging.
+  virtual StringRef getDebugName() { return ""; }
+
+protected:
+  Chunk(Kind K = OtherKind) : ChunkKind(K) {}
+  const Kind ChunkKind;
+
+  // The RVA of this chunk in the output. The writer sets a value.
+  uint64_t RVA = 0;
+
+  // The offset from beginning of the output section. The writer sets a value.
+  uint64_t OutputSectionOff = 0;
+
+  // The output section for this chunk.
+  OutputSection *Out = nullptr;
+
+  // The alignment of this chunk. The writer uses the value.
+  uint32_t Align = 1;
+};
+
+// A chunk corresponding a section of an input file.
+class SectionChunk : public Chunk {
+  // Identical COMDAT Folding feature accesses section internal data.
+  friend class ICF;
+
+public:
+  class symbol_iterator : public llvm::iterator_adaptor_base<
+                              symbol_iterator, const coff_relocation *,
+                              std::random_access_iterator_tag, SymbolBody *> {
+    friend SectionChunk;
+
+    ObjectFile *File;
+
+    symbol_iterator(ObjectFile *File, const coff_relocation *I)
+        : symbol_iterator::iterator_adaptor_base(I), File(File) {}
+
+  public:
+    symbol_iterator() = default;
+
+    SymbolBody *operator*() const {
+      return File->getSymbolBody(I->SymbolTableIndex);
+    }
+  };
+
+  SectionChunk(ObjectFile *File, const coff_section *Header);
+  static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
+  size_t getSize() const override { return Header->SizeOfRawData; }
+  ArrayRef<uint8_t> 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<Baserel> *Res) override;
+  bool isCOMDAT() const;
+  void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+  void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+  void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+
+  // Called if the garbage collector decides to not include this chunk
+  // in a final output. It's supposed to print out a log message to stdout.
+  void printDiscardedMessage() const;
+
+  // Adds COMDAT associative sections to this COMDAT section. A chunk
+  // and its children are treated as a group by the garbage collector.
+  void addAssociative(SectionChunk *Child);
+
+  StringRef getDebugName() override;
+  void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
+
+  // Used by the garbage collector.
+  bool isLive() { return !Config->DoGC || Live; }
+  void markLive() {
+    assert(!isLive() && "Cannot mark an already live section!");
+    Live = true;
+  }
+
+  // Allow iteration over the bodies of this chunk's relocated symbols.
+  llvm::iterator_range<symbol_iterator> symbols() const {
+    return llvm::make_range(symbol_iterator(File, Relocs.begin()),
+                            symbol_iterator(File, Relocs.end()));
+  }
+
+  // Allow iteration over the associated child chunks for this section.
+  ArrayRef<SectionChunk *> children() const { return AssocChildren; }
+
+  // A pointer pointing to a replacement for this chunk.
+  // Initially it points to "this" object. If this chunk is merged
+  // with other chunk by ICF, it points to another chunk,
+  // and this chunk is considrered as dead.
+  SectionChunk *Repl;
+
+  // The CRC of the contents as described in the COFF spec 4.5.5.
+  // Auxiliary Format 5: Section Definitions. Used for ICF.
+  uint32_t Checksum = 0;
+
+private:
+  // A file this chunk was created from.
+  ObjectFile *File;
+
+  const coff_section *Header;
+  StringRef SectionName;
+  std::vector<SectionChunk *> AssocChildren;
+  llvm::iterator_range<const coff_relocation *> Relocs;
+  size_t NumRelocs;
+
+  // Used by the garbage collector.
+  bool Live;
+
+  // Used for ICF (Identical COMDAT Folding)
+  void replace(SectionChunk *Other);
+  std::atomic<uint64_t> GroupID = { 0 };
+
+  // Sym points to a section symbol if this is a COMDAT chunk.
+  DefinedRegular *Sym = nullptr;
+};
+
+// A chunk for common symbols. Common chunks don't have actual data.
+class CommonChunk : public Chunk {
+public:
+  CommonChunk(const COFFSymbolRef Sym);
+  size_t getSize() const override { return Sym.getValue(); }
+  bool hasData() const override { return false; }
+  uint32_t getPermissions() const override;
+  StringRef getSectionName() const override { return ".bss"; }
+
+private:
+  const COFFSymbolRef Sym;
+};
+
+// A chunk for linker-created strings.
+class StringChunk : public Chunk {
+public:
+  explicit StringChunk(StringRef S) : Str(S) {}
+  size_t getSize() const override { return Str.size() + 1; }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  StringRef Str;
+};
+
+static const uint8_t ImportThunkX86[] = {
+    0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
+};
+
+static const uint8_t ImportThunkARM[] = {
+    0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
+    0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
+    0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
+};
+
+// Windows-specific.
+// A chunk for DLL import jump table entry. In a final output, it's
+// contents will be a JMP instruction to some __imp_ symbol.
+class ImportThunkChunkX64 : public Chunk {
+public:
+  explicit ImportThunkChunkX64(Defined *S);
+  size_t getSize() const override { return sizeof(ImportThunkX86); }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+class ImportThunkChunkX86 : public Chunk {
+public:
+  explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {}
+  size_t getSize() const override { return sizeof(ImportThunkX86); }
+  void getBaserels(std::vector<Baserel> *Res) override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM : public Chunk {
+public:
+  explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {}
+  size_t getSize() const override { return sizeof(ImportThunkARM); }
+  void getBaserels(std::vector<Baserel> *Res) override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+// 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<Baserel> *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<Defined *> S) : Syms(std::move(S)) {}
+  size_t getSize() const override { return Syms.size() * 4; }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  std::set<Defined *> Syms;
+};
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+// See the PE/COFF spec 5.6 for details.
+class BaserelChunk : public Chunk {
+public:
+  BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
+  size_t getSize() const override { return Data.size(); }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  std::vector<uint8_t> Data;
+};
+
+class Baserel {
+public:
+  Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
+  explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+  uint8_t getDefaultType();
+
+  uint32_t RVA;
+  uint8_t Type;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Config.h b/COFF/Config.h
new file mode 100644 (file)
index 0000000..a5472e9
--- /dev/null
@@ -0,0 +1,151 @@
+//===- 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 <cstdint>
+#include <map>
+#include <set>
+#include <string>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+class DefinedAbsolute;
+class DefinedRelative;
+class StringChunk;
+class Undefined;
+
+// Short aliases.
+static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+
+// Represents an /export option.
+struct Export {
+  StringRef Name;       // N in /export:N or /export:E=N
+  StringRef ExtName;    // E in /export:E=N
+  Undefined *Sym = nullptr;
+  uint16_t Ordinal = 0;
+  bool Noname = false;
+  bool Data = false;
+  bool Private = false;
+
+  // 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);
+  }
+};
+
+// Global configuration.
+struct Configuration {
+  enum ManifestKind { SideBySide, Embed, No };
+  bool is64() { return Machine == AMD64; }
+
+  llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+  bool Verbose = false;
+  WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+  Undefined *Entry = nullptr;
+  bool NoEntry = false;
+  std::string OutputFile;
+  bool DoGC = true;
+  bool DoICF = true;
+  bool Relocatable = true;
+  bool Force = false;
+  bool Debug = false;
+  bool WriteSymtab = true;
+
+  // Symbols in this set are considered as live by the garbage collector.
+  std::set<Undefined *> GCRoot;
+
+  std::set<StringRef> NoDefaultLibs;
+  bool NoDefaultLibAll = false;
+
+  // True if we are creating a DLL.
+  bool DLL = false;
+  StringRef Implib;
+  std::vector<Export> Exports;
+  std::set<std::string> DelayLoads;
+  std::map<std::string, int> DLLOrder;
+  Undefined *DelayLoadHelper = nullptr;
+
+  // Used for SafeSEH.
+  DefinedRelative *SEHTable = nullptr;
+  DefinedAbsolute *SEHCount = nullptr;
+
+  // Used for /opt:lldlto=N
+  unsigned LTOOptLevel = 2;
+
+  // Used for /opt:lldltojobs=N
+  unsigned LTOJobs = 1;
+
+  // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+  std::map<StringRef, StringRef> Merge;
+
+  // Used for /section=.name,{DEKPRSW} to set section attributes.
+  std::map<StringRef, uint32_t> Section;
+
+  // Options for manifest files.
+  ManifestKind Manifest = SideBySide;
+  int ManifestID = 1;
+  StringRef ManifestDependency;
+  bool ManifestUAC = true;
+  std::vector<std::string> ManifestInput;
+  StringRef ManifestLevel = "'asInvoker'";
+  StringRef ManifestUIAccess = "'false'";
+  StringRef ManifestFile;
+
+  // Used for /failifmismatch.
+  std::map<StringRef, StringRef> MustMatch;
+
+  // Used for /alternatename.
+  std::map<StringRef, StringRef> AlternateNames;
+
+  uint64_t ImageBase = -1;
+  uint64_t StackReserve = 1024 * 1024;
+  uint64_t StackCommit = 4096;
+  uint64_t HeapReserve = 1024 * 1024;
+  uint64_t HeapCommit = 4096;
+  uint32_t MajorImageVersion = 0;
+  uint32_t MinorImageVersion = 0;
+  uint32_t MajorOSVersion = 6;
+  uint32_t MinorOSVersion = 0;
+  bool DynamicBase = true;
+  bool AllowBind = true;
+  bool NxCompat = true;
+  bool AllowIsolation = true;
+  bool TerminalServerAware = true;
+  bool LargeAddressAware = false;
+  bool HighEntropyVA = false;
+};
+
+extern Configuration *Config;
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
new file mode 100644 (file)
index 0000000..9ac370c
--- /dev/null
@@ -0,0 +1,571 @@
+//===- 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<std::vector<DefinedImportData *>>
+binImports(const std::vector<DefinedImportData *> &Imports) {
+  // Group DLL-imported symbols by DLL name because that's how
+  // symbols are layed out in the import descriptor table.
+  auto Less = [](const std::string &A, const std::string &B) {
+    return Config->DLLOrder[A] < Config->DLLOrder[B];
+  };
+  std::map<std::string, std::vector<DefinedImportData *>,
+           bool(*)(const std::string &, const std::string &)> M(Less);
+  for (DefinedImportData *Sym : Imports)
+    M[Sym->getDLLName().lower()].push_back(Sym);
+
+  std::vector<std::vector<DefinedImportData *>> V;
+  for (auto &P : M) {
+    // Sort symbols by name for each group.
+    std::vector<DefinedImportData *> &Syms = P.second;
+    std::sort(Syms.begin(), Syms.end(),
+              [](DefinedImportData *A, DefinedImportData *B) {
+                return A->getName() < B->getName();
+              });
+    V.push_back(std::move(Syms));
+  }
+  return V;
+}
+
+// Export table
+// See Microsoft PE/COFF spec 4.3 for details.
+
+// A chunk for the delay import descriptor table etnry.
+class DelayDirectoryChunk : public Chunk {
+public:
+  explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
+
+  size_t getSize() const override {
+    return sizeof(delay_import_directory_table_entry);
+  }
+
+  void writeTo(uint8_t *Buf) const override {
+    auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
+    E->Attributes = 1;
+    E->Name = DLLName->getRVA();
+    E->ModuleHandle = ModuleHandle->getRVA();
+    E->DelayImportAddressTable = AddressTab->getRVA();
+    E->DelayImportNameTable = NameTab->getRVA();
+  }
+
+  Chunk *DLLName;
+  Chunk *ModuleHandle;
+  Chunk *AddressTab;
+  Chunk *NameTab;
+};
+
+// Initial contents for delay-loaded functions.
+// This code calls __delayLoadHelper2 function to resolve a symbol
+// and then overwrites its jump table slot with the result
+// for subsequent function calls.
+static const uint8_t ThunkX64[] = {
+    0x51,                               // push    rcx
+    0x52,                               // push    rdx
+    0x41, 0x50,                         // push    r8
+    0x41, 0x51,                         // push    r9
+    0x48, 0x83, 0xEC, 0x48,             // sub     rsp, 48h
+    0x66, 0x0F, 0x7F, 0x04, 0x24,       // movdqa  xmmword ptr [rsp], xmm0
+    0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa  xmmword ptr [rsp+10h], xmm1
+    0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa  xmmword ptr [rsp+20h], xmm2
+    0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa  xmmword ptr [rsp+30h], xmm3
+    0x48, 0x8D, 0x15, 0, 0, 0, 0,       // lea     rdx, [__imp_<FUNCNAME>]
+    0x48, 0x8D, 0x0D, 0, 0, 0, 0,       // lea     rcx, [___DELAY_IMPORT_...]
+    0xE8, 0, 0, 0, 0,                   // call    __delayLoadHelper2
+    0x66, 0x0F, 0x6F, 0x04, 0x24,       // movdqa  xmm0, xmmword ptr [rsp]
+    0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa  xmm1, xmmword ptr [rsp+10h]
+    0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa  xmm2, xmmword ptr [rsp+20h]
+    0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa  xmm3, xmmword ptr [rsp+30h]
+    0x48, 0x83, 0xC4, 0x48,             // add     rsp, 48h
+    0x41, 0x59,                         // pop     r9
+    0x41, 0x58,                         // pop     r8
+    0x5A,                               // pop     rdx
+    0x59,                               // pop     rcx
+    0xFF, 0xE0,                         // jmp     rax
+};
+
+static const uint8_t ThunkX86[] = {
+    0x51,              // push  ecx
+    0x52,              // push  edx
+    0x68, 0, 0, 0, 0,  // push  offset ___imp__<FUNCNAME>
+    0x68, 0, 0, 0, 0,  // push  offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
+    0xE8, 0, 0, 0, 0,  // call  ___delayLoadHelper2@8
+    0x5A,              // pop   edx
+    0x59,              // pop   ecx
+    0xFF, 0xE0,        // jmp   eax
+};
+
+// A chunk for the delay import thunk.
+class ThunkChunkX64 : public Chunk {
+public:
+  ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
+      : Imp(I), Desc(D), Helper(H) {}
+
+  size_t getSize() const override { return sizeof(ThunkX64); }
+
+  void writeTo(uint8_t *Buf) const override {
+    memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64));
+    write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40);
+    write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47);
+    write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52);
+  }
+
+  Defined *Imp = nullptr;
+  Chunk *Desc = nullptr;
+  Defined *Helper = nullptr;
+};
+
+class ThunkChunkX86 : public Chunk {
+public:
+  ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
+      : Imp(I), Desc(D), Helper(H) {}
+
+  size_t getSize() const override { return sizeof(ThunkX86); }
+
+  void writeTo(uint8_t *Buf) const override {
+    memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86));
+    write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase);
+    write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase);
+    write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17);
+  }
+
+  void getBaserels(std::vector<Baserel> *Res) override {
+    Res->emplace_back(RVA + 3);
+    Res->emplace_back(RVA + 8);
+  }
+
+  Defined *Imp = nullptr;
+  Chunk *Desc = nullptr;
+  Defined *Helper = nullptr;
+};
+
+// 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<Baserel> *Res) override {
+    Res->emplace_back(RVA);
+  }
+
+  Chunk *Thunk;
+};
+
+// Export table
+// Read Microsoft PE/COFF spec 5.3 for details.
+
+// A chunk for the export descriptor table.
+class ExportDirectoryChunk : public Chunk {
+public:
+  ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
+      : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
+        OrdinalTab(O) {}
+
+  size_t getSize() const override {
+    return sizeof(export_directory_table_entry);
+  }
+
+  void writeTo(uint8_t *Buf) const override {
+    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<Defined>(E.Sym->repl())->getRVA());
+      }
+    }
+  }
+
+private:
+  size_t Size;
+};
+
+class NamePointersChunk : public Chunk {
+public:
+  explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
+  size_t getSize() const override { return Chunks.size() * 4; }
+
+  void writeTo(uint8_t *Buf) const override {
+    uint8_t *P = Buf + OutputSectionOff;
+    for (Chunk *C : Chunks) {
+      write32le(P, C->getRVA());
+      P += 4;
+    }
+  }
+
+private:
+  std::vector<Chunk *> Chunks;
+};
+
+class ExportOrdinalChunk : public Chunk {
+public:
+  explicit ExportOrdinalChunk(size_t I) : Size(I) {}
+  size_t getSize() const override { return Size * 2; }
+
+  void writeTo(uint8_t *Buf) const override {
+    uint8_t *P = Buf + OutputSectionOff;
+    for (Export &E : Config->Exports) {
+      if (E.Noname)
+        continue;
+      write16le(P, E.Ordinal);
+      P += 2;
+    }
+  }
+
+private:
+  size_t Size;
+};
+
+} // anonymous namespace
+
+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<Chunk *> IdataContents::getChunks() {
+  create();
+  std::vector<Chunk *> V;
+  // The loader assumes a specific order of data.
+  // Add each type in the correct order.
+  for (std::unique_ptr<Chunk> &C : Dirs)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Lookups)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Addresses)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Hints)
+    V.push_back(C.get());
+  for (auto &P : DLLNames) {
+    std::unique_ptr<Chunk> &C = P.second;
+    V.push_back(C.get());
+  }
+  return V;
+}
+
+void IdataContents::create() {
+  std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+  // Create .idata contents for each DLL.
+  for (std::vector<DefinedImportData *> &Syms : V) {
+    StringRef Name = Syms[0]->getDLLName();
+
+    // Create lookup and address tables. If they have external names,
+    // we need to create HintName chunks to store the names.
+    // If they don't (if they are import-by-ordinals), we store only
+    // ordinal values to the table.
+    size_t Base = Lookups.size();
+    for (DefinedImportData *S : Syms) {
+      uint16_t Ord = S->getOrdinal();
+      if (S->getExternalName().empty()) {
+        Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+        Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+        continue;
+      }
+      auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
+      Lookups.push_back(make_unique<LookupChunk>(C.get()));
+      Addresses.push_back(make_unique<LookupChunk>(C.get()));
+      Hints.push_back(std::move(C));
+    }
+    // Terminate with null values.
+    Lookups.push_back(make_unique<NullChunk>(ptrSize()));
+    Addresses.push_back(make_unique<NullChunk>(ptrSize()));
+
+    for (int I = 0, E = Syms.size(); I < E; ++I)
+      Syms[I]->setLocation(Addresses[Base + I].get());
+
+    // Create the import table header.
+    if (!DLLNames.count(Name))
+      DLLNames[Name] = make_unique<StringChunk>(Name);
+    auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
+    Dir->LookupTab = Lookups[Base].get();
+    Dir->AddressTab = Addresses[Base].get();
+    Dirs.push_back(std::move(Dir));
+  }
+  // Add null terminator.
+  Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+}
+
+std::vector<Chunk *> DelayLoadContents::getChunks() {
+  std::vector<Chunk *> V;
+  for (std::unique_ptr<Chunk> &C : Dirs)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Names)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : HintNames)
+    V.push_back(C.get());
+  for (auto &P : DLLNames) {
+    std::unique_ptr<Chunk> &C = P.second;
+    V.push_back(C.get());
+  }
+  return V;
+}
+
+std::vector<Chunk *> DelayLoadContents::getDataChunks() {
+  std::vector<Chunk *> V;
+  for (std::unique_ptr<Chunk> &C : ModuleHandles)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Addresses)
+    V.push_back(C.get());
+  return V;
+}
+
+uint64_t DelayLoadContents::getDirSize() {
+  return Dirs.size() * sizeof(delay_import_directory_table_entry);
+}
+
+void DelayLoadContents::create(Defined *H) {
+  Helper = H;
+  std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+  // Create .didat contents for each DLL.
+  for (std::vector<DefinedImportData *> &Syms : V) {
+    StringRef Name = Syms[0]->getDLLName();
+
+    // Create the delay import table header.
+    if (!DLLNames.count(Name))
+      DLLNames[Name] = make_unique<StringChunk>(Name);
+    auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
+
+    size_t Base = Addresses.size();
+    for (DefinedImportData *S : Syms) {
+      Chunk *T = newThunkChunk(S, Dir.get());
+      auto A = make_unique<DelayAddressChunk>(T);
+      Addresses.push_back(std::move(A));
+      Thunks.push_back(std::unique_ptr<Chunk>(T));
+      StringRef ExtName = S->getExternalName();
+      if (ExtName.empty()) {
+        Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
+      } else {
+        auto C = make_unique<HintNameChunk>(ExtName, 0);
+        Names.push_back(make_unique<LookupChunk>(C.get()));
+        HintNames.push_back(std::move(C));
+      }
+    }
+    // Terminate with null values.
+    Addresses.push_back(make_unique<NullChunk>(8));
+    Names.push_back(make_unique<NullChunk>(8));
+
+    for (int I = 0, E = Syms.size(); I < E; ++I)
+      Syms[I]->setLocation(Addresses[Base + I].get());
+    auto *MH = new NullChunk(8);
+    MH->setAlign(8);
+    ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
+
+    // Fill the delay import table header fields.
+    Dir->ModuleHandle = MH;
+    Dir->AddressTab = Addresses[Base].get();
+    Dir->NameTab = Names[Base].get();
+    Dirs.push_back(std::move(Dir));
+  }
+  // Add null terminator.
+  Dirs.push_back(
+      make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
+}
+
+Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
+  switch (Config->Machine) {
+  case AMD64:
+    return new ThunkChunkX64(S, Dir, Helper);
+  case I386:
+    return new ThunkChunkX86(S, Dir, Helper);
+  default:
+    llvm_unreachable("unsupported machine type");
+  }
+}
+
+EdataContents::EdataContents() {
+  uint16_t MaxOrdinal = 0;
+  for (Export &E : Config->Exports)
+    MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
+
+  auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
+  auto *AddressTab = new AddressTableChunk(MaxOrdinal);
+  std::vector<Chunk *> Names;
+  for (Export &E : Config->Exports)
+    if (!E.Noname)
+      Names.push_back(new StringChunk(E.ExportName));
+
+  std::vector<Chunk *> Forwards;
+  for (Export &E : Config->Exports) {
+    if (E.ForwardTo.empty())
+      continue;
+    E.ForwardChunk = new StringChunk(E.ForwardTo);
+    Forwards.push_back(E.ForwardChunk);
+  }
+
+  auto *NameTab = new NamePointersChunk(Names);
+  auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
+  auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
+                                       AddressTab, NameTab, OrdinalTab);
+  Chunks.push_back(std::unique_ptr<Chunk>(Dir));
+  Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
+  Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
+  Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
+  Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
+  for (Chunk *C : Names)
+    Chunks.push_back(std::unique_ptr<Chunk>(C));
+  for (Chunk *C : Forwards)
+    Chunks.push_back(std::unique_ptr<Chunk>(C));
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/DLL.h b/COFF/DLL.h
new file mode 100644 (file)
index 0000000..83a12df
--- /dev/null
@@ -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<Chunk *> 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<DefinedImportData *> Imports;
+  std::vector<std::unique_ptr<Chunk>> Dirs;
+  std::vector<std::unique_ptr<Chunk>> Lookups;
+  std::vector<std::unique_ptr<Chunk>> Addresses;
+  std::vector<std::unique_ptr<Chunk>> Hints;
+  std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+};
+
+// Windows-specific.
+// DelayLoadContents creates all chunks for the delay-load DLL import table.
+class DelayLoadContents {
+public:
+  void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+  bool empty() { return Imports.empty(); }
+  void create(Defined *Helper);
+  std::vector<Chunk *> getChunks();
+  std::vector<Chunk *> getDataChunks();
+  std::vector<std::unique_ptr<Chunk>> &getCodeChunks() { return Thunks; }
+
+  uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+  uint64_t getDirSize();
+
+private:
+  Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
+
+  Defined *Helper;
+  std::vector<DefinedImportData *> Imports;
+  std::vector<std::unique_ptr<Chunk>> Dirs;
+  std::vector<std::unique_ptr<Chunk>> ModuleHandles;
+  std::vector<std::unique_ptr<Chunk>> Addresses;
+  std::vector<std::unique_ptr<Chunk>> Names;
+  std::vector<std::unique_ptr<Chunk>> HintNames;
+  std::vector<std::unique_ptr<Chunk>> Thunks;
+  std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+};
+
+// Windows-specific.
+// EdataContents creates all chunks for the DLL export table.
+class EdataContents {
+public:
+  EdataContents();
+  std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
new file mode 100644 (file)
index 0000000..bb6a60e
--- /dev/null
@@ -0,0 +1,694 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/LibDriver/LibDriver.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using llvm::sys::Process;
+using llvm::sys::fs::OpenFlags;
+using llvm::sys::fs::file_magic;
+using llvm::sys::fs::identify_magic;
+
+namespace lld {
+namespace coff {
+
+Configuration *Config;
+LinkerDriver *Driver;
+
+bool link(llvm::ArrayRef<const char *> Args) {
+  Configuration C;
+  LinkerDriver D;
+  Config = &C;
+  Driver = &D;
+  Driver->link(Args);
+  return true;
+}
+
+// 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();
+}
+
+// Opens a file. Path has to be resolved already.
+// Newly created memory buffers are owned by this driver.
+MemoryBufferRef LinkerDriver::openFile(StringRef Path) {
+  std::unique_ptr<MemoryBuffer> MB =
+      check(MemoryBuffer::getFile(Path), "could not open " + Path);
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  OwningMBs.push_back(std::move(MB)); // take ownership
+  return MBRef;
+}
+
+static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
+  // File type is detected by contents, not by file extension.
+  file_magic Magic = identify_magic(MB.getBuffer());
+  if (Magic == file_magic::archive)
+    return std::unique_ptr<InputFile>(new ArchiveFile(MB));
+  if (Magic == file_magic::bitcode)
+    return std::unique_ptr<InputFile>(new BitcodeFile(MB));
+  if (Config->OutputFile == "")
+    Config->OutputFile = getOutputPath(MB.getBufferIdentifier());
+  return std::unique_ptr<InputFile>(new ObjectFile(MB));
+}
+
+static bool isDecorated(StringRef Sym) {
+  return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
+// Parses .drectve section contents and returns a list of files
+// specified by /defaultlib.
+void LinkerDriver::parseDirectives(StringRef S) {
+  llvm::opt::InputArgList Args = Parser.parse(S);
+
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_alternatename:
+      parseAlternateName(Arg->getValue());
+      break;
+    case OPT_defaultlib:
+      if (Optional<StringRef> Path = findLib(Arg->getValue())) {
+        MemoryBufferRef MB = openFile(*Path);
+        Symtab.addFile(createFile(MB));
+      }
+      break;
+    case OPT_export: {
+      Export E = parseExport(Arg->getValue());
+      E.Directives = true;
+      Config->Exports.push_back(E);
+      break;
+    }
+    case OPT_failifmismatch:
+      checkFailIfMismatch(Arg->getValue());
+      break;
+    case OPT_incl:
+      addUndefined(Arg->getValue());
+      break;
+    case OPT_merge:
+      parseMerge(Arg->getValue());
+      break;
+    case OPT_nodefaultlib:
+      Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+      break;
+    case OPT_section:
+      parseSection(Arg->getValue());
+      break;
+    case OPT_editandcontinue:
+    case OPT_fastfail:
+    case OPT_guardsym:
+    case OPT_throwingnew:
+      break;
+    default:
+      fatal(Arg->getSpelling() + " is not allowed in .drectve");
+    }
+  }
+}
+
+// Find file from search paths. You can omit ".obj", this function takes
+// care of that. Note that the returned path is not guaranteed to exist.
+StringRef LinkerDriver::doFindFile(StringRef Filename) {
+  bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
+  if (hasPathSep)
+    return Filename;
+  bool hasExt = (Filename.find('.') != StringRef::npos);
+  for (StringRef Dir : SearchPaths) {
+    SmallString<128> Path = Dir;
+    llvm::sys::path::append(Path, Filename);
+    if (llvm::sys::fs::exists(Path.str()))
+      return Alloc.save(Path.str());
+    if (!hasExt) {
+      Path.append(".obj");
+      if (llvm::sys::fs::exists(Path.str()))
+        return Alloc.save(Path.str());
+    }
+  }
+  return Filename;
+}
+
+// Resolves a file path. This never returns the same path
+// (in that case, it returns None).
+Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
+  StringRef Path = doFindFile(Filename);
+  bool Seen = !VisitedFiles.insert(Path.lower()).second;
+  if (Seen)
+    return None;
+  return Path;
+}
+
+// Find library file from search path.
+StringRef LinkerDriver::doFindLib(StringRef Filename) {
+  // Add ".lib" to Filename if that has no file extension.
+  bool hasExt = (Filename.find('.') != StringRef::npos);
+  if (!hasExt)
+    Filename = Alloc.save(Filename + ".lib");
+  return doFindFile(Filename);
+}
+
+// Resolves a library path. /nodefaultlib options are taken into
+// consideration. This never returns the same path (in that case,
+// it returns None).
+Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
+  if (Config->NoDefaultLibAll)
+    return None;
+  StringRef Path = doFindLib(Filename);
+  if (Config->NoDefaultLibs.count(Path))
+    return None;
+  bool Seen = !VisitedFiles.insert(Path.lower()).second;
+  if (Seen)
+    return None;
+  return Path;
+}
+
+// Parses LIB environment which contains a list of search paths.
+void LinkerDriver::addLibSearchPaths() {
+  Optional<std::string> EnvOpt = Process::GetEnv("LIB");
+  if (!EnvOpt.hasValue())
+    return;
+  StringRef Env = Alloc.save(*EnvOpt);
+  while (!Env.empty()) {
+    StringRef Path;
+    std::tie(Path, Env) = Env.split(';');
+    SearchPaths.push_back(Path);
+  }
+}
+
+Undefined *LinkerDriver::addUndefined(StringRef Name) {
+  Undefined *U = Symtab.addUndefined(Name);
+  Config->GCRoot.insert(U);
+  return U;
+}
+
+// Symbol names are mangled by appending "_" prefix on x86.
+StringRef LinkerDriver::mangle(StringRef Sym) {
+  assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+  if (Config->Machine == I386)
+    return Alloc.save("_" + Sym);
+  return Sym;
+}
+
+// Windows specific -- find default entry point name.
+StringRef LinkerDriver::findDefaultEntry() {
+  // User-defined main functions and their corresponding entry points.
+  static const char *Entries[][2] = {
+      {"main", "mainCRTStartup"},
+      {"wmain", "wmainCRTStartup"},
+      {"WinMain", "WinMainCRTStartup"},
+      {"wWinMain", "wWinMainCRTStartup"},
+  };
+  for (auto E : Entries) {
+    StringRef Entry = Symtab.findMangle(mangle(E[0]));
+    if (!Entry.empty() && !isa<Undefined>(Symtab.find(Entry)->Body))
+      return mangle(E[1]);
+  }
+  return "";
+}
+
+WindowsSubsystem LinkerDriver::inferSubsystem() {
+  if (Config->DLL)
+    return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+  if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain"))
+    return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+  if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain"))
+    return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+  return IMAGE_SUBSYSTEM_UNKNOWN;
+}
+
+static uint64_t getDefaultImageBase() {
+  if (Config->is64())
+    return Config->DLL ? 0x180000000 : 0x140000000;
+  return Config->DLL ? 0x10000000 : 0x400000;
+}
+
+void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
+  // If the first command line argument is "/lib", link.exe acts like lib.exe.
+  // We call our own implementation of lib.exe that understands bitcode files.
+  if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) {
+    if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
+      fatal("lib failed");
+    return;
+  }
+
+  // Needed for LTO.
+  llvm::InitializeAllTargetInfos();
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmParsers();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllDisassemblers();
+
+  // Parse command line options.
+  llvm::opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+
+  // Handle /help
+  if (Args.hasArg(OPT_help)) {
+    printHelp(ArgsArr[0]);
+    return;
+  }
+
+  if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
+    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;
+
+  // Handle /noentry
+  if (Args.hasArg(OPT_noentry)) {
+    if (!Args.hasArg(OPT_dll))
+      fatal("/noentry must be specified with /dll");
+    Config->NoEntry = true;
+  }
+
+  // Handle /dll
+  if (Args.hasArg(OPT_dll)) {
+    Config->DLL = true;
+    Config->ManifestID = 2;
+  }
+
+  // Handle /fixed
+  if (Args.hasArg(OPT_fixed)) {
+    if (Args.hasArg(OPT_dynamicbase))
+      fatal("/fixed must not be specified with /dynamicbase");
+    Config->Relocatable = false;
+    Config->DynamicBase = false;
+  }
+
+  // Handle /machine
+  if (auto *Arg = Args.getLastArg(OPT_machine))
+    Config->Machine = getMachineType(Arg->getValue());
+
+  // Handle /nodefaultlib:<filename>
+  for (auto *Arg : Args.filtered(OPT_nodefaultlib))
+    Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+
+  // Handle /nodefaultlib
+  if (Args.hasArg(OPT_nodefaultlib_all))
+    Config->NoDefaultLibAll = true;
+
+  // Handle /base
+  if (auto *Arg = Args.getLastArg(OPT_base))
+    parseNumbers(Arg->getValue(), &Config->ImageBase);
+
+  // Handle /stack
+  if (auto *Arg = Args.getLastArg(OPT_stack))
+    parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+
+  // Handle /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<StringRef, 1> 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)
+          fatal("/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)
+          fatal("/opt:lldltojobs: invalid job count: " + Jobs);
+        continue;
+      }
+      if (S != "ref" && S != "lbr" && S != "nolbr")
+        fatal("/opt: unknown option: " + S);
+    }
+  }
+
+  // Handle /failifmismatch
+  for (auto *Arg : Args.filtered(OPT_failifmismatch))
+    checkFailIfMismatch(Arg->getValue());
+
+  // Handle /merge
+  for (auto *Arg : Args.filtered(OPT_merge))
+    parseMerge(Arg->getValue());
+
+  // Handle /section
+  for (auto *Arg : Args.filtered(OPT_section))
+    parseSection(Arg->getValue());
+
+  // Handle /manifest
+  if (auto *Arg = Args.getLastArg(OPT_manifest_colon))
+    parseManifest(Arg->getValue());
+
+  // Handle /manifestuac
+  if (auto *Arg = Args.getLastArg(OPT_manifestuac))
+    parseManifestUAC(Arg->getValue());
+
+  // Handle /manifestdependency
+  if (auto *Arg = Args.getLastArg(OPT_manifestdependency))
+    Config->ManifestDependency = Arg->getValue();
+
+  // Handle /manifestfile
+  if (auto *Arg = Args.getLastArg(OPT_manifestfile))
+    Config->ManifestFile = Arg->getValue();
+
+  // Handle /manifestinput
+  for (auto *Arg : Args.filtered(OPT_manifestinput))
+    Config->ManifestInput.push_back(Arg->getValue());
+
+  // Handle miscellaneous boolean flags.
+  if (Args.hasArg(OPT_allowbind_no))
+    Config->AllowBind = false;
+  if (Args.hasArg(OPT_allowisolation_no))
+    Config->AllowIsolation = false;
+  if (Args.hasArg(OPT_dynamicbase_no))
+    Config->DynamicBase = false;
+  if (Args.hasArg(OPT_nxcompat_no))
+    Config->NxCompat = false;
+  if (Args.hasArg(OPT_tsaware_no))
+    Config->TerminalServerAware = false;
+  if (Args.hasArg(OPT_nosymtab))
+    Config->WriteSymtab = false;
+
+  // Create a list of input files. Files can be given as arguments
+  // for /defaultlib option.
+  std::vector<StringRef> Paths;
+  std::vector<MemoryBufferRef> MBs;
+  for (auto *Arg : Args.filtered(OPT_INPUT))
+    if (Optional<StringRef> Path = findFile(Arg->getValue()))
+      Paths.push_back(*Path);
+  for (auto *Arg : Args.filtered(OPT_defaultlib))
+    if (Optional<StringRef> Path = findLib(Arg->getValue()))
+      Paths.push_back(*Path);
+  for (StringRef Path : Paths)
+    MBs.push_back(openFile(Path));
+
+  // Windows specific -- Create a resource file containing a manifest file.
+  if (Config->Manifest == Configuration::Embed) {
+    std::unique_ptr<MemoryBuffer> MB = createManifestRes();
+    MBs.push_back(MB->getMemBufferRef());
+    OwningMBs.push_back(std::move(MB)); // take ownership
+  }
+
+  // Windows specific -- Input files can be Windows resource files (.res files).
+  // We invoke cvtres.exe to convert resource files to a regular COFF file
+  // then link the result file normally.
+  std::vector<MemoryBufferRef> Resources;
+  auto NotResource = [](MemoryBufferRef MB) {
+    return identify_magic(MB.getBuffer()) != file_magic::windows_resource;
+  };
+  auto It = std::stable_partition(MBs.begin(), MBs.end(), NotResource);
+  if (It != MBs.end()) {
+    Resources.insert(Resources.end(), It, MBs.end());
+    MBs.erase(It, MBs.end());
+  }
+
+  // Read all input files given via the command line. Note that step()
+  // doesn't read files that are specified by directive sections.
+  for (MemoryBufferRef MB : MBs)
+    Symtab.addFile(createFile(MB));
+  Symtab.step();
+
+  // Determine machine type and check if all object files are
+  // for the same CPU type. Note that this needs to be done before
+  // any call to mangle().
+  for (std::unique_ptr<InputFile> &File : Symtab.getFiles()) {
+    MachineTypes MT = File->getMachineType();
+    if (MT == IMAGE_FILE_MACHINE_UNKNOWN)
+      continue;
+    if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+      Config->Machine = MT;
+      continue;
+    }
+    if (Config->Machine != MT)
+      fatal(File->getShortName() + ": machine type " + machineToStr(MT) +
+            " conflicts with " + machineToStr(Config->Machine));
+  }
+  if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+    llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n";
+    Config->Machine = AMD64;
+  }
+
+  // Windows specific -- Convert Windows resource files to a COFF file.
+  if (!Resources.empty()) {
+    std::unique_ptr<MemoryBuffer> MB = convertResToCOFF(Resources);
+    Symtab.addFile(createFile(MB->getMemBufferRef()));
+    OwningMBs.push_back(std::move(MB)); // take ownership
+  }
+
+  // Handle /largeaddressaware
+  if (Config->is64() || Args.hasArg(OPT_largeaddressaware))
+    Config->LargeAddressAware = true;
+
+  // Handle /highentropyva
+  if (Config->is64() && !Args.hasArg(OPT_highentropyva_no))
+    Config->HighEntropyVA = true;
+
+  // Handle /entry and /dll
+  if (auto *Arg = Args.getLastArg(OPT_entry)) {
+    Config->Entry = addUndefined(mangle(Arg->getValue()));
+  } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) {
+    StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+                                            : "_DllMainCRTStartup";
+    Config->Entry = addUndefined(S);
+  } else if (!Config->NoEntry) {
+    // Windows specific -- If entry point name is not given, we need to
+    // infer that from user-defined entry name.
+    StringRef S = findDefaultEntry();
+    if (S.empty())
+      fatal("entry point must be defined");
+    Config->Entry = addUndefined(S);
+    if (Config->Verbose)
+      llvm::outs() << "Entry name inferred: " << S << "\n";
+  }
+
+  // Handle /export
+  for (auto *Arg : Args.filtered(OPT_export)) {
+    Export E = parseExport(Arg->getValue());
+    if (Config->Machine == I386) {
+      if (!isDecorated(E.Name))
+        E.Name = Alloc.save("_" + E.Name);
+      if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+        E.ExtName = Alloc.save("_" + E.ExtName);
+    }
+    Config->Exports.push_back(E);
+  }
+
+  // Handle /def
+  if (auto *Arg = Args.getLastArg(OPT_deffile)) {
+    MemoryBufferRef MB = openFile(Arg->getValue());
+    // parseModuleDefs mutates Config object.
+    parseModuleDefs(MB, &Alloc);
+  }
+
+  // Handle /delayload
+  for (auto *Arg : Args.filtered(OPT_delayload)) {
+    Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
+    if (Config->Machine == I386) {
+      Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
+    } else {
+      Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
+    }
+  }
+
+  // Set default image base if /base is not given.
+  if (Config->ImageBase == uint64_t(-1))
+    Config->ImageBase = getDefaultImageBase();
+
+  Symtab.addRelative(mangle("__ImageBase"), 0);
+  if (Config->Machine == I386) {
+    Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0);
+    Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0);
+  }
+
+  // We do not support /guard:cf (control flow protection) yet.
+  // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
+  Symtab.addAbsolute(mangle("__guard_fids_table"), 0);
+  Symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+  Symtab.addAbsolute(mangle("__guard_flags"), 0x100);
+
+  // Read as much files as we can from directives sections.
+  Symtab.run();
+
+  // Resolve auxiliary symbols until we get a convergence.
+  // (Trying to resolve a symbol may trigger a Lazy symbol to load a new file.
+  // A new file may contain a directive section to add new command line options.
+  // That's why we have to repeat until converge.)
+  for (;;) {
+    // Windows specific -- if entry point is not found,
+    // search for its mangled names.
+    if (Config->Entry)
+      Symtab.mangleMaybe(Config->Entry);
+
+    // Windows specific -- Make sure we resolve all dllexported symbols.
+    for (Export &E : Config->Exports) {
+      if (!E.ForwardTo.empty())
+        continue;
+      E.Sym = addUndefined(E.Name);
+      if (!E.Directives)
+        Symtab.mangleMaybe(E.Sym);
+    }
+
+    // Add weak aliases. Weak aliases is a mechanism to give remaining
+    // undefined symbols final chance to be resolved successfully.
+    for (auto Pair : Config->AlternateNames) {
+      StringRef From = Pair.first;
+      StringRef To = Pair.second;
+      Symbol *Sym = Symtab.find(From);
+      if (!Sym)
+        continue;
+      if (auto *U = dyn_cast<Undefined>(Sym->Body))
+        if (!U->WeakAlias)
+          U->WeakAlias = Symtab.addUndefined(To);
+    }
+
+    // Windows specific -- if __load_config_used can be resolved, resolve it.
+    if (Symtab.findUnderscore("_load_config_used"))
+      addUndefined(mangle("_load_config_used"));
+
+    if (Symtab.queueEmpty())
+      break;
+    Symtab.run();
+  }
+
+  // Do LTO by compiling bitcode input files to a set of native COFF files then
+  // link those files.
+  Symtab.addCombinedLTOObjects();
+
+  // Make sure we have resolved all symbols.
+  Symtab.reportRemainingUndefines(/*Resolve=*/true);
+
+  // Windows specific -- if no /subsystem is given, we need to infer
+  // that from entry point name.
+  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+    Config->Subsystem = inferSubsystem();
+    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+      fatal("subsystem must be defined");
+  }
+
+  // Handle /safeseh.
+  if (Args.hasArg(OPT_safeseh))
+    for (ObjectFile *File : Symtab.ObjectFiles)
+      if (!File->SEHCompat)
+        fatal("/safeseh: " + File->getName() + " is not compatible with SEH");
+
+  // Windows specific -- when we are creating a .dll file, we also
+  // need to create a .lib file.
+  if (!Config->Exports.empty() || Config->DLL) {
+    fixupExports();
+    writeImportLibrary();
+    assignExportOrdinals();
+  }
+
+  // Windows specific -- Create a side-by-side manifest file.
+  if (Config->Manifest == Configuration::SideBySide)
+    createSideBySideManifest();
+
+  // Create a dummy PDB file to satisfy build sytem rules.
+  if (auto *Arg = Args.getLastArg(OPT_pdb))
+    createPDB(Arg->getValue());
+
+  // Identify unreferenced COMDAT sections.
+  if (Config->DoGC)
+    markLive(Symtab.getChunks());
+
+  // Identify identical COMDAT sections to merge them.
+  if (Config->DoICF)
+    doICF(Symtab.getChunks());
+
+  // Write the result.
+  writeResult(&Symtab);
+
+  // Create a symbol map file containing symbol VAs and their names
+  // to help debugging.
+  if (auto *Arg = Args.getLastArg(OPT_lldmap)) {
+    std::error_code EC;
+    llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text);
+    if (EC)
+      fatal(EC, "could not create the symbol map");
+    Symtab.printMap(Out);
+  }
+  // Call exit to avoid calling destructors.
+  exit(0);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Driver.h b/COFF/Driver.h
new file mode 100644 (file)
index 0000000..23969ee
--- /dev/null
@@ -0,0 +1,177 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DRIVER_H
+#define LLD_COFF_DRIVER_H
+
+#include "Config.h"
+#include "SymbolTable.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class LinkerDriver;
+extern LinkerDriver *Driver;
+
+using llvm::COFF::MachineTypes;
+using llvm::COFF::WindowsSubsystem;
+using llvm::Optional;
+class InputFile;
+
+// Implemented in MarkLive.cpp.
+void markLive(const std::vector<Chunk *> &Chunks);
+
+// Implemented in ICF.cpp.
+void doICF(const std::vector<Chunk *> &Chunks);
+
+class ArgParser {
+public:
+  ArgParser() : Alloc(AllocAux) {}
+  // Parses command line options.
+  llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
+
+  // Concatenate LINK environment varirable and given arguments and parse them.
+  llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> 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<const char *> tokenize(StringRef S);
+
+  std::vector<const char *> replaceResponseFiles(std::vector<const char *>);
+
+  llvm::BumpPtrAllocator AllocAux;
+  llvm::StringSaver Alloc;
+};
+
+class LinkerDriver {
+public:
+  LinkerDriver() : Alloc(AllocAux) {}
+  void link(llvm::ArrayRef<const char *> Args);
+
+  // Used by the resolver to parse .drectve section contents.
+  void parseDirectives(StringRef S);
+
+private:
+  llvm::BumpPtrAllocator AllocAux;
+  llvm::StringSaver Alloc;
+  ArgParser Parser;
+  SymbolTable Symtab;
+
+  // Opens a file. Path has to be resolved already.
+  MemoryBufferRef openFile(StringRef Path);
+
+  // Searches a file from search paths.
+  Optional<StringRef> findFile(StringRef Filename);
+  Optional<StringRef> 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<StringRef> SearchPaths;
+  std::set<std::string> VisitedFiles;
+
+  Undefined *addUndefined(StringRef Sym);
+  StringRef mangle(StringRef Sym);
+
+  // Windows specific -- "main" is not the only main function in Windows.
+  // You can choose one from these four -- {w,}{WinMain,main}.
+  // There are four different entry point functions for them,
+  // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to
+  // choose the right one depending on which "main" function is defined.
+  // This function looks up the symbol table and resolve corresponding
+  // entry point name.
+  StringRef findDefaultEntry();
+  WindowsSubsystem inferSubsystem();
+
+  // Driver is the owner of all opened files.
+  // InputFiles have MemoryBufferRefs to them.
+  std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
+};
+
+void parseModuleDefs(MemoryBufferRef MB, llvm::StringSaver *Alloc);
+void writeImportLibrary();
+
+// Functions below this line are defined in DriverUtils.cpp.
+
+void printHelp(const char *Argv0);
+
+// For /machine option.
+MachineTypes getMachineType(StringRef Arg);
+StringRef machineToStr(MachineTypes MT);
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// Minor's default value is 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+                    uint32_t *Minor);
+
+void parseAlternateName(StringRef);
+void parseMerge(StringRef);
+void parseSection(StringRef);
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+void parseManifest(StringRef Arg);
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>"
+void parseManifestUAC(StringRef Arg);
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes();
+void createSideBySideManifest();
+
+// Used for dllexported symbols.
+Export parseExport(StringRef Arg);
+void fixupExports();
+void assignExportOrdinals();
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the key.
+// This feature used in the directive section to reject
+// incompatible objects.
+void checkFailIfMismatch(StringRef Arg);
+
+// Convert Windows resource files (.res files) to a .obj file
+// using cvtres.exe.
+std::unique_ptr<MemoryBuffer>
+convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
+
+void createPDB(StringRef Path);
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
new file mode 100644 (file)
index 0000000..5d7dc2b
--- /dev/null
@@ -0,0 +1,659 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+using namespace llvm::COFF;
+using namespace llvm;
+using llvm::cl::ExpandResponseFiles;
+using llvm::cl::TokenizeWindowsCommandLine;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+namespace {
+
+class Executor {
+public:
+  explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {}
+  void add(StringRef S)    { Args.push_back(Saver.save(S)); }
+  void add(std::string &S) { Args.push_back(Saver.save(S)); }
+  void add(Twine S)        { Args.push_back(Saver.save(S)); }
+  void add(const char *S)  { Args.push_back(Saver.save(S)); }
+
+  void run() {
+    ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog);
+    if (auto EC = ExeOrErr.getError())
+      fatal(EC, "unable to find " + Prog + " in PATH: ");
+    const char *Exe = Saver.save(*ExeOrErr);
+    Args.insert(Args.begin(), Exe);
+    Args.push_back(nullptr);
+    if (llvm::sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
+      for (const char *S : Args)
+        if (S)
+          llvm::errs() << S << " ";
+      fatal("ExecuteAndWait failed");
+    }
+  }
+
+private:
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver;
+  StringRef Prog;
+  std::vector<const char *> Args;
+};
+
+} // anonymous namespace
+
+// Returns /machine's value.
+MachineTypes getMachineType(StringRef S) {
+  MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
+                        .Case("x64", AMD64)
+                        .Case("amd64", AMD64)
+                        .Case("x86", I386)
+                        .Case("i386", I386)
+                        .Case("arm", ARMNT)
+                        .Default(IMAGE_FILE_MACHINE_UNKNOWN);
+  if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
+    return MT;
+  fatal("unknown /machine argument: " + S);
+}
+
+StringRef machineToStr(MachineTypes MT) {
+  switch (MT) {
+  case ARMNT:
+    return "arm";
+  case AMD64:
+    return "x64";
+  case I386:
+    return "x86";
+  default:
+    llvm_unreachable("unknown machine type");
+  }
+}
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
+  StringRef S1, S2;
+  std::tie(S1, S2) = Arg.split(',');
+  if (S1.getAsInteger(0, *Addr))
+    fatal("invalid number: " + S1);
+  if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
+    fatal("invalid number: " + S2);
+}
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// If second number is not present, Minor is set to 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
+  StringRef S1, S2;
+  std::tie(S1, S2) = Arg.split('.');
+  if (S1.getAsInteger(0, *Major))
+    fatal("invalid number: " + S1);
+  *Minor = 0;
+  if (!S2.empty() && S2.getAsInteger(0, *Minor))
+    fatal("invalid number: " + S2);
+}
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+                    uint32_t *Minor) {
+  StringRef SysStr, Ver;
+  std::tie(SysStr, Ver) = Arg.split(',');
+  *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
+    .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+    .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
+    .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+    .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
+    .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+    .Case("native", IMAGE_SUBSYSTEM_NATIVE)
+    .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
+    .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+    .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+  if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
+    fatal("unknown subsystem: " + SysStr);
+  if (!Ver.empty())
+    parseVersion(Ver, Major, Minor);
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseAlternateName(StringRef S) {
+  StringRef From, To;
+  std::tie(From, To) = S.split('=');
+  if (From.empty() || To.empty())
+    fatal("/alternatename: invalid argument: " + S);
+  auto It = Config->AlternateNames.find(From);
+  if (It != Config->AlternateNames.end() && It->second != To)
+    fatal("/alternatename: conflicts: " + S);
+  Config->AlternateNames.insert(It, std::make_pair(From, To));
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseMerge(StringRef S) {
+  StringRef From, To;
+  std::tie(From, To) = S.split('=');
+  if (From.empty() || To.empty())
+    fatal("/merge: invalid argument: " + S);
+  auto Pair = Config->Merge.insert(std::make_pair(From, To));
+  bool Inserted = Pair.second;
+  if (!Inserted) {
+    StringRef Existing = Pair.first->second;
+    if (Existing != To)
+      llvm::errs() << "warning: " << S << ": already merged into "
+                   << Existing << "\n";
+  }
+}
+
+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[,=<integer>]|NO".
+// Results are directly written to Config.
+void parseManifest(StringRef Arg) {
+  if (Arg.equals_lower("no")) {
+    Config->Manifest = Configuration::No;
+    return;
+  }
+  if (!Arg.startswith_lower("embed"))
+    fatal("invalid option " + Arg);
+  Config->Manifest = Configuration::Embed;
+  Arg = Arg.substr(strlen("embed"));
+  if (Arg.empty())
+    return;
+  if (!Arg.startswith_lower(",id="))
+    fatal("invalid option " + Arg);
+  Arg = Arg.substr(strlen(",id="));
+  if (Arg.getAsInteger(0, Config->ManifestID))
+    fatal("invalid option " + Arg);
+}
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
+// Results are directly written to Config.
+void parseManifestUAC(StringRef Arg) {
+  if (Arg.equals_lower("no")) {
+    Config->ManifestUAC = false;
+    return;
+  }
+  for (;;) {
+    Arg = Arg.ltrim();
+    if (Arg.empty())
+      return;
+    if (Arg.startswith_lower("level=")) {
+      Arg = Arg.substr(strlen("level="));
+      std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
+      continue;
+    }
+    if (Arg.startswith_lower("uiaccess=")) {
+      Arg = Arg.substr(strlen("uiaccess="));
+      std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
+      continue;
+    }
+    fatal("invalid option " + Arg);
+  }
+}
+
+// Quote each line with "". Existing double-quote is converted
+// to two double-quotes.
+static void quoteAndPrint(raw_ostream &Out, StringRef S) {
+  while (!S.empty()) {
+    StringRef Line;
+    std::tie(Line, S) = S.split("\n");
+    if (Line.empty())
+      continue;
+    Out << '\"';
+    for (int I = 0, E = Line.size(); I != E; ++I) {
+      if (Line[I] == '\"') {
+        Out << "\"\"";
+      } else {
+        Out << Line[I];
+      }
+    }
+    Out << "\"\n";
+  }
+}
+
+// Create the default manifest file as a temporary file.
+static std::string createDefaultXml() {
+  // Create a temporary file.
+  SmallString<128> Path;
+  if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path))
+    fatal(EC, "cannot create a temporary file");
+
+  // Open the temporary file for writing.
+  std::error_code EC;
+  llvm::raw_fd_ostream OS(Path, EC, sys::fs::F_Text);
+  if (EC)
+    fatal(EC, "failed to open " + 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 << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+     << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+     << "          manifestVersion=\"1.0\">\n";
+  if (Config->ManifestUAC) {
+    OS << "  <trustInfo>\n"
+       << "    <security>\n"
+       << "      <requestedPrivileges>\n"
+       << "         <requestedExecutionLevel level=" << Config->ManifestLevel
+       << " uiAccess=" << Config->ManifestUIAccess << "/>\n"
+       << "      </requestedPrivileges>\n"
+       << "    </security>\n"
+       << "  </trustInfo>\n";
+    if (!Config->ManifestDependency.empty()) {
+      OS << "  <dependency>\n"
+         << "    <dependentAssembly>\n"
+         << "      <assemblyIdentity " << Config->ManifestDependency << " />\n"
+         << "    </dependentAssembly>\n"
+         << "  </dependency>\n";
+    }
+  }
+  OS << "</assembly>\n";
+  OS.close();
+  return StringRef(Path);
+}
+
+static std::string readFile(StringRef Path) {
+  std::unique_ptr<MemoryBuffer> MB =
+      check(MemoryBuffer::getFile(Path), "could not open " + Path);
+  std::unique_ptr<MemoryBuffer> Buf(std::move(MB));
+  return Buf->getBuffer();
+}
+
+static std::string createManifestXml() {
+  // Create the default manifest file.
+  std::string Path1 = createDefaultXml();
+  if (Config->ManifestInput.empty())
+    return readFile(Path1);
+
+  // If manifest files are supplied by the user using /MANIFESTINPUT
+  // option, we need to merge them with the default manifest.
+  SmallString<128> Path2;
+  if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path2))
+    fatal(EC, "cannot create a temporary file");
+  FileRemover Remover1(Path1);
+  FileRemover Remover2(Path2);
+
+  Executor E("mt.exe");
+  E.add("/manifest");
+  E.add(Path1);
+  for (StringRef Filename : Config->ManifestInput) {
+    E.add("/manifest");
+    E.add(Filename);
+  }
+  E.add("/nologo");
+  E.add("/out:" + StringRef(Path2));
+  E.run();
+  return readFile(Path2);
+}
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes() {
+  // Create a temporary file for the resource script file.
+  SmallString<128> RCPath;
+  if (auto EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath))
+    fatal(EC, "cannot create a temporary file");
+  FileRemover RCRemover(RCPath);
+
+  // Open the temporary file for writing.
+  std::error_code EC;
+  llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text);
+  if (EC)
+    fatal(EC, "failed to open " + RCPath);
+
+  // Write resource script to the RC file.
+  Out << "#define LANG_ENGLISH 9\n"
+      << "#define SUBLANG_DEFAULT 1\n"
+      << "#define APP_MANIFEST " << Config->ManifestID << "\n"
+      << "#define RT_MANIFEST 24\n"
+      << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
+      << "APP_MANIFEST RT_MANIFEST {\n";
+  quoteAndPrint(Out, createManifestXml());
+  Out << "}\n";
+  Out.close();
+
+  // Create output resource file.
+  SmallString<128> ResPath;
+  if (auto EC = sys::fs::createTemporaryFile("tmp", "res", ResPath))
+    fatal(EC, "cannot create a temporary file");
+
+  Executor E("rc.exe");
+  E.add("/fo");
+  E.add(ResPath.str());
+  E.add("/nologo");
+  E.add(RCPath.str());
+  E.run();
+  return check(MemoryBuffer::getFile(ResPath), "could not open " + ResPath);
+}
+
+void createSideBySideManifest() {
+  std::string Path = Config->ManifestFile;
+  if (Path == "")
+    Path = Config->OutputFile + ".manifest";
+  std::error_code EC;
+  llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text);
+  if (EC)
+    fatal(EC, "failed to create manifest");
+  Out << createManifestXml();
+}
+
+// Parse a string in the form of
+// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+// or "<name>=<dllname>.<name>".
+// Used for parsing /export arguments.
+Export parseExport(StringRef Arg) {
+  Export E;
+  StringRef Rest;
+  std::tie(E.Name, Rest) = Arg.split(",");
+  if (E.Name.empty())
+    goto err;
+
+  if (E.Name.find('=') != StringRef::npos) {
+    StringRef X, Y;
+    std::tie(X, Y) = E.Name.split("=");
+
+    // If "<name>=<dllname>.<name>".
+    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 "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+  while (!Rest.empty()) {
+    StringRef Tok;
+    std::tie(Tok, Rest) = Rest.split(",");
+    if (Tok.equals_lower("noname")) {
+      if (E.Ordinal == 0)
+        goto err;
+      E.Noname = true;
+      continue;
+    }
+    if (Tok.equals_lower("data")) {
+      E.Data = true;
+      continue;
+    }
+    if (Tok.equals_lower("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<uint16_t> Ords;
+  for (Export &E : Config->Exports) {
+    if (E.Ordinal == 0)
+      continue;
+    if (!Ords.insert(E.Ordinal).second)
+      fatal("duplicate export ordinal: " + E.Name);
+  }
+
+  for (Export &E : Config->Exports) {
+    if (!E.ForwardTo.empty()) {
+      E.SymbolName = E.Name;
+    } else if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) {
+      E.SymbolName = U->getName();
+    } else {
+      E.SymbolName = E.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<StringRef, Export *> Map;
+  std::vector<Export> V;
+  for (Export &E : Config->Exports) {
+    auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
+    bool Inserted = Pair.second;
+    if (Inserted) {
+      V.push_back(E);
+      continue;
+    }
+    Export *Existing = Pair.first->second;
+    if (E == *Existing || E.Name != Existing->Name)
+      continue;
+    llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n";
+  }
+  Config->Exports = std::move(V);
+
+  // Sort by name.
+  std::sort(Config->Exports.begin(), Config->Exports.end(),
+            [](const Export &A, const Export &B) {
+              return A.ExportName < B.ExportName;
+            });
+}
+
+void assignExportOrdinals() {
+  // Assign unique ordinals if default (= 0).
+  uint16_t Max = 0;
+  for (Export &E : Config->Exports)
+    Max = std::max(Max, E.Ordinal);
+  for (Export &E : Config->Exports)
+    if (E.Ordinal == 0)
+      E.Ordinal = ++Max;
+}
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the same key.
+void checkFailIfMismatch(StringRef Arg) {
+  StringRef K, V;
+  std::tie(K, V) = Arg.split('=');
+  if (K.empty() || V.empty())
+    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<MemoryBuffer>
+convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
+  // Create an output file path.
+  SmallString<128> Path;
+  if (auto EC = llvm::sys::fs::createTemporaryFile("resource", "obj", Path))
+    fatal(EC, "could not create temporary file");
+
+  // Execute cvtres.exe.
+  Executor E("cvtres.exe");
+  E.add("/machine:" + machineToStr(Config->Machine));
+  E.add("/readonly");
+  E.add("/nologo");
+  E.add("/out:" + Path);
+  for (MemoryBufferRef MB : MBs)
+    E.add(MB.getBufferIdentifier());
+  E.run();
+  return check(MemoryBuffer::getFile(Path), "could not open " + Path);
+}
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)    \
+  {                                                                    \
+    X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
+    OPT_##GROUP, OPT_##ALIAS, X6                                       \
+  },
+#include "Options.inc"
+#undef OPTION
+};
+
+class COFFOptTable : public llvm::opt::OptTable {
+public:
+  COFFOptTable() : OptTable(infoTable, true) {}
+};
+
+// Parses a given list of options.
+llvm::opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
+  // First, replace respnose files (@<file>-style options).
+  std::vector<const char *> Argv = replaceResponseFiles(ArgsArr);
+
+  // Make InputArgList from string vectors.
+  COFFOptTable Table;
+  unsigned MissingIndex;
+  unsigned MissingCount;
+  llvm::opt::InputArgList Args =
+      Table.ParseArgs(Argv, MissingIndex, MissingCount);
+
+  // Print the real command line if response files are expanded.
+  if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
+    llvm::outs() << "Command line:";
+    for (const char *S : Argv)
+      llvm::outs() << " " << S;
+    llvm::outs() << "\n";
+  }
+
+  if (MissingCount)
+    fatal("missing arg value for \"" + Twine(Args.getArgString(MissingIndex)) +
+          "\", expected " + Twine(MissingCount) +
+          (MissingCount == 1 ? " argument." : " arguments."));
+  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+    llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
+  return Args;
+}
+
+llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) {
+  // Concatenate LINK env and given arguments and parse them.
+  Optional<std::string> Env = Process::GetEnv("LINK");
+  if (!Env)
+    return parse(Args);
+  std::vector<const char *> V = tokenize(*Env);
+  V.insert(V.end(), Args.begin(), Args.end());
+  return parse(V);
+}
+
+std::vector<const char *> ArgParser::tokenize(StringRef S) {
+  SmallVector<const char *, 16> Tokens;
+  StringSaver Saver(AllocAux);
+  llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
+  return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+// Creates a new command line by replacing options starting with '@'
+// character. '@<filename>' is replaced by the file's contents.
+std::vector<const char *>
+ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
+  SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size());
+  StringSaver Saver(AllocAux);
+  ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens);
+  return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+void printHelp(const char *Argv0) {
+  COFFOptTable Table;
+  Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.cpp b/COFF/Error.cpp
new file mode 100644 (file)
index 0000000..602a854
--- /dev/null
@@ -0,0 +1,33 @@
+//===- Error.cpp ----------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace coff {
+
+void fatal(const Twine &Msg) {
+  llvm::errs() << Msg << "\n";
+  exit(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);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.h b/COFF/Error.h
new file mode 100644 (file)
index 0000000..c9f64c6
--- /dev/null
@@ -0,0 +1,38 @@
+//===- 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 {
+
+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 <class T> T check(ErrorOr<T> &&V, const Twine &Prefix) {
+  if (auto EC = V.getError())
+    fatal(EC, Prefix);
+  return std::move(*V);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+  if (llvm::Error Err = E.takeError())
+    fatal(Err, Prefix);
+  return std::move(*E);
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
new file mode 100644 (file)
index 0000000..a2c5a90
--- /dev/null
@@ -0,0 +1,244 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Identical COMDAT Folding is a feature to merge COMDAT sections not by
+// name (which is regular COMDAT handling) but by contents. If two COMDAT
+// sections have the same data, relocations, attributes, etc., then the two
+// are considered identical and merged by the linker. This optimization
+// makes outputs smaller.
+//
+// ICF is theoretically a problem of reducing graphs by merging as many
+// identical subgraphs as possible, if we consider sections as vertices and
+// relocations as edges. This may be a bit more complicated problem than you
+// might think. The order of processing sections matters since merging two
+// sections can make other sections, whose relocations now point to the same
+// section, mergeable. Graphs may contain cycles, which is common in COFF.
+// We need a sophisticated algorithm to do this properly and efficiently.
+//
+// What we do in this file is this. We split sections into groups. Sections
+// in the same group are considered identical.
+//
+// First, all sections are grouped by their "constant" values. Constant
+// values are values that are never changed by ICF, such as section contents,
+// section name, number of relocations, type and offset of each relocation,
+// etc. Because we do not care about some relocation targets in this step,
+// two sections in the same group may not be identical, but at least two
+// sections in different groups can never be identical.
+//
+// Then, we try to split each group by relocation targets. Relocations are
+// considered identical if and only if the relocation targets are in the
+// same group. Splitting a group may make more groups to be splittable,
+// because two relocations that were previously considered identical might
+// now point to different groups. We repeat this step until the convergence
+// is obtained.
+//
+// This algorithm is so-called "optimistic" algorithm described in
+// http://research.google.com/pubs/pub36912.html.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <atomic>
+#include <vector>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+typedef std::vector<SectionChunk *>::iterator ChunkIterator;
+typedef bool (*Comparator)(const SectionChunk *, const SectionChunk *);
+
+class ICF {
+public:
+  void run(const std::vector<Chunk *> &V);
+
+private:
+  static uint64_t getHash(SectionChunk *C);
+  static bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
+  static bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
+  bool forEachGroup(std::vector<SectionChunk *> &Chunks, Comparator Eq);
+  bool segregate(ChunkIterator Begin, ChunkIterator End, Comparator Eq);
+
+  std::atomic<uint64_t> NextID = { 1 };
+};
+
+// Entry point to ICF.
+void doICF(const std::vector<Chunk *> &Chunks) {
+  ICF().run(Chunks);
+}
+
+uint64_t ICF::getHash(SectionChunk *C) {
+  return hash_combine(C->getPermissions(),
+                      hash_value(C->SectionName),
+                      C->NumRelocs,
+                      C->getAlign(),
+                      uint32_t(C->Header->SizeOfRawData),
+                      C->Checksum);
+}
+
+bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
+  if (A->AssocChildren.size() != B->AssocChildren.size() ||
+      A->NumRelocs != B->NumRelocs) {
+    return false;
+  }
+
+  // Compare associative sections.
+  for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I)
+    if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID)
+      return false;
+
+  // Compare relocations.
+  auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+    if (R1.Type != R2.Type ||
+        R1.VirtualAddress != R2.VirtualAddress) {
+      return false;
+    }
+    SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl();
+    SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl();
+    if (B1 == B2)
+      return true;
+    if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+      if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+        return D1->getValue() == D2->getValue() &&
+               D1->getChunk()->GroupID == D2->getChunk()->GroupID;
+    return false;
+  };
+  if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
+    return false;
+
+  // Compare section attributes and contents.
+  return A->getPermissions() == B->getPermissions() &&
+         A->SectionName == B->SectionName &&
+         A->getAlign() == B->getAlign() &&
+         A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
+         A->Checksum == B->Checksum &&
+         A->getContents() == B->getContents();
+}
+
+bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
+  // Compare associative sections.
+  for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I)
+    if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID)
+      return false;
+
+  // Compare relocations.
+  auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+    SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl();
+    SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl();
+    if (B1 == B2)
+      return true;
+    if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+      if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+        return D1->getChunk()->GroupID == D2->getChunk()->GroupID;
+    return false;
+  };
+  return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+}
+
+bool ICF::segregate(ChunkIterator Begin, ChunkIterator End, Comparator Eq) {
+  bool R = false;
+  for (auto It = Begin;;) {
+    SectionChunk *Head = *It;
+    auto Bound = std::partition(It + 1, End, [&](SectionChunk *SC) {
+      return Eq(Head, SC);
+    });
+    if (Bound == End)
+      return R;
+    uint64_t ID = NextID++;
+    std::for_each(It, Bound, [&](SectionChunk *SC) { SC->GroupID = ID; });
+    It = Bound;
+    R = true;
+  }
+}
+
+bool ICF::forEachGroup(std::vector<SectionChunk *> &Chunks, Comparator Eq) {
+  bool R = false;
+  for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) {
+    SectionChunk *Head = *It;
+    auto Bound = std::find_if(It + 1, End, [&](SectionChunk *SC) {
+      return SC->GroupID != Head->GroupID;
+    });
+    if (segregate(It, Bound, Eq))
+      R = true;
+    It = Bound;
+  }
+  return R;
+}
+
+// Merge identical COMDAT sections.
+// Two sections are considered the same if their section headers,
+// contents and relocations are all the same.
+void ICF::run(const std::vector<Chunk *> &Vec) {
+  // Collect only mergeable sections and group by hash value.
+  parallel_for_each(Vec.begin(), Vec.end(), [&](Chunk *C) {
+    if (auto *SC = dyn_cast<SectionChunk>(C)) {
+      bool Global = SC->Sym && SC->Sym->isExternal();
+      bool Writable = SC->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+      if (SC->isCOMDAT() && SC->isLive() && Global && !Writable)
+        SC->GroupID = getHash(SC) | (uint64_t(1) << 63);
+    }
+  });
+  std::vector<SectionChunk *> Chunks;
+  for (Chunk *C : Vec) {
+    if (auto *SC = dyn_cast<SectionChunk>(C)) {
+      if (SC->GroupID) {
+        Chunks.push_back(SC);
+      } else {
+        SC->GroupID = NextID++;
+      }
+    }
+  }
+
+  // From now on, sections in Chunks are ordered so that sections in
+  // the same group are consecutive in the vector.
+  std::sort(Chunks.begin(), Chunks.end(),
+            [](SectionChunk *A, SectionChunk *B) {
+              return A->GroupID < B->GroupID;
+            });
+
+  // Split groups until we get a convergence.
+  int Cnt = 1;
+  forEachGroup(Chunks, equalsConstant);
+
+  for (;;) {
+    if (!forEachGroup(Chunks, equalsVariable))
+      break;
+    ++Cnt;
+  }
+  if (Config->Verbose)
+    llvm::outs() << "\nICF needed " << Cnt << " iterations.\n";
+
+  // Merge sections in the same group.
+  for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) {
+    SectionChunk *Head = *It++;
+    auto Bound = std::find_if(It, End, [&](SectionChunk *SC) {
+      return Head->GroupID != SC->GroupID;
+    });
+    if (It == Bound)
+      continue;
+    if (Config->Verbose)
+      llvm::outs() << "Selected " << Head->getDebugName() << "\n";
+    while (It != Bound) {
+      SectionChunk *SC = *It++;
+      if (Config->Verbose)
+        llvm::outs() << "  Removed " << SC->getDebugName() << "\n";
+      Head->replace(SC);
+    }
+  }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
new file mode 100644 (file)
index 0000000..ff26826
--- /dev/null
@@ -0,0 +1,373 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/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 "llvm-c/lto.h"
+#include <cstring>
+#include <system_error>
+#include <utility>
+
+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 {
+
+int InputFile::NextIndex = 0;
+llvm::LLVMContext BitcodeFile::Context;
+
+// Returns the last element of a path, which is supposed to be a filename.
+static StringRef getBasename(StringRef Path) {
+  size_t Pos = Path.find_last_of("\\/");
+  if (Pos == StringRef::npos)
+    return Path;
+  return Path.substr(Pos + 1);
+}
+
+// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
+std::string InputFile::getShortName() {
+  if (ParentName == "")
+    return getName().lower();
+  std::string Res = (getBasename(ParentName) + "(" +
+                     getBasename(getName()) + ")").str();
+  return StringRef(Res).lower();
+}
+
+void ArchiveFile::parse() {
+  // Parse a MemoryBufferRef as an archive file.
+  File = check(Archive::create(MB), "failed to parse static library");
+
+  // Allocate a buffer for Lazy objects.
+  size_t NumSyms = File->getNumberOfSymbols();
+  LazySymbols.reserve(NumSyms);
+
+  // Read the symbol table to construct Lazy objects.
+  for (const Archive::Symbol &Sym : File->symbols())
+    LazySymbols.emplace_back(this, Sym);
+
+  // Seen is a map from member files to boolean values. Initially
+  // all members are mapped to false, which indicates all these files
+  // are not read yet.
+  Error Err;
+  for (auto &Child : File->children(Err))
+    Seen[Child.getChildOffset()].clear();
+  if (Err)
+    fatal(Err, "failed to parse static library");
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+// This function is thread-safe.
+MemoryBufferRef ArchiveFile::getMember(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[C.getChildOffset()].test_and_set())
+    return MemoryBufferRef();
+  return check(C.getMemoryBufferRef(),
+               "could not get the buffer for the member defining symbol " +
+                   Sym->getName());
+}
+
+void ObjectFile::parse() {
+  // Parse a memory buffer as a COFF file.
+  std::unique_ptr<Binary> Bin =
+      check(createBinary(MB), "failed to parse object file");
+
+  if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
+    Bin.release();
+    COFFObj.reset(Obj);
+  } else {
+    fatal(getName() + " is not a COFF file");
+  }
+
+  // Read section and symbol tables.
+  initializeChunks();
+  initializeSymbols();
+  initializeSEH();
+}
+
+void ObjectFile::initializeChunks() {
+  uint32_t NumSections = COFFObj->getNumberOfSections();
+  Chunks.reserve(NumSections);
+  SparseChunks.resize(NumSections + 1);
+  for (uint32_t I = 1; I < NumSections + 1; ++I) {
+    const coff_section *Sec;
+    StringRef Name;
+    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<uint8_t> Data;
+      COFFObj->getSectionContents(Sec, Data);
+      Directives = std::string((const char *)Data.data(), Data.size());
+      continue;
+    }
+    // Skip non-DWARF debug info. MSVC linker converts the sections into
+    // a PDB file, but we don't support that.
+    if (Name == ".debug" || Name.startswith(".debug$"))
+      continue;
+    // We want to preserve DWARF debug sections only when /debug is on.
+    if (!Config->Debug && Name.startswith(".debug"))
+      continue;
+    if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+      continue;
+    auto *C = new (Alloc) SectionChunk(this, Sec);
+    Chunks.push_back(C);
+    SparseChunks[I] = C;
+  }
+}
+
+void ObjectFile::initializeSymbols() {
+  uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
+  SymbolBodies.reserve(NumSymbols);
+  SparseSymbolBodies.resize(NumSymbols);
+  llvm::SmallVector<std::pair<Undefined *, uint32_t>, 8> WeakAliases;
+  int32_t LastSectionNumber = 0;
+  for (uint32_t I = 0; I < NumSymbols; ++I) {
+    // Get a COFFSymbolRef object.
+    COFFSymbolRef Sym =
+        check(COFFObj->getSymbol(I), "broken object file: " + getName());
+
+    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<const coff_aux_weak_external *>(AuxP)->TagIndex;
+      WeakAliases.emplace_back((Undefined *)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 WeakAlias : WeakAliases)
+    WeakAlias.first->WeakAlias = SparseSymbolBodies[WeakAlias.second];
+}
+
+Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) {
+  StringRef Name;
+  COFFObj->getSymbolName(Sym, Name);
+  return new (Alloc) Undefined(Name);
+}
+
+Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
+                                   bool IsFirst) {
+  StringRef Name;
+  if (Sym.isCommon()) {
+    auto *C = new (Alloc) CommonChunk(Sym);
+    Chunks.push_back(C);
+    return new (Alloc) DefinedCommon(this, Sym, C);
+  }
+  if (Sym.isAbsolute()) {
+    COFFObj->getSymbolName(Sym, Name);
+    // Skip special symbols.
+    if (Name == "@comp.id")
+      return nullptr;
+    // COFF spec 5.10.1. The .sxdata section.
+    if (Name == "@feat.00") {
+      if (Sym.getValue() & 1)
+        SEHCompat = true;
+      return nullptr;
+    }
+    return new (Alloc) DefinedAbsolute(Name, Sym);
+  }
+  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: " + getName());
+
+  // This symbol references a section which is not present in the section
+  // header.
+  if ((uint32_t)SectionNumber >= SparseChunks.size())
+    fatal("broken object file: " + getName());
+
+  // Nothing else to do without a section chunk.
+  auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]);
+  if (!SC)
+    return nullptr;
+
+  // Handle section definitions
+  if (IsFirst && AuxP) {
+    auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
+    if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+      if (auto *ParentSC = cast_or_null<SectionChunk>(
+              SparseChunks[Aux->getNumber(Sym.isBigObj())]))
+        ParentSC->addAssociative(SC);
+    SC->Checksum = Aux->CheckSum;
+  }
+
+  auto *B = new (Alloc) DefinedRegular(this, Sym, SC);
+  if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
+    SC->setSymbol(B);
+
+  return B;
+}
+
+void ObjectFile::initializeSEH() {
+  if (!SEHCompat || !SXData)
+    return;
+  ArrayRef<uint8_t> A;
+  COFFObj->getSectionContents(SXData, A);
+  if (A.size() % 4 != 0)
+    fatal(".sxdata must be an array of symbol table indices");
+  auto *I = reinterpret_cast<const ulittle32_t *>(A.data());
+  auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size());
+  for (; I != E; ++I)
+    SEHandlers.insert(SparseSymbolBodies[*I]);
+}
+
+MachineTypes ObjectFile::getMachineType() {
+  if (COFFObj)
+    return static_cast<MachineTypes>(COFFObj->getMachine());
+  return IMAGE_FILE_MACHINE_UNKNOWN;
+}
+
+StringRef ltrim1(StringRef S, const char *Chars) {
+  if (!S.empty() && strchr(Chars, S[0]))
+    return S.substr(1);
+  return S;
+}
+
+void ImportFile::parse() {
+  const char *Buf = MB.getBufferStart();
+  const char *End = MB.getBufferEnd();
+  const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
+
+  // Check if the total size is valid.
+  if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
+    fatal("broken import library");
+
+  // Read names and create an __imp_ symbol.
+  StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
+  StringRef ImpName = StringAlloc.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;
+  }
+  ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExtName, Hdr);
+  SymbolBodies.push_back(ImpSym);
+
+  // If type is function, we need to create a thunk which jump to an
+  // address pointed by the __imp_ symbol. (This allows you to call
+  // DLL functions just like regular non-DLL functions.)
+  if (Hdr->getType() != llvm::COFF::IMPORT_CODE)
+    return;
+  ThunkSym = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine);
+  SymbolBodies.push_back(ThunkSym);
+}
+
+void BitcodeFile::parse() {
+  // Usually parse() is thread-safe, but bitcode file is an exception.
+  std::lock_guard<std::mutex> Lock(Mu);
+
+  Context.enableDebugTypeODRUniquing();
+  ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
+      Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
+  M = check(std::move(ModOrErr), "could not create LTO module");
+
+  llvm::StringSaver Saver(Alloc);
+  for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
+    lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
+    if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
+      continue;
+
+    StringRef SymName = Saver.save(M->getSymbolName(I));
+    int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
+    if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
+      SymbolBodies.push_back(new (Alloc) Undefined(SymName));
+    } else {
+      bool Replaceable =
+          (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
+           (Attrs & LTO_SYMBOL_COMDAT) ||                  // comdat
+           (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK &&     // weak external
+            (Attrs & LTO_SYMBOL_ALIAS)));
+      SymbolBodies.push_back(new (Alloc) DefinedBitcode(this, SymName,
+                                                        Replaceable));
+    }
+  }
+
+  Directives = M->getLinkerOpts();
+}
+
+MachineTypes BitcodeFile::getMachineType() {
+  if (!M)
+    return IMAGE_FILE_MACHINE_UNKNOWN;
+  switch (Triple(M->getTargetTriple()).getArch()) {
+  case Triple::x86_64:
+    return AMD64;
+  case Triple::x86:
+    return I386;
+  case Triple::arm:
+    return ARMNT;
+  default:
+    return IMAGE_FILE_MACHINE_UNKNOWN;
+  }
+}
+
+std::mutex BitcodeFile::Mu;
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
new file mode 100644 (file)
index 0000000..0ec01b5
--- /dev/null
@@ -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 "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::LTOModule;
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::MachineTypes;
+using llvm::object::Archive;
+using llvm::object::COFFObjectFile;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_section;
+
+class Chunk;
+class Defined;
+class DefinedImportData;
+class DefinedImportThunk;
+class Lazy;
+class SymbolBody;
+class Undefined;
+
+// The root class of input files.
+class InputFile {
+public:
+  enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+  Kind kind() const { return FileKind; }
+  virtual ~InputFile() {}
+
+  // Returns the filename.
+  StringRef getName() { return MB.getBufferIdentifier(); }
+
+  // Returns symbols defined by this file.
+  virtual std::vector<SymbolBody *> &getSymbols() = 0;
+
+  // Reads a file (the constructor doesn't do that).
+  virtual void parse() = 0;
+
+  // Returns the CPU type this file was compiled to.
+  virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
+
+  // Returns a short, human-friendly filename. If this is a member of
+  // an archive file, a returned value includes parent's filename.
+  // Used for logging or debugging.
+  std::string getShortName();
+
+  // Sets a parent filename if this file is created from an archive.
+  void setParentName(StringRef N) { ParentName = N; }
+
+  // Returns .drectve section contents if exist.
+  StringRef getDirectives() { return StringRef(Directives).trim(); }
+
+  // Each file has a unique index. The index number is used to
+  // resolve ties in symbol resolution.
+  int Index;
+  static int NextIndex;
+
+protected:
+  InputFile(Kind K, MemoryBufferRef M)
+      : Index(NextIndex++), MB(M), FileKind(K) {}
+
+  MemoryBufferRef MB;
+  std::string Directives;
+
+private:
+  const Kind FileKind;
+  StringRef ParentName;
+};
+
+// .lib or .a file.
+class ArchiveFile : public InputFile {
+public:
+  explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+  void parse() override;
+
+  // Returns a memory buffer for a given symbol. An empty memory buffer
+  // is returned if we have already returned the same memory buffer.
+  // (So that we don't instantiate same members more than once.)
+  MemoryBufferRef getMember(const Archive::Symbol *Sym);
+
+  llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
+
+  // All symbols returned by ArchiveFiles are of Lazy type.
+  std::vector<SymbolBody *> &getSymbols() override {
+    llvm_unreachable("internal fatal");
+  }
+
+private:
+  std::unique_ptr<Archive> File;
+  std::string Filename;
+  std::vector<Lazy> LazySymbols;
+  std::map<uint64_t, std::atomic_flag> 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<Chunk *> &getChunks() { return Chunks; }
+  std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
+
+  // Returns a SymbolBody object for the SymbolIndex'th symbol in the
+  // underlying object file.
+  SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
+    return SparseSymbolBodies[SymbolIndex];
+  }
+
+  // Returns the underying COFF file.
+  COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+
+  // True if this object file is compatible with SEH.
+  // COFF-specific and x86-only.
+  bool SEHCompat = false;
+
+  // The list of safe exception handlers listed in .sxdata section.
+  // COFF-specific and x86-only.
+  std::set<SymbolBody *> SEHandlers;
+
+private:
+  void initializeChunks();
+  void initializeSymbols();
+  void initializeSEH();
+
+  Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst);
+  Undefined *createUndefined(COFFSymbolRef Sym);
+
+  std::unique_ptr<COFFObjectFile> COFFObj;
+  llvm::BumpPtrAllocator Alloc;
+  const coff_section *SXData = nullptr;
+
+  // List of all chunks defined by this file. This includes both section
+  // chunks and non-section chunks for common symbols.
+  std::vector<Chunk *> Chunks;
+
+  // This vector contains the same chunks as Chunks, but they are
+  // indexed such that you can get a SectionChunk by section index.
+  // Nonexistent section indices are filled with null pointers.
+  // (Because section number is 1-based, the first slot is always a
+  // null pointer.)
+  std::vector<Chunk *> SparseChunks;
+
+  // List of all symbols referenced or defined by this file.
+  std::vector<SymbolBody *> 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<SymbolBody *> SparseSymbolBodies;
+};
+
+// This type represents import library members that contain DLL names
+// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7
+// for details about the format.
+class ImportFile : public InputFile {
+public:
+  explicit ImportFile(MemoryBufferRef M)
+      : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {}
+  static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
+  std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
+
+  DefinedImportData *ImpSym = nullptr;
+  DefinedImportThunk *ThunkSym = nullptr;
+  std::string DLLName;
+
+private:
+  void parse() override;
+
+  std::vector<SymbolBody *> SymbolBodies;
+  llvm::BumpPtrAllocator Alloc;
+  llvm::BumpPtrAllocator StringAllocAux;
+  llvm::StringSaver StringAlloc;
+};
+
+// Used for LTO.
+class BitcodeFile : public InputFile {
+public:
+  explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+  std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
+  MachineTypes getMachineType() override;
+  std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
+
+  static llvm::LLVMContext Context;
+
+private:
+  void parse() override;
+
+  std::vector<SymbolBody *> SymbolBodies;
+  llvm::BumpPtrAllocator Alloc;
+  std::unique_ptr<LTOModule> M;
+  static std::mutex Mu;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp
new file mode 100644 (file)
index 0000000..25fb4a8
--- /dev/null
@@ -0,0 +1,489 @@
+//===- Librarian.cpp ------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains functions for the Librarian.  The librarian creates and
+// manages libraries of the Common Object File Format (COFF) object files.  It
+// primarily is used for creating static libraries and import libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Path.h"
+
+#include <vector>
+
+using namespace lld::coff;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm;
+
+static bool is32bit() {
+  switch (Config->Machine) {
+  default:
+    llvm_unreachable("unsupported machine");
+  case IMAGE_FILE_MACHINE_AMD64:
+    return false;
+  case IMAGE_FILE_MACHINE_ARMNT:
+  case IMAGE_FILE_MACHINE_I386:
+    return true;
+  }
+}
+
+static uint16_t getImgRelRelocation() {
+  switch (Config->Machine) {
+  default:
+    llvm_unreachable("unsupported machine");
+  case IMAGE_FILE_MACHINE_AMD64:
+    return IMAGE_REL_AMD64_ADDR32NB;
+  case IMAGE_FILE_MACHINE_ARMNT:
+    return IMAGE_REL_ARM_ADDR32NB;
+  case IMAGE_FILE_MACHINE_I386:
+    return IMAGE_REL_I386_DIR32NB;
+  }
+}
+
+template <class T> void append(std::vector<uint8_t> &B, const T &Data) {
+  size_t S = B.size();
+  B.resize(S + sizeof(T));
+  memcpy(&B[S], &Data, sizeof(T));
+}
+
+static void writeStringTable(std::vector<uint8_t> &B,
+                             ArrayRef<const std::string> Strings) {
+  // The COFF string table consists of a 4-byte value which is the size of the
+  // table, including the length field itself.  This value is followed by the
+  // string content itself, which is an array of null-terminated C-style
+  // strings.  The termination is important as they are referenced to by offset
+  // by the symbol entity in the file format.
+
+  std::vector<uint8_t>::size_type Pos = B.size();
+  std::vector<uint8_t>::size_type Offset = B.size();
+
+  // Skip over the length field, we will fill it in later as we will have
+  // computed the length while emitting the string content itself.
+  Pos += sizeof(uint32_t);
+
+  for (const auto &S : Strings) {
+    B.resize(Pos + S.length() + 1);
+    strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
+    Pos += S.length() + 1;
+  }
+
+  // Backfill the length of the table now that it has been computed.
+  support::ulittle32_t Length(B.size() - Offset);
+  memcpy(&B[Offset], &Length, sizeof(Length));
+}
+
+static std::string getImplibPath() {
+  if (!Config->Implib.empty())
+    return Config->Implib;
+  SmallString<128> Out = StringRef(Config->OutputFile);
+  sys::path::replace_extension(Out, ".lib");
+  return Out.str();
+}
+
+static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
+  if (Sym != ExtName)
+    return IMPORT_NAME_UNDECORATE;
+  if (Config->Machine == I386 && Sym.startswith("_"))
+    return IMPORT_NAME_NOPREFIX;
+  return IMPORT_NAME;
+}
+
+static std::string replace(StringRef S, StringRef From, StringRef To) {
+  size_t Pos = S.find(From);
+  assert(Pos != StringRef::npos);
+  return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
+}
+
+static const std::string NullImportDescriptorSymbolName =
+    "__NULL_IMPORT_DESCRIPTOR";
+
+namespace {
+// This class constructs various small object files necessary to support linking
+// symbols imported from a DLL.  The contents are pretty strictly defined and
+// nearly entirely static.  The details of the structures files are defined in
+// WINNT.h and the PE/COFF specification.
+class ObjectFactory {
+  using u16 = support::ulittle16_t;
+  using u32 = support::ulittle32_t;
+
+  BumpPtrAllocator Alloc;
+  StringRef DLLName;
+  StringRef Library;
+  std::string ImportDescriptorSymbolName;
+  std::string NullThunkSymbolName;
+
+public:
+  ObjectFactory(StringRef S)
+      : DLLName(S), Library(S.drop_back(4)),
+        ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
+        NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
+
+  // Creates an Import Descriptor.  This is a small object file which contains a
+  // reference to the terminators and contains the library name (entry) for the
+  // import name table.  It will force the linker to construct the necessary
+  // structure to import symbols from the DLL.
+  NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
+
+  // Creates a NULL import descriptor.  This is a small object file whcih
+  // contains a NULL import descriptor.  It is used to terminate the imports
+  // from a specific DLL.
+  NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
+
+  // Create a NULL Thunk Entry.  This is a small object file which contains a
+  // NULL Import Address Table entry and a NULL Import Lookup Table Entry.  It
+  // is used to terminate the IAT and ILT.
+  NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
+
+  // Create a short import file which is described in PE/COFF spec 7. Import
+  // Library Format.
+  NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
+                                     ImportNameType NameType, bool isData);
+};
+}
+
+NewArchiveMember
+ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
+  static const uint32_t NumberOfSections = 2;
+  static const uint32_t NumberOfSymbols = 7;
+  static const uint32_t NumberOfRelocations = 3;
+
+  // COFF Header
+  coff_file_header Header{
+      u16(Config->Machine), u16(NumberOfSections), u32(0),
+      u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+          // .idata$2
+          sizeof(coff_import_directory_table_entry) +
+          NumberOfRelocations * sizeof(coff_relocation) +
+          // .idata$4
+          (DLLName.size() + 1)),
+      u32(NumberOfSymbols), u16(0),
+      u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+  };
+  append(Buffer, Header);
+
+  // Section Header Table
+  static const coff_section SectionTable[NumberOfSections] = {
+      {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
+       u32(0),
+       u32(0),
+       u32(sizeof(coff_import_directory_table_entry)),
+       u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+       u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+           sizeof(coff_import_directory_table_entry)),
+       u32(0),
+       u16(NumberOfRelocations),
+       u16(0),
+       u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+           IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+      {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
+       u32(0),
+       u32(0),
+       u32(DLLName.size() + 1),
+       u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+           sizeof(coff_import_directory_table_entry) +
+           NumberOfRelocations * sizeof(coff_relocation)),
+       u32(0),
+       u32(0),
+       u16(0),
+       u16(0),
+       u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+           IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+  };
+  append(Buffer, SectionTable);
+
+  // .idata$2
+  static const coff_import_directory_table_entry ImportDescriptor{
+      u32(0), u32(0), u32(0), u32(0), u32(0),
+  };
+  append(Buffer, ImportDescriptor);
+
+  static const coff_relocation RelocationTable[NumberOfRelocations] = {
+      {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
+       u16(getImgRelRelocation())},
+      {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
+       u32(3), u16(getImgRelRelocation())},
+      {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
+       u32(4), u16(getImgRelRelocation())},
+  };
+  append(Buffer, RelocationTable);
+
+  // .idata$6
+  auto S = Buffer.size();
+  Buffer.resize(S + DLLName.size() + 1);
+  memcpy(&Buffer[S], DLLName.data(), DLLName.size());
+  Buffer[S + DLLName.size()] = '\0';
+
+  // Symbol Table
+  coff_symbol16 SymbolTable[NumberOfSymbols] = {
+      {{{0, 0, 0, 0, 0, 0, 0, 0}},
+       u32(0),
+       u16(1),
+       u16(0),
+       IMAGE_SYM_CLASS_EXTERNAL,
+       0},
+      {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
+       u32(0),
+       u16(1),
+       u16(0),
+       IMAGE_SYM_CLASS_SECTION,
+       0},
+      {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
+       u32(0),
+       u16(2),
+       u16(0),
+       IMAGE_SYM_CLASS_STATIC,
+       0},
+      {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
+       u32(0),
+       u16(0),
+       u16(0),
+       IMAGE_SYM_CLASS_SECTION,
+       0},
+      {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
+       u32(0),
+       u16(0),
+       u16(0),
+       IMAGE_SYM_CLASS_SECTION,
+       0},
+      {{{0, 0, 0, 0, 0, 0, 0, 0}},
+       u32(0),
+       u16(0),
+       u16(0),
+       IMAGE_SYM_CLASS_EXTERNAL,
+       0},
+      {{{0, 0, 0, 0, 0, 0, 0, 0}},
+       u32(0),
+       u16(0),
+       u16(0),
+       IMAGE_SYM_CLASS_EXTERNAL,
+       0},
+  };
+  reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
+      sizeof(uint32_t);
+  reinterpret_cast<StringTableOffset &>(SymbolTable[5].Name).Offset =
+      sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
+  reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset =
+      sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
+      NullImportDescriptorSymbolName.length() + 1;
+  append(Buffer, SymbolTable);
+
+  // String Table
+  writeStringTable(Buffer,
+                   {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
+                    NullThunkSymbolName});
+
+  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+  return {MemoryBufferRef(F, DLLName)};
+}
+
+NewArchiveMember
+ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
+  static const uint32_t NumberOfSections = 1;
+  static const uint32_t NumberOfSymbols = 1;
+
+  // COFF Header
+  coff_file_header Header{
+      u16(Config->Machine), u16(NumberOfSections), u32(0),
+      u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+          // .idata$3
+          sizeof(coff_import_directory_table_entry)),
+      u32(NumberOfSymbols), u16(0),
+      u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+  };
+  append(Buffer, Header);
+
+  // Section Header Table
+  static const coff_section SectionTable[NumberOfSections] = {
+      {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
+       u32(0),
+       u32(0),
+       u32(sizeof(coff_import_directory_table_entry)),
+       u32(sizeof(coff_file_header) +
+           (NumberOfSections * sizeof(coff_section))),
+       u32(0),
+       u32(0),
+       u16(0),
+       u16(0),
+       u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+           IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+  };
+  append(Buffer, SectionTable);
+
+  // .idata$3
+  static const coff_import_directory_table_entry ImportDescriptor{
+      u32(0), u32(0), u32(0), u32(0), u32(0),
+  };
+  append(Buffer, ImportDescriptor);
+
+  // Symbol Table
+  coff_symbol16 SymbolTable[NumberOfSymbols] = {
+      {{{0, 0, 0, 0, 0, 0, 0, 0}},
+       u32(0),
+       u16(1),
+       u16(0),
+       IMAGE_SYM_CLASS_EXTERNAL,
+       0},
+  };
+  reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
+      sizeof(uint32_t);
+  append(Buffer, SymbolTable);
+
+  // String Table
+  writeStringTable(Buffer, {NullImportDescriptorSymbolName});
+
+  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+  return {MemoryBufferRef(F, DLLName)};
+}
+
+NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
+  static const uint32_t NumberOfSections = 2;
+  static const uint32_t NumberOfSymbols = 1;
+
+  // COFF Header
+  coff_file_header Header{
+      u16(Config->Machine), u16(NumberOfSections), u32(0),
+      u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+          // .idata$5
+          sizeof(export_address_table_entry) +
+          // .idata$4
+          sizeof(export_address_table_entry)),
+      u32(NumberOfSymbols), u16(0),
+      u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+  };
+  append(Buffer, Header);
+
+  // Section Header Table
+  static const coff_section SectionTable[NumberOfSections] = {
+      {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
+       u32(0),
+       u32(0),
+       u32(sizeof(export_address_table_entry)),
+       u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+       u32(0),
+       u32(0),
+       u16(0),
+       u16(0),
+       u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+           IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+      {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
+       u32(0),
+       u32(0),
+       u32(sizeof(export_address_table_entry)),
+       u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+           sizeof(export_address_table_entry)),
+       u32(0),
+       u32(0),
+       u16(0),
+       u16(0),
+       u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+           IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+  };
+  append(Buffer, SectionTable);
+
+  // .idata$5
+  static const export_address_table_entry ILT{u32(0)};
+  append(Buffer, ILT);
+
+  // .idata$4
+  static const export_address_table_entry IAT{u32(0)};
+  append(Buffer, IAT);
+
+  // Symbol Table
+  coff_symbol16 SymbolTable[NumberOfSymbols] = {
+      {{{0, 0, 0, 0, 0, 0, 0, 0}},
+       u32(0),
+       u16(1),
+       u16(0),
+       IMAGE_SYM_CLASS_EXTERNAL,
+       0},
+  };
+  reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
+      sizeof(uint32_t);
+  append(Buffer, SymbolTable);
+
+  // String Table
+  writeStringTable(Buffer, {NullThunkSymbolName});
+
+  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+  return {MemoryBufferRef{F, DLLName}};
+}
+
+NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
+                                                  uint16_t Ordinal,
+                                                  ImportNameType NameType,
+                                                  bool isData) {
+  size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
+  size_t Size = sizeof(coff_import_header) + ImpSize;
+  char *Buf = Alloc.Allocate<char>(Size);
+  memset(Buf, 0, Size);
+  char *P = Buf;
+
+  // Write short import library.
+  auto *Imp = reinterpret_cast<coff_import_header *>(P);
+  P += sizeof(*Imp);
+  Imp->Sig2 = 0xFFFF;
+  Imp->Machine = Config->Machine;
+  Imp->SizeOfData = ImpSize;
+  if (Ordinal > 0)
+    Imp->OrdinalHint = Ordinal;
+  Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE);
+  Imp->TypeInfo |= NameType << 2;
+
+  // Write symbol name and DLL name.
+  memcpy(P, Sym.data(), Sym.size());
+  P += Sym.size() + 1;
+  memcpy(P, DLLName.data(), DLLName.size());
+
+  return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
+}
+
+// Creates an import library for a DLL. In this function, we first
+// create an empty import library using lib.exe and then adds short
+// import files to that file.
+void lld::coff::writeImportLibrary() {
+  std::vector<NewArchiveMember> Members;
+
+  std::string Path = getImplibPath();
+  std::string DLLName = llvm::sys::path::filename(Config->OutputFile);
+  ObjectFactory OF(DLLName);
+
+  std::vector<uint8_t> ImportDescriptor;
+  Members.push_back(OF.createImportDescriptor(ImportDescriptor));
+
+  std::vector<uint8_t> NullImportDescriptor;
+  Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
+
+  std::vector<uint8_t> NullThunk;
+  Members.push_back(OF.createNullThunk(NullThunk));
+
+  for (Export &E : Config->Exports) {
+    if (E.Private)
+      continue;
+
+    ImportNameType Type = getNameType(E.SymbolName, E.Name);
+    std::string Name = E.ExtName.empty()
+                           ? std::string(E.SymbolName)
+                           : replace(E.SymbolName, E.Name, E.ExtName);
+    Members.push_back(OF.createShortImport(Name, E.Ordinal, Type, E.Data));
+  }
+
+  std::pair<StringRef, std::error_code> Result =
+      writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
+                   /*Deterministic*/ true, /*Thin*/ false);
+  if (auto EC = Result.second)
+    fatal(EC, "failed to write " + Path);
+}
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
new file mode 100644 (file)
index 0000000..0870986
--- /dev/null
@@ -0,0 +1,61 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include <vector>
+
+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<Chunk *> &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<SectionChunk *, 256> Worklist;
+
+  // COMDAT section chunks are dead by default. Add non-COMDAT chunks.
+  for (Chunk *C : Chunks)
+    if (auto *SC = dyn_cast<SectionChunk>(C))
+      if (SC->isLive())
+        Worklist.push_back(SC);
+
+  auto Enqueue = [&](SectionChunk *C) {
+    if (C->isLive())
+      return;
+    C->markLive();
+    Worklist.push_back(C);
+  };
+
+  // Add GC root chunks.
+  for (Undefined *U : Config->GCRoot)
+    if (auto *D = dyn_cast<DefinedRegular>(U->repl()))
+      Enqueue(D->getChunk());
+
+  while (!Worklist.empty()) {
+    SectionChunk *SC = Worklist.pop_back_val();
+    assert(SC->isLive() && "We mark as live when pushing onto the worklist!");
+
+    // Mark all symbols listed in the relocation table for this section.
+    for (SymbolBody *S : SC->symbols())
+      if (auto *D = dyn_cast<DefinedRegular>(S->repl()))
+        Enqueue(D->getChunk());
+
+    // Mark associative sections if any.
+    for (SectionChunk *C : SC->children())
+      Enqueue(C);
+  }
+}
+
+}
+}
diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp
new file mode 100644 (file)
index 0000000..5e393f4
--- /dev/null
@@ -0,0 +1,291 @@
+//===- COFF/ModuleDef.cpp -------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific.
+// A parser for the module-definition file (.def file).
+// Parsed results are directly written to Config global variable.
+//
+// The format of module-definition files are described in this document:
+// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+namespace {
+
+enum Kind {
+  Unknown,
+  Eof,
+  Identifier,
+  Comma,
+  Equal,
+  KwBase,
+  KwData,
+  KwExports,
+  KwHeapsize,
+  KwLibrary,
+  KwName,
+  KwNoname,
+  KwPrivate,
+  KwStacksize,
+  KwVersion,
+};
+
+struct Token {
+  explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
+  Kind K;
+  StringRef Value;
+};
+
+static bool isDecorated(StringRef Sym) {
+  return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
+class Lexer {
+public:
+  explicit Lexer(StringRef S) : Buf(S) {}
+
+  Token lex() {
+    Buf = Buf.trim();
+    if (Buf.empty())
+      return Token(Eof);
+
+    switch (Buf[0]) {
+    case '\0':
+      return Token(Eof);
+    case ';': {
+      size_t End = Buf.find('\n');
+      Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+      return lex();
+    }
+    case '=':
+      Buf = Buf.drop_front();
+      return Token(Equal, "=");
+    case ',':
+      Buf = Buf.drop_front();
+      return Token(Comma, ",");
+    case '"': {
+      StringRef S;
+      std::tie(S, Buf) = Buf.substr(1).split('"');
+      return Token(Identifier, S);
+    }
+    default: {
+      size_t End = Buf.find_first_of("=,\r\n \t\v");
+      StringRef Word = Buf.substr(0, End);
+      Kind K = llvm::StringSwitch<Kind>(Word)
+                   .Case("BASE", KwBase)
+                   .Case("DATA", KwData)
+                   .Case("EXPORTS", KwExports)
+                   .Case("HEAPSIZE", KwHeapsize)
+                   .Case("LIBRARY", KwLibrary)
+                   .Case("NAME", KwName)
+                   .Case("NONAME", KwNoname)
+                   .Case("PRIVATE", KwPrivate)
+                   .Case("STACKSIZE", KwStacksize)
+                   .Case("VERSION", KwVersion)
+                   .Default(Identifier);
+      Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+      return Token(K, Word);
+    }
+    }
+  }
+
+private:
+  StringRef Buf;
+};
+
+class Parser {
+public:
+  explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {}
+
+  void parse() {
+    do {
+      parseOne();
+    } while (Tok.K != Eof);
+  }
+
+private:
+  void read() {
+    if (Stack.empty()) {
+      Tok = Lex.lex();
+      return;
+    }
+    Tok = Stack.back();
+    Stack.pop_back();
+  }
+
+  void readAsInt(uint64_t *I) {
+    read();
+    if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
+      fatal("integer expected");
+  }
+
+  void expect(Kind Expected, StringRef Msg) {
+    read();
+    if (Tok.K != Expected)
+      fatal(Msg);
+  }
+
+  void unget() { Stack.push_back(Tok); }
+
+  void parseOne() {
+    read();
+    switch (Tok.K) {
+    case Eof:
+      return;
+    case KwExports:
+      for (;;) {
+        read();
+        if (Tok.K != Identifier) {
+          unget();
+          return;
+        }
+        parseExport();
+      }
+    case KwHeapsize:
+      parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
+      return;
+    case KwLibrary:
+      parseName(&Config->OutputFile, &Config->ImageBase);
+      if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
+        Config->OutputFile += ".dll";
+      return;
+    case KwStacksize:
+      parseNumbers(&Config->StackReserve, &Config->StackCommit);
+      return;
+    case KwName:
+      parseName(&Config->OutputFile, &Config->ImageBase);
+      return;
+    case KwVersion:
+      parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
+      return;
+    default:
+      fatal("unknown directive: " + Tok.Value);
+    }
+  }
+
+  void parseExport() {
+    Export E;
+    E.Name = Tok.Value;
+    read();
+    if (Tok.K == Equal) {
+      read();
+      if (Tok.K != Identifier)
+        fatal("identifier expected, but got " + Tok.Value);
+      E.ExtName = E.Name;
+      E.Name = Tok.Value;
+    } else {
+      unget();
+    }
+
+    if (Config->Machine == I386) {
+      if (!isDecorated(E.Name))
+        E.Name = Alloc->save("_" + E.Name);
+      if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+        E.ExtName = Alloc->save("_" + E.ExtName);
+    }
+
+    for (;;) {
+      read();
+      if (Tok.K == Identifier && Tok.Value[0] == '@') {
+        Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
+        read();
+        if (Tok.K == KwNoname) {
+          E.Noname = true;
+        } else {
+          unget();
+        }
+        continue;
+      }
+      if (Tok.K == KwData) {
+        E.Data = true;
+        continue;
+      }
+      if (Tok.K == KwPrivate) {
+        E.Private = true;
+        continue;
+      }
+      unget();
+      Config->Exports.push_back(E);
+      return;
+    }
+  }
+
+  // HEAPSIZE/STACKSIZE reserve[,commit]
+  void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
+    readAsInt(Reserve);
+    read();
+    if (Tok.K != Comma) {
+      unget();
+      Commit = nullptr;
+      return;
+    }
+    readAsInt(Commit);
+  }
+
+  // NAME outputPath [BASE=address]
+  void parseName(std::string *Out, uint64_t *Baseaddr) {
+    read();
+    if (Tok.K == Identifier) {
+      *Out = Tok.Value;
+    } else {
+      *Out = "";
+      unget();
+      return;
+    }
+    read();
+    if (Tok.K == KwBase) {
+      expect(Equal, "'=' expected");
+      readAsInt(Baseaddr);
+    } else {
+      unget();
+      *Baseaddr = 0;
+    }
+  }
+
+  // VERSION major[.minor]
+  void parseVersion(uint32_t *Major, uint32_t *Minor) {
+    read();
+    if (Tok.K != Identifier)
+      fatal("identifier expected, but got " + Tok.Value);
+    StringRef V1, V2;
+    std::tie(V1, V2) = Tok.Value.split('.');
+    if (V1.getAsInteger(10, *Major))
+      fatal("integer expected, but got " + Tok.Value);
+    if (V2.empty())
+      *Minor = 0;
+    else if (V2.getAsInteger(10, *Minor))
+      fatal("integer expected, but got " + Tok.Value);
+  }
+
+  Lexer Lex;
+  Token Tok;
+  std::vector<Token> Stack;
+  StringSaver *Alloc;
+};
+
+} // anonymous namespace
+
+void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) {
+  Parser(MB.getBuffer(), Alloc).parse();
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Options.td b/COFF/Options.td
new file mode 100644 (file)
index 0000000..e5c9c5b
--- /dev/null
@@ -0,0 +1,127 @@
+include "llvm/Option/OptParser.td"
+
+// link.exe accepts options starting with either a dash or a slash.
+
+// Flag that takes no arguments.
+class F<string name> : Flag<["/", "-", "-?"], name>;
+
+// Flag that takes one argument after ":".
+class P<string name, string help> :
+      Joined<["/", "-", "-?"], name#":">, HelpText<help>;
+
+// Boolean flag suffixed by ":no".
+multiclass B<string name, string help> {
+  def "" : F<name>;
+  def _no : F<name#":no">, HelpText<help>;
+}
+
+def 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 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 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<nodefaultlib>;
+
+def manifest : F<"manifest">;
+def manifest_colon : P<"manifest", "Create manifest file">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest file path">;
+def manifestdependency : P<"manifestdependency",
+                           "Attributes for <dependency> in manifest file">;
+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 dll : F<"dll">, HelpText<"Create a DLL">;
+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 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<help>;
+
+// LLD extensions
+def nosymtab : F<"nosymtab">;
+
+// Flags for debugging
+def lldmap : Joined<["/", "-"], "lldmap:">;
+
+//==============================================================================
+// The flags below do nothing. They are defined only for link.exe compatibility.
+//==============================================================================
+
+class QF<string name> : Joined<["/", "-", "-?"], name#":">;
+
+multiclass QB<string name> {
+  def "" : F<name>;
+  def _no : F<name#":no">;
+}
+
+def functionpadmin : F<"functionpadmin">;
+def ignoreidl : F<"ignoreidl">;
+def incremental : F<"incremental">;
+def no_incremental : F<"incremental:no">;
+def nologo : F<"nologo">;
+def 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 (file)
index 0000000..7606ccc
--- /dev/null
@@ -0,0 +1,61 @@
+//===- PDB.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+const int PageSize = 4096;
+const uint8_t Magic[32] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";
+
+namespace {
+struct PDBHeader {
+  uint8_t Magic[32];
+  ulittle32_t PageSize;
+  ulittle32_t FpmPage;
+  ulittle32_t PageCount;
+  ulittle32_t RootSize;
+  ulittle32_t Reserved;
+  ulittle32_t RootPointer;
+};
+}
+
+void lld::coff::createPDB(StringRef Path) {
+  // Create a file.
+  size_t FileSize = PageSize * 3;
+  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(Path, FileSize);
+  if (auto EC = BufferOrErr.getError())
+    fatal(EC, "failed to open " + Path);
+  std::unique_ptr<FileOutputBuffer> Buffer = std::move(*BufferOrErr);
+
+  // Write the file header.
+  uint8_t *Buf = Buffer->getBufferStart();
+  auto *Hdr = reinterpret_cast<PDBHeader *>(Buf);
+  memcpy(Hdr->Magic, Magic, sizeof(Magic));
+  Hdr->PageSize = PageSize;
+  // I don't know what FpmPage field means, but it must not be 0.
+  Hdr->FpmPage = 1;
+  Hdr->PageCount = FileSize / PageSize;
+  // Root directory is empty, containing only the length field.
+  Hdr->RootSize = 4;
+  // Root directory is on page 1.
+  Hdr->RootPointer = 1;
+
+  // Write the root directory. Root stream is on page 2.
+  write32le(Buf + PageSize, 2);
+  Buffer->commit();
+}
diff --git a/COFF/README.md b/COFF/README.md
new file mode 100644 (file)
index 0000000..f1bfc9c
--- /dev/null
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..df9da4c
--- /dev/null
@@ -0,0 +1,448 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/legacy/LTOCodeGenerator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+void SymbolTable::addFile(std::unique_ptr<InputFile> FileP) {
+#if LLVM_ENABLE_THREADS
+  std::launch Policy = std::launch::async;
+#else
+  std::launch Policy = std::launch::deferred;
+#endif
+
+  InputFile *File = FileP.get();
+  Files.push_back(std::move(FileP));
+  if (auto *F = dyn_cast<ArchiveFile>(File)) {
+    ArchiveQueue.push_back(
+        std::async(Policy, [=]() { F->parse(); return F; }));
+    return;
+  }
+  ObjectQueue.push_back(
+      std::async(Policy, [=]() { File->parse(); return File; }));
+  if (auto *F = dyn_cast<ObjectFile>(File)) {
+    ObjectFiles.push_back(F);
+  } else if (auto *F = dyn_cast<BitcodeFile>(File)) {
+    BitcodeFiles.push_back(F);
+  } else {
+    ImportFiles.push_back(cast<ImportFile>(File));
+  }
+}
+
+void SymbolTable::step() {
+  if (queueEmpty())
+    return;
+  readObjects();
+  readArchives();
+}
+
+void SymbolTable::run() {
+  while (!queueEmpty())
+    step();
+}
+
+void SymbolTable::readArchives() {
+  if (ArchiveQueue.empty())
+    return;
+
+  // Add lazy symbols to the symbol table. Lazy symbols that conflict
+  // with existing undefined symbols are accumulated in LazySyms.
+  std::vector<Symbol *> LazySyms;
+  for (std::future<ArchiveFile *> &Future : ArchiveQueue) {
+    ArchiveFile *File = Future.get();
+    if (Config->Verbose)
+      llvm::outs() << "Reading " << File->getShortName() << "\n";
+    for (Lazy &Sym : File->getLazySymbols())
+      addLazy(&Sym, &LazySyms);
+  }
+  ArchiveQueue.clear();
+
+  // Add archive member files to ObjectQueue that should resolve
+  // existing undefined symbols.
+  for (Symbol *Sym : LazySyms)
+    addMemberFile(cast<Lazy>(Sym->Body));
+}
+
+void SymbolTable::readObjects() {
+  if (ObjectQueue.empty())
+    return;
+
+  // Add defined and undefined symbols to the symbol table.
+  std::vector<StringRef> Directives;
+  for (size_t I = 0; I < ObjectQueue.size(); ++I) {
+    InputFile *File = ObjectQueue[I].get();
+    if (Config->Verbose)
+      llvm::outs() << "Reading " << File->getShortName() << "\n";
+    // Adding symbols may add more files to ObjectQueue
+    // (but not to ArchiveQueue).
+    for (SymbolBody *Sym : File->getSymbols())
+      if (Sym->isExternal())
+        addSymbol(Sym);
+    StringRef S = File->getDirectives();
+    if (!S.empty()) {
+      Directives.push_back(S);
+      if (Config->Verbose)
+        llvm::outs() << "Directives: " << File->getShortName()
+                     << ": " << S << "\n";
+    }
+  }
+  ObjectQueue.clear();
+
+  // Parse directive sections. This may add files to
+  // ArchiveQueue and ObjectQueue.
+  for (StringRef S : Directives)
+    Driver->parseDirectives(S);
+}
+
+bool SymbolTable::queueEmpty() {
+  return ArchiveQueue.empty() && ObjectQueue.empty();
+}
+
+void SymbolTable::reportRemainingUndefines(bool Resolve) {
+  llvm::SmallPtrSet<SymbolBody *, 8> Undefs;
+  for (auto &I : Symtab) {
+    Symbol *Sym = I.second;
+    auto *Undef = dyn_cast<Undefined>(Sym->Body);
+    if (!Undef)
+      continue;
+    StringRef Name = Undef->getName();
+    // A weak alias may have been resolved, so check for that.
+    if (Defined *D = Undef->getWeakAlias()) {
+      if (Resolve)
+        Sym->Body = D;
+      continue;
+    }
+    // If we can resolve a symbol by removing __imp_ prefix, do that.
+    // This odd rule is for compatibility with MSVC linker.
+    if (Name.startswith("__imp_")) {
+      Symbol *Imp = find(Name.substr(strlen("__imp_")));
+      if (Imp && isa<Defined>(Imp->Body)) {
+        if (!Resolve)
+          continue;
+        auto *D = cast<Defined>(Imp->Body);
+        auto *S = new (Alloc) DefinedLocalImport(Name, D);
+        LocalImportChunks.push_back(S->getChunk());
+        Sym->Body = S;
+        continue;
+      }
+    }
+    // Remaining undefined symbols are not fatal if /force is specified.
+    // They are replaced with dummy defined symbols.
+    if (Config->Force && Resolve)
+      Sym->Body = new (Alloc) DefinedAbsolute(Name, 0);
+    Undefs.insert(Sym->Body);
+  }
+  if (Undefs.empty())
+    return;
+  for (Undefined *U : Config->GCRoot)
+    if (Undefs.count(U->repl()))
+      llvm::errs() << "<root>: undefined symbol: " << U->getName() << "\n";
+  for (std::unique_ptr<InputFile> &File : Files)
+    if (!isa<ArchiveFile>(File.get()))
+      for (SymbolBody *Sym : File->getSymbols())
+        if (Undefs.count(Sym->repl()))
+          llvm::errs() << File->getShortName() << ": undefined symbol: "
+                       << Sym->getName() << "\n";
+  if (!Config->Force)
+    fatal("link failed");
+}
+
+void SymbolTable::addLazy(Lazy *New, std::vector<Symbol *> *Accum) {
+  Symbol *Sym = insert(New);
+  if (Sym->Body == New)
+    return;
+  SymbolBody *Existing = Sym->Body;
+  if (isa<Defined>(Existing))
+    return;
+  if (Lazy *L = dyn_cast<Lazy>(Existing))
+    if (L->getFileIndex() < New->getFileIndex())
+      return;
+  Sym->Body = New;
+  New->setBackref(Sym);
+  if (isa<Undefined>(Existing))
+    Accum->push_back(Sym);
+}
+
+void SymbolTable::addSymbol(SymbolBody *New) {
+  // Find an existing symbol or create and insert a new one.
+  assert(isa<Defined>(New) || isa<Undefined>(New));
+  Symbol *Sym = insert(New);
+  if (Sym->Body == New)
+    return;
+  SymbolBody *Existing = Sym->Body;
+
+  // If we have an undefined symbol and a lazy symbol,
+  // let the lazy symbol to read a member file.
+  if (auto *L = dyn_cast<Lazy>(Existing)) {
+    // Undefined symbols with weak aliases need not to be resolved,
+    // since they would be replaced with weak aliases if they remain
+    // undefined.
+    if (auto *U = dyn_cast<Undefined>(New)) {
+      if (!U->WeakAlias) {
+        addMemberFile(L);
+        return;
+      }
+    }
+    Sym->Body = New;
+    return;
+  }
+
+  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
+  // equivalent (conflicting), or more preferable, respectively.
+  int Comp = Existing->compare(New);
+  if (Comp == 0)
+    fatal("duplicate symbol: " + Existing->getDebugName() + " and " +
+          New->getDebugName());
+  if (Comp < 0)
+    Sym->Body = New;
+}
+
+Symbol *SymbolTable::insert(SymbolBody *New) {
+  Symbol *&Sym = Symtab[New->getName()];
+  if (Sym) {
+    New->setBackref(Sym);
+    return Sym;
+  }
+  Sym = new (Alloc) Symbol(New);
+  New->setBackref(Sym);
+  return Sym;
+}
+
+// Reads an archive member file pointed by a given symbol.
+void SymbolTable::addMemberFile(Lazy *Body) {
+  std::unique_ptr<InputFile> File = Body->getMember();
+
+  // getMember returns an empty buffer if the member was already
+  // read from the library.
+  if (!File)
+    return;
+  if (Config->Verbose)
+    llvm::outs() << "Loaded " << File->getShortName() << " for "
+                 << Body->getName() << "\n";
+  addFile(std::move(File));
+}
+
+std::vector<Chunk *> SymbolTable::getChunks() {
+  std::vector<Chunk *> Res;
+  for (ObjectFile *File : ObjectFiles) {
+    std::vector<Chunk *> &V = File->getChunks();
+    Res.insert(Res.end(), V.begin(), V.end());
+  }
+  return Res;
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+  auto It = Symtab.find(Name);
+  if (It == Symtab.end())
+    return nullptr;
+  return It->second;
+}
+
+Symbol *SymbolTable::findUnderscore(StringRef Name) {
+  if (Config->Machine == I386)
+    return find(("_" + Name).str());
+  return find(Name);
+}
+
+StringRef SymbolTable::findByPrefix(StringRef Prefix) {
+  for (auto Pair : Symtab) {
+    StringRef Name = Pair.first;
+    if (Name.startswith(Prefix))
+      return Name;
+  }
+  return "";
+}
+
+StringRef SymbolTable::findMangle(StringRef Name) {
+  if (Symbol *Sym = find(Name))
+    if (!isa<Undefined>(Sym->Body))
+      return Name;
+  if (Config->Machine != I386)
+    return findByPrefix(("?" + Name + "@@Y").str());
+  if (!Name.startswith("_"))
+    return "";
+  // Search for x86 C function.
+  StringRef S = findByPrefix((Name + "@").str());
+  if (!S.empty())
+    return S;
+  // Search for x86 C++ non-member function.
+  return findByPrefix(("?" + Name.substr(1) + "@@Y").str());
+}
+
+void SymbolTable::mangleMaybe(Undefined *U) {
+  if (U->WeakAlias)
+    return;
+  if (!isa<Undefined>(U->repl()))
+    return;
+  StringRef Alias = findMangle(U->getName());
+  if (!Alias.empty())
+    U->WeakAlias = addUndefined(Alias);
+}
+
+Undefined *SymbolTable::addUndefined(StringRef Name) {
+  auto *New = new (Alloc) Undefined(Name);
+  addSymbol(New);
+  if (auto *U = dyn_cast<Undefined>(New->repl()))
+    return U;
+  return New;
+}
+
+DefinedRelative *SymbolTable::addRelative(StringRef Name, uint64_t VA) {
+  auto *New = new (Alloc) DefinedRelative(Name, VA);
+  addSymbol(New);
+  return New;
+}
+
+DefinedAbsolute *SymbolTable::addAbsolute(StringRef Name, uint64_t VA) {
+  auto *New = new (Alloc) DefinedAbsolute(Name, VA);
+  addSymbol(New);
+  return New;
+}
+
+void SymbolTable::printMap(llvm::raw_ostream &OS) {
+  for (ObjectFile *File : ObjectFiles) {
+    OS << File->getShortName() << ":\n";
+    for (SymbolBody *Body : File->getSymbols())
+      if (auto *R = dyn_cast<DefinedRegular>(Body))
+        if (R->getChunk()->isLive())
+          OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
+             << " " << R->getName() << "\n";
+  }
+}
+
+void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) {
+  for (SymbolBody *Body : Obj->getSymbols()) {
+    if (!Body->isExternal())
+      continue;
+    // We should not see any new undefined symbols at this point, but we'll
+    // diagnose them later in reportRemainingUndefines().
+    StringRef Name = Body->getName();
+    Symbol *Sym = insert(Body);
+    SymbolBody *Existing = Sym->Body;
+
+    if (Existing == Body)
+      continue;
+
+    if (isa<DefinedBitcode>(Existing)) {
+      Sym->Body = Body;
+      continue;
+    }
+    if (auto *L = dyn_cast<Lazy>(Existing)) {
+      // We may see new references to runtime library symbols such as __chkstk
+      // here. These symbols must be wholly defined in non-bitcode files.
+      addMemberFile(L);
+      continue;
+    }
+
+    int Comp = Existing->compare(Body);
+    if (Comp == 0)
+      fatal("LTO: unexpected duplicate symbol: " + Name);
+    if (Comp < 0)
+      Sym->Body = Body;
+  }
+}
+
+void SymbolTable::addCombinedLTOObjects() {
+  if (BitcodeFiles.empty())
+    return;
+
+  // Diagnose any undefined symbols early, but do not resolve weak externals,
+  // as resolution breaks the invariant that each Symbol points to a unique
+  // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly.
+  reportRemainingUndefines(/*Resolve=*/false);
+
+  // Create an object file and add it to the symbol table by replacing any
+  // DefinedBitcode symbols with the definitions in the object file.
+  LTOCodeGenerator CG(BitcodeFile::Context);
+  CG.setOptLevel(Config->LTOOptLevel);
+  std::vector<ObjectFile *> Objs = createLTOObjects(&CG);
+
+  for (ObjectFile *Obj : Objs)
+    addCombinedLTOObject(Obj);
+
+  size_t NumBitcodeFiles = BitcodeFiles.size();
+  run();
+  if (BitcodeFiles.size() != NumBitcodeFiles)
+    fatal("LTO: late loaded symbol created new bitcode reference");
+}
+
+// Combine and compile bitcode files and then return the result
+// as a vector of regular COFF object files.
+std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
+  // All symbols referenced by non-bitcode objects must be preserved.
+  for (ObjectFile *File : ObjectFiles)
+    for (SymbolBody *Body : File->getSymbols())
+      if (auto *S = dyn_cast<DefinedBitcode>(Body->repl()))
+        CG->addMustPreserveSymbol(S->getName());
+
+  // Likewise for bitcode symbols which we initially resolved to non-bitcode.
+  for (BitcodeFile *File : BitcodeFiles)
+    for (SymbolBody *Body : File->getSymbols())
+      if (isa<DefinedBitcode>(Body) && !isa<DefinedBitcode>(Body->repl()))
+        CG->addMustPreserveSymbol(Body->getName());
+
+  // Likewise for other symbols that must be preserved.
+  for (Undefined *U : Config->GCRoot) {
+    if (auto *S = dyn_cast<DefinedBitcode>(U->repl()))
+      CG->addMustPreserveSymbol(S->getName());
+    else if (auto *S = dyn_cast_or_null<DefinedBitcode>(U->getWeakAlias()))
+      CG->addMustPreserveSymbol(S->getName());
+  }
+
+  CG->setModule(BitcodeFiles[0]->takeModule());
+  for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
+    CG->addModule(BitcodeFiles[I]->takeModule().get());
+
+  bool DisableVerify = true;
+#ifdef NDEBUG
+  DisableVerify = false;
+#endif
+  if (!CG->optimize(DisableVerify, false, false, false))
+    fatal(""); // optimize() should have emitted any error message.
+
+  Objs.resize(Config->LTOJobs);
+  // Use std::list to avoid invalidation of pointers in OSPtrs.
+  std::list<raw_svector_ostream> OSs;
+  std::vector<raw_pwrite_stream *> OSPtrs;
+  for (SmallString<0> &Obj : Objs) {
+    OSs.emplace_back(Obj);
+    OSPtrs.push_back(&OSs.back());
+  }
+
+  if (!CG->compileOptimized(OSPtrs))
+    fatal(""); // compileOptimized() should have emitted any error message.
+
+  std::vector<ObjectFile *> ObjFiles;
+  for (SmallString<0> &Obj : Objs) {
+    auto *ObjFile = new ObjectFile(MemoryBufferRef(Obj, "<LTO object>"));
+    Files.emplace_back(ObjFile);
+    ObjectFiles.push_back(ObjFile);
+    ObjFile->parse();
+    ObjFiles.push_back(ObjFile);
+  }
+
+  return ObjFiles;
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
new file mode 100644 (file)
index 0000000..8bf4387
--- /dev/null
@@ -0,0 +1,125 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOL_TABLE_H
+#define LLD_COFF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+
+#ifdef _MSC_VER
+// <future> depends on <eh.h> for __uncaught_exception.
+#include <eh.h>
+#endif
+
+#include <future>
+
+namespace llvm {
+struct LTOCodeGenerator;
+}
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class Defined;
+class Lazy;
+class SymbolBody;
+struct Symbol;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in resolve().
+class SymbolTable {
+public:
+  void addFile(std::unique_ptr<InputFile> File);
+  std::vector<std::unique_ptr<InputFile>> &getFiles() { return Files; }
+  void step();
+  void run();
+  bool queueEmpty();
+
+  // Print an error message on undefined symbols. If Resolve is true, try to
+  // resolve any undefined symbols and update the symbol table accordingly.
+  void reportRemainingUndefines(bool Resolve);
+
+  // Returns a list of chunks of selected symbols.
+  std::vector<Chunk *> getChunks();
+
+  // Returns a symbol for a given name. Returns a nullptr if not found.
+  Symbol *find(StringRef Name);
+  Symbol *findUnderscore(StringRef Name);
+
+  // Occasionally we have to resolve an undefined symbol to its
+  // mangled symbol. This function tries to find a mangled name
+  // for U from the symbol table, and if found, set the symbol as
+  // a weak alias for U.
+  void mangleMaybe(Undefined *U);
+  StringRef findMangle(StringRef Name);
+
+  // Print a layout map to OS.
+  void printMap(llvm::raw_ostream &OS);
+
+  // Build a set of COFF objects representing the combined contents of
+  // BitcodeFiles and add them to the symbol table. Called after all files are
+  // added and before the writer writes results to a file.
+  void addCombinedLTOObjects();
+
+  // The writer needs to handle DLL import libraries specially in
+  // order to create the import descriptor table.
+  std::vector<ImportFile *> ImportFiles;
+
+  // The writer needs to infer the machine type from the object files.
+  std::vector<ObjectFile *> ObjectFiles;
+
+  // Creates an Undefined symbol for a given name.
+  Undefined *addUndefined(StringRef Name);
+  DefinedRelative *addRelative(StringRef Name, uint64_t VA);
+  DefinedAbsolute *addAbsolute(StringRef Name, uint64_t VA);
+
+  // A list of chunks which to be added to .rdata.
+  std::vector<Chunk *> LocalImportChunks;
+
+private:
+  void readArchives();
+  void readObjects();
+
+  void addSymbol(SymbolBody *New);
+  void addLazy(Lazy *New, std::vector<Symbol *> *Accum);
+  Symbol *insert(SymbolBody *New);
+  StringRef findByPrefix(StringRef Prefix);
+
+  void addMemberFile(Lazy *Body);
+  void addCombinedLTOObject(ObjectFile *Obj);
+  std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
+
+  llvm::DenseMap<StringRef, Symbol *> Symtab;
+
+  std::vector<std::unique_ptr<InputFile>> Files;
+  std::vector<std::future<ArchiveFile *>> ArchiveQueue;
+  std::vector<std::future<InputFile *>> ObjectQueue;
+
+  std::vector<BitcodeFile *> BitcodeFiles;
+  std::vector<SmallString<0>> Objs;
+  llvm::BumpPtrAllocator Alloc;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
new file mode 100644 (file)
index 0000000..6e2db66
--- /dev/null
@@ -0,0 +1,217 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::object;
+using llvm::sys::fs::identify_magic;
+using llvm::sys::fs::file_magic;
+
+namespace lld {
+namespace coff {
+
+StringRef SymbolBody::getName() {
+  // DefinedCOFF names are read lazily for a performance reason.
+  // Non-external symbol names are never used by the linker except for logging
+  // or debugging. Their internal references are resolved not by name but by
+  // symbol index. And because they are not external, no one can refer them by
+  // name. Object files contain lots of non-external symbols, and creating
+  // StringRefs for them (which involves lots of strlen() on the string table)
+  // is a waste of time.
+  if (Name.empty()) {
+    auto *D = cast<DefinedCOFF>(this);
+    D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
+  }
+  return Name;
+}
+
+// Returns 1, 0 or -1 if this symbol should take precedence
+// over the Other, tie or lose, respectively.
+int SymbolBody::compare(SymbolBody *Other) {
+  Kind LK = kind(), RK = Other->kind();
+
+  // Normalize so that the smaller kind is on the left.
+  if (LK > RK)
+    return -Other->compare(this);
+
+  // First handle comparisons between two different kinds.
+  if (LK != RK) {
+    if (RK > LastDefinedKind) {
+      if (LK == LazyKind && cast<Undefined>(Other)->WeakAlias)
+        return -1;
+
+      // The LHS is either defined or lazy and so it wins.
+      assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!");
+      return 1;
+    }
+
+    // Bitcode has special complexities.
+    if (RK == DefinedBitcodeKind) {
+      auto *RHS = cast<DefinedBitcode>(Other);
+
+      switch (LK) {
+      case DefinedCommonKind:
+        return 1;
+
+      case DefinedRegularKind:
+        // As an approximation, regular symbols win over bitcode symbols,
+        // but we definitely have a conflict if the regular symbol is not
+        // replaceable and neither is the bitcode symbol. We do not
+        // replicate the rest of the symbol resolution logic here; symbol
+        // resolution will be done accurately after lowering bitcode symbols
+        // to regular symbols in addCombinedLTOObject().
+        if (cast<DefinedRegular>(this)->isCOMDAT() || RHS->IsReplaceable)
+          return 1;
+
+        // Fallthrough to the default of a tie otherwise.
+      default:
+        return 0;
+      }
+    }
+
+    // Either of the object file kind will trump a higher kind.
+    if (LK <= LastDefinedCOFFKind)
+      return 1;
+
+    // The remaining kind pairs are ties amongst defined symbols.
+    return 0;
+  }
+
+  // Now handle the case where the kinds are the same.
+  switch (LK) {
+  case DefinedRegularKind: {
+    auto *LHS = cast<DefinedRegular>(this);
+    auto *RHS = cast<DefinedRegular>(Other);
+    if (LHS->isCOMDAT() && RHS->isCOMDAT())
+      return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+    return 0;
+  }
+
+  case DefinedCommonKind: {
+    auto *LHS = cast<DefinedCommon>(this);
+    auto *RHS = cast<DefinedCommon>(Other);
+    if (LHS->getSize() == RHS->getSize())
+      return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+    return LHS->getSize() > RHS->getSize() ? 1 : -1;
+  }
+
+  case DefinedBitcodeKind: {
+    auto *LHS = cast<DefinedBitcode>(this);
+    auto *RHS = cast<DefinedBitcode>(Other);
+    // If both are non-replaceable, we have a tie.
+    if (!LHS->IsReplaceable && !RHS->IsReplaceable)
+      return 0;
+
+    // Non-replaceable symbols win, but even two replaceable symboles don't
+    // tie. If both symbols are replaceable, choice is arbitrary.
+    if (RHS->IsReplaceable && LHS->IsReplaceable)
+      return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
+    return LHS->IsReplaceable ? -1 : 1;
+  }
+
+  case LazyKind: {
+    // Don't tie, pick the earliest.
+    auto *LHS = cast<Lazy>(this);
+    auto *RHS = cast<Lazy>(Other);
+    return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+  }
+
+  case UndefinedKind: {
+    auto *LHS = cast<Undefined>(this);
+    auto *RHS = cast<Undefined>(Other);
+    // Tie if both undefined symbols have different weak aliases.
+    if (LHS->WeakAlias && RHS->WeakAlias) {
+      if (LHS->WeakAlias->getName() != RHS->WeakAlias->getName())
+        return 0;
+      return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
+    }
+    return LHS->WeakAlias ? 1 : -1;
+  }
+
+  case DefinedLocalImportKind:
+  case DefinedImportThunkKind:
+  case DefinedImportDataKind:
+  case DefinedAbsoluteKind:
+  case DefinedRelativeKind:
+    // These all simply tie.
+    return 0;
+  }
+  llvm_unreachable("unknown symbol kind");
+}
+
+std::string SymbolBody::getDebugName() {
+  std::string N = getName().str();
+  if (auto *D = dyn_cast<DefinedCOFF>(this)) {
+    N += " ";
+    N += D->File->getShortName();
+  } else if (auto *D = dyn_cast<DefinedBitcode>(this)) {
+    N += " ";
+    N += D->File->getShortName();
+  }
+  return N;
+}
+
+COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
+  size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize();
+  if (SymSize == sizeof(coff_symbol16))
+    return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
+  assert(SymSize == sizeof(coff_symbol32));
+  return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
+}
+
+DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
+                                       uint16_t Machine)
+    : Defined(DefinedImportThunkKind, Name) {
+  switch (Machine) {
+  case AMD64: Data.reset(new ImportThunkChunkX64(S)); return;
+  case I386:  Data.reset(new ImportThunkChunkX86(S)); return;
+  case ARMNT: Data.reset(new ImportThunkChunkARM(S)); return;
+  default:    llvm_unreachable("unknown machine type");
+  }
+}
+
+std::unique_ptr<InputFile> Lazy::getMember() {
+  MemoryBufferRef MBRef = File->getMember(&Sym);
+
+  // getMember returns an empty buffer if the member was already
+  // read from the library.
+  if (MBRef.getBuffer().empty())
+    return std::unique_ptr<InputFile>(nullptr);
+
+  file_magic Magic = identify_magic(MBRef.getBuffer());
+  if (Magic == file_magic::coff_import_library)
+    return std::unique_ptr<InputFile>(new ImportFile(MBRef));
+
+  std::unique_ptr<InputFile> Obj;
+  if (Magic == file_magic::coff_object)
+    Obj.reset(new ObjectFile(MBRef));
+  else if (Magic == file_magic::bitcode)
+    Obj.reset(new BitcodeFile(MBRef));
+  else
+    fatal("unknown file type: " + File->getName());
+
+  Obj->setParentName(File->getName());
+  return Obj;
+}
+
+Defined *Undefined::getWeakAlias() {
+  // A weak alias may be a weak alias to another symbol, so check recursively.
+  for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
+    if (auto *D = dyn_cast<Defined>(A->repl()))
+      return D;
+  return nullptr;
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
new file mode 100644 (file)
index 0000000..f96c1fb
--- /dev/null
@@ -0,0 +1,403 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOLS_H
+#define LLD_COFF_SYMBOLS_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::object::Archive;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_symbol_generic;
+
+class ArchiveFile;
+class BitcodeFile;
+class InputFile;
+class ObjectFile;
+class SymbolBody;
+
+// A real symbol object, SymbolBody, is usually accessed indirectly
+// through a Symbol. There's always one Symbol for each symbol name.
+// The resolver updates SymbolBody pointers as it resolves symbols.
+struct Symbol {
+  explicit Symbol(SymbolBody *P) : Body(P) {}
+  SymbolBody *Body;
+};
+
+// The base class for real symbol classes.
+class SymbolBody {
+public:
+  enum Kind {
+    // The order of these is significant. We start with the regular defined
+    // symbols as those are the most prevelant and the zero tag is the cheapest
+    // to set. Among the defined kinds, the lower the kind is preferred over
+    // the higher kind when testing wether one symbol should take precedence
+    // over another.
+    DefinedRegularKind = 0,
+    DefinedCommonKind,
+    DefinedLocalImportKind,
+    DefinedImportThunkKind,
+    DefinedImportDataKind,
+    DefinedAbsoluteKind,
+    DefinedRelativeKind,
+    DefinedBitcodeKind,
+
+    UndefinedKind,
+    LazyKind,
+
+    LastDefinedCOFFKind = DefinedCommonKind,
+    LastDefinedKind = DefinedBitcodeKind,
+  };
+
+  Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+  // Returns true if this is an external symbol.
+  bool isExternal() { return IsExternal; }
+
+  // Returns the symbol name.
+  StringRef getName();
+
+  // A SymbolBody has a backreference to a Symbol. Originally they are
+  // doubly-linked. A backreference will never change. But the pointer
+  // in the Symbol may be mutated by the resolver. If you have a
+  // pointer P to a SymbolBody and are not sure whether the resolver
+  // has chosen the object among other objects having the same name,
+  // you can access P->Backref->Body to get the resolver's result.
+  void setBackref(Symbol *P) { Backref = P; }
+  SymbolBody *repl() { return Backref ? Backref->Body : this; }
+
+  // Decides which symbol should "win" in the symbol table, this or
+  // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
+  // they are duplicate (conflicting) symbols.
+  int compare(SymbolBody *Other);
+
+  // Returns a name of this symbol including source file name.
+  // Used only for debugging and logging.
+  std::string getDebugName();
+
+protected:
+  explicit SymbolBody(Kind K, StringRef N = "")
+      : SymbolKind(K), IsExternal(true), IsCOMDAT(false),
+        IsReplaceable(false), Name(N) {}
+
+  const unsigned SymbolKind : 8;
+  unsigned IsExternal : 1;
+
+  // This bit is used by the \c DefinedRegular subclass.
+  unsigned IsCOMDAT : 1;
+
+  // This bit is used by the \c DefinedBitcode subclass.
+  unsigned IsReplaceable : 1;
+
+  StringRef Name;
+  Symbol *Backref = nullptr;
+};
+
+// The base class for any defined symbols, including absolute symbols,
+// etc.
+class Defined : public SymbolBody {
+public:
+  Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() <= LastDefinedKind;
+  }
+
+  // Returns the RVA (relative virtual address) of this symbol. The
+  // writer sets and uses RVAs.
+  uint64_t getRVA();
+
+  // Returns the RVA relative to the beginning of the output section.
+  // Used to implement SECREL relocation type.
+  uint64_t getSecrel();
+
+  // Returns the output section index.
+  // Used to implement SECTION relocation type.
+  uint64_t getSectionIndex();
+
+  // Returns true if this symbol points to an executable (e.g. .text) section.
+  // Used to implement ARM relocations.
+  bool isExecutable();
+};
+
+// Symbols defined via a COFF object file.
+class DefinedCOFF : public Defined {
+  friend SymbolBody;
+public:
+  DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S)
+      : Defined(K), File(F), Sym(S.getGeneric()) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() <= LastDefinedCOFFKind;
+  }
+
+  int getFileIndex() { return File->Index; }
+
+  COFFSymbolRef getCOFFSymbol();
+
+protected:
+  ObjectFile *File;
+  const coff_symbol_generic *Sym;
+};
+
+// Regular defined symbols read from object file symbol tables.
+class DefinedRegular : public DefinedCOFF {
+public:
+  DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C)
+      : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) {
+    IsExternal = S.isExternal();
+    IsCOMDAT = C->isCOMDAT();
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedRegularKind;
+  }
+
+  uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; }
+  bool isCOMDAT() { return IsCOMDAT; }
+  SectionChunk *getChunk() { return *Data; }
+  uint32_t getValue() { return Sym->Value; }
+
+private:
+  SectionChunk **Data;
+};
+
+class DefinedCommon : public DefinedCOFF {
+public:
+  DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C)
+      : DefinedCOFF(DefinedCommonKind, F, S), Data(C) {
+    IsExternal = S.isExternal();
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedCommonKind;
+  }
+
+  uint64_t getRVA() { return Data->getRVA(); }
+
+private:
+  friend SymbolBody;
+  uint64_t getSize() { return Sym->Value; }
+  CommonChunk *Data;
+};
+
+// Absolute symbols.
+class DefinedAbsolute : public Defined {
+public:
+  DefinedAbsolute(StringRef N, COFFSymbolRef S)
+      : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
+    IsExternal = S.isExternal();
+  }
+
+  DefinedAbsolute(StringRef N, uint64_t V)
+      : Defined(DefinedAbsoluteKind, N), VA(V) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedAbsoluteKind;
+  }
+
+  uint64_t getRVA() { return VA - Config->ImageBase; }
+  void setVA(uint64_t V) { VA = V; }
+
+private:
+  uint64_t VA;
+};
+
+// This is a kind of absolute symbol but relative to the image base.
+// Unlike absolute symbols, relocations referring this kind of symbols
+// are subject of the base relocation. This type is used rarely --
+// mainly for __ImageBase.
+class DefinedRelative : public Defined {
+public:
+  explicit DefinedRelative(StringRef Name, uint64_t V = 0)
+      : Defined(DefinedRelativeKind, Name), RVA(V) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedRelativeKind;
+  }
+
+  uint64_t getRVA() { return RVA; }
+  void setRVA(uint64_t V) { RVA = V; }
+
+private:
+  uint64_t RVA;
+};
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol. If the resolver finds both Undefined and Lazy for
+// the same name, it will ask the Lazy to load a file.
+class Lazy : public SymbolBody {
+public:
+  Lazy(ArchiveFile *F, const Archive::Symbol S)
+      : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {}
+
+  static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+
+  // Returns an object file for this symbol, or a nullptr if the file
+  // was already returned.
+  std::unique_ptr<InputFile> getMember();
+
+  int getFileIndex() { return File->Index; }
+
+private:
+  ArchiveFile *File;
+  const Archive::Symbol Sym;
+};
+
+// Undefined symbols.
+class Undefined : public SymbolBody {
+public:
+  explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == UndefinedKind;
+  }
+
+  // An undefined symbol can have a fallback symbol which gives an
+  // undefined symbol a second chance if it would remain undefined.
+  // If it remains undefined, it'll be replaced with whatever the
+  // Alias pointer points to.
+  SymbolBody *WeakAlias = nullptr;
+
+  // If this symbol is external weak, try to resolve it to a defined
+  // symbol by searching the chain of fallback symbols. Returns the symbol if
+  // successful, otherwise returns null.
+  Defined *getWeakAlias();
+};
+
+// Windows-specific classes.
+
+// This class represents a symbol imported from a DLL. This has two
+// names for internal use and external use. The former is used for
+// name resolution, and the latter is used for the import descriptor
+// table in an output. The former has "__imp_" prefix.
+class DefinedImportData : public Defined {
+public:
+  DefinedImportData(StringRef D, StringRef N, StringRef E,
+                    const coff_import_header *H)
+      : Defined(DefinedImportDataKind, N), DLLName(D), ExternalName(E), Hdr(H) {
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedImportDataKind;
+  }
+
+  uint64_t getRVA() { return Location->getRVA(); }
+  StringRef getDLLName() { return DLLName; }
+  StringRef getExternalName() { return ExternalName; }
+  void setLocation(Chunk *AddressTable) { Location = AddressTable; }
+  uint16_t getOrdinal() { return Hdr->OrdinalHint; }
+
+private:
+  StringRef DLLName;
+  StringRef ExternalName;
+  const coff_import_header *Hdr;
+  Chunk *Location = nullptr;
+};
+
+// This class represents a symbol for a jump table entry which jumps
+// to a function in a DLL. Linker are supposed to create such symbols
+// without "__imp_" prefix for all function symbols exported from
+// DLLs, so that you can call DLL functions as regular functions with
+// a regular name. A function pointer is given as a DefinedImportData.
+class DefinedImportThunk : public Defined {
+public:
+  DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedImportThunkKind;
+  }
+
+  uint64_t getRVA() { return Data->getRVA(); }
+  Chunk *getChunk() { return Data.get(); }
+
+private:
+  std::unique_ptr<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(S) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedLocalImportKind;
+  }
+
+  uint64_t getRVA() { return Data.getRVA(); }
+  Chunk *getChunk() { return &Data; }
+
+private:
+  LocalImportChunk Data;
+};
+
+class DefinedBitcode : public Defined {
+  friend SymbolBody;
+public:
+  DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable)
+      : Defined(DefinedBitcodeKind, N), File(F) {
+    this->IsReplaceable = IsReplaceable;
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedBitcodeKind;
+  }
+
+private:
+  BitcodeFile *File;
+};
+
+inline uint64_t Defined::getRVA() {
+  switch (kind()) {
+  case DefinedAbsoluteKind:
+    return cast<DefinedAbsolute>(this)->getRVA();
+  case DefinedRelativeKind:
+    return cast<DefinedRelative>(this)->getRVA();
+  case DefinedImportDataKind:
+    return cast<DefinedImportData>(this)->getRVA();
+  case DefinedImportThunkKind:
+    return cast<DefinedImportThunk>(this)->getRVA();
+  case DefinedLocalImportKind:
+    return cast<DefinedLocalImport>(this)->getRVA();
+  case DefinedCommonKind:
+    return cast<DefinedCommon>(this)->getRVA();
+  case DefinedRegularKind:
+    return cast<DefinedRegular>(this)->getRVA();
+  case DefinedBitcodeKind:
+    llvm_unreachable("There is no address for a bitcode symbol.");
+  case LazyKind:
+  case UndefinedKind:
+    llvm_unreachable("Cannot get the address for an undefined symbol.");
+  }
+  llvm_unreachable("unknown symbol kind");
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
new file mode 100644 (file)
index 0000000..d8077df
--- /dev/null
@@ -0,0 +1,796 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "DLL.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::coff;
+
+static const int PageSize = 4096;
+static const int SectorSize = 512;
+static const int DOSStubSize = 64;
+static const int NumberfOfDataDirectory = 16;
+
+namespace {
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+  Writer(SymbolTable *T) : Symtab(T) {}
+  void run();
+
+private:
+  void createSections();
+  void createMiscChunks();
+  void createImportTables();
+  void createExportTable();
+  void assignAddresses();
+  void removeEmptySections();
+  void createSymbolAndStringTable();
+  void openFile(StringRef OutputPath);
+  template <typename PEHeaderTy> void writeHeader();
+  void fixSafeSEHSymbols();
+  void setSectionPermissions();
+  void writeSections();
+  void sortExceptionTable();
+  void applyRelocations();
+
+  llvm::Optional<coff_symbol16> 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<Baserel> &V);
+
+  uint32_t getSizeOfInitializedData();
+  std::map<StringRef, std::vector<DefinedImportData *>> binImports();
+
+  SymbolTable *Symtab;
+  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+  llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
+  llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
+  std::vector<OutputSection *> OutputSections;
+  std::vector<char> Strtab;
+  std::vector<llvm::object::coff_symbol16> OutputSymtab;
+  IdataContents Idata;
+  DelayLoadContents DelayIdata;
+  EdataContents Edata;
+  std::unique_ptr<SEHTableChunk> SEHTable;
+
+  uint64_t FileSize;
+  uint32_t PointerToSymbolTable = 0;
+  uint64_t SizeOfImage;
+  uint64_t SizeOfHeaders;
+
+  std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+} // anonymous namespace
+
+namespace lld {
+namespace coff {
+
+void writeResult(SymbolTable *T) { Writer(T).run(); }
+
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+  OutputSection(StringRef N) : Name(N), Header({}) {}
+  void setRVA(uint64_t);
+  void setFileOffset(uint64_t);
+  void addChunk(Chunk *C);
+  StringRef getName() { return Name; }
+  std::vector<Chunk *> &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:
+  StringRef Name;
+  coff_section Header;
+  uint32_t StringTableOff = 0;
+  std::vector<Chunk *> Chunks;
+};
+
+void OutputSection::setRVA(uint64_t RVA) {
+  Header.VirtualAddress = RVA;
+  for (Chunk *C : Chunks)
+    C->setRVA(C->getRVA() + RVA);
+}
+
+void OutputSection::setFileOffset(uint64_t Off) {
+  // If a section has no actual data (i.e. BSS section), we want to
+  // set 0 to its PointerToRawData. Otherwise the output is rejected
+  // by the loader.
+  if (Header.SizeOfRawData == 0)
+    return;
+  Header.PointerToRawData = Off;
+}
+
+void OutputSection::addChunk(Chunk *C) {
+  Chunks.push_back(C);
+  C->setOutputSection(this);
+  uint64_t Off = Header.VirtualSize;
+  Off = alignTo(Off, C->getAlign());
+  C->setRVA(Off);
+  C->setOutputSectionOff(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<coff_section *>(Buf);
+  *Hdr = Header;
+  if (StringTableOff) {
+    // If name is too long, write offset into the string table as a name.
+    sprintf(Hdr->Name, "/%d", StringTableOff);
+  } else {
+    assert(!Config->Debug || Name.size() <= COFF::NameSize);
+    strncpy(Hdr->Name, Name.data(),
+            std::min(Name.size(), (size_t)COFF::NameSize));
+  }
+}
+
+uint64_t Defined::getSecrel() {
+  if (auto *D = dyn_cast<DefinedRegular>(this))
+    return getRVA() - D->getChunk()->getOutputSection()->getRVA();
+  fatal("SECREL relocation points to a non-regular symbol");
+}
+
+uint64_t Defined::getSectionIndex() {
+  if (auto *D = dyn_cast<DefinedRegular>(this))
+    return D->getChunk()->getOutputSection()->SectionIndex;
+  fatal("SECTION relocation points to a non-regular symbol");
+}
+
+bool Defined::isExecutable() {
+  const auto X = IMAGE_SCN_MEM_EXECUTE;
+  if (auto *D = dyn_cast<DefinedRegular>(this))
+    return D->getChunk()->getOutputSection()->getPermissions() & X;
+  return isa<DefinedImportThunk>(this);
+}
+
+} // namespace coff
+} // namespace lld
+
+// The main function of the writer.
+void Writer::run() {
+  createSections();
+  createMiscChunks();
+  createImportTables();
+  createExportTable();
+  if (Config->Relocatable)
+    createSection(".reloc");
+  assignAddresses();
+  removeEmptySections();
+  setSectionPermissions();
+  createSymbolAndStringTable();
+  openFile(Config->OutputFile);
+  if (Config->is64()) {
+    writeHeader<pe32plus_header>();
+  } else {
+    writeHeader<pe32_header>();
+  }
+  fixSafeSEHSymbols();
+  writeSections();
+  sortExceptionTable();
+  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<StringRef, std::vector<Chunk *>> Map;
+  for (Chunk *C : Symtab->getChunks()) {
+    auto *SC = dyn_cast<SectionChunk>(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<StringRef, OutputSection *> Sections;
+  for (auto Pair : Map) {
+    StringRef Name = getOutputSection(Pair.first);
+    OutputSection *&Sec = Sections[Name];
+    if (!Sec) {
+      Sec = new (CAlloc.Allocate()) OutputSection(Name);
+      OutputSections.push_back(Sec);
+    }
+    std::vector<Chunk *> &Chunks = Pair.second;
+    for (Chunk *C : Chunks) {
+      Sec->addChunk(C);
+      Sec->addPermissions(C->getPermissions());
+    }
+  }
+}
+
+void Writer::createMiscChunks() {
+  // Create thunks for locally-dllimported symbols.
+  if (!Symtab->LocalImportChunks.empty()) {
+    OutputSection *Sec = createSection(".rdata");
+    for (Chunk *C : Symtab->LocalImportChunks)
+      Sec->addChunk(C);
+  }
+
+  // Create SEH table. x86-only.
+  if (Config->Machine != I386)
+    return;
+  std::set<Defined *> Handlers;
+  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
+    if (!File->SEHCompat)
+      return;
+    for (SymbolBody *B : File->SEHandlers)
+      Handlers.insert(cast<Defined>(B->repl()));
+  }
+  SEHTable.reset(new SEHTableChunk(Handlers));
+  createSection(".rdata")->addChunk(SEHTable.get());
+}
+
+// Create .idata section for the DLL-imported symbol table.
+// The format of this section is inherently Windows-specific.
+// IdataContents class abstracted away the details for us,
+// so we just let it create chunks and add them to the section.
+void Writer::createImportTables() {
+  if (Symtab->ImportFiles.empty())
+    return;
+
+  // Initialize DLLOrder so that import entries are ordered in
+  // the same order as in the command line. (That affects DLL
+  // initialization order, and this ordering is MSVC-compatible.)
+  for (ImportFile *File : Symtab->ImportFiles) {
+    std::string DLL = StringRef(File->DLLName).lower();
+    if (Config->DLLOrder.count(DLL) == 0)
+      Config->DLLOrder[DLL] = Config->DLLOrder.size();
+  }
+
+  OutputSection *Text = createSection(".text");
+  for (ImportFile *File : Symtab->ImportFiles) {
+    if (DefinedImportThunk *Thunk = File->ThunkSym)
+      Text->addChunk(Thunk->getChunk());
+    if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
+      DelayIdata.add(File->ImpSym);
+    } else {
+      Idata.add(File->ImpSym);
+    }
+  }
+  if (!Idata.empty()) {
+    OutputSection *Sec = createSection(".idata");
+    for (Chunk *C : Idata.getChunks())
+      Sec->addChunk(C);
+  }
+  if (!DelayIdata.empty()) {
+    Defined *Helper = cast<Defined>(Config->DelayLoadHelper->repl());
+    DelayIdata.create(Helper);
+    OutputSection *Sec = createSection(".didat");
+    for (Chunk *C : DelayIdata.getChunks())
+      Sec->addChunk(C);
+    Sec = createSection(".data");
+    for (Chunk *C : DelayIdata.getDataChunks())
+      Sec->addChunk(C);
+    Sec = createSection(".text");
+    for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks())
+      Sec->addChunk(C.get());
+  }
+}
+
+void Writer::createExportTable() {
+  if (Config->Exports.empty())
+    return;
+  OutputSection *Sec = createSection(".edata");
+  for (std::unique_ptr<Chunk> &C : Edata.Chunks)
+    Sec->addChunk(C.get());
+}
+
+// The Windows loader doesn't seem to like empty sections,
+// so we remove them if any.
+void Writer::removeEmptySections() {
+  auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; };
+  OutputSections.erase(
+      std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
+      OutputSections.end());
+  uint32_t Idx = 1;
+  for (OutputSection *Sec : OutputSections)
+    Sec->SectionIndex = Idx++;
+}
+
+size_t Writer::addEntryToStringTable(StringRef Str) {
+  assert(Str.size() > COFF::NameSize);
+  size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
+  Strtab.insert(Strtab.end(), Str.begin(), Str.end());
+  Strtab.push_back('\0');
+  return OffsetOfEntry;
+}
+
+Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
+  if (auto *D = dyn_cast<DefinedRegular>(Def))
+    if (!D->getChunk()->isLive())
+      return None;
+
+  coff_symbol16 Sym;
+  StringRef Name = Def->getName();
+  if (Name.size() > COFF::NameSize) {
+    Sym.Name.Offset.Zeroes = 0;
+    Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+  } else {
+    memset(Sym.Name.ShortName, 0, COFF::NameSize);
+    memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+  }
+
+  if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+    COFFSymbolRef Ref = D->getCOFFSymbol();
+    Sym.Type = Ref.getType();
+    Sym.StorageClass = Ref.getStorageClass();
+  } else {
+    Sym.Type = IMAGE_SYM_TYPE_NULL;
+    Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+  }
+  Sym.NumberOfAuxSymbols = 0;
+
+  switch (Def->kind()) {
+  case SymbolBody::DefinedAbsoluteKind:
+  case SymbolBody::DefinedRelativeKind:
+    Sym.Value = Def->getRVA();
+    Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+    break;
+  default: {
+    uint64_t RVA = Def->getRVA();
+    OutputSection *Sec = nullptr;
+    for (OutputSection *S : OutputSections) {
+      if (S->getRVA() > RVA)
+        break;
+      Sec = S;
+    }
+    Sym.Value = RVA - Sec->getRVA();
+    Sym.SectionNumber = Sec->SectionIndex;
+    break;
+  }
+  }
+  return Sym;
+}
+
+void Writer::createSymbolAndStringTable() {
+  if (!Config->Debug || !Config->WriteSymtab)
+    return;
+
+  // Name field in the section table is 8 byte long. Longer names need
+  // to be written to the string table. First, construct string table.
+  for (OutputSection *Sec : OutputSections) {
+    StringRef Name = Sec->getName();
+    if (Name.size() <= COFF::NameSize)
+      continue;
+    Sec->setStringTableOff(addEntryToStringTable(Name));
+  }
+
+  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles)
+    for (SymbolBody *B : File->getSymbols())
+      if (auto *D = dyn_cast<Defined>(B))
+        if (Optional<coff_symbol16> Sym = createSymbol(D))
+          OutputSymtab.push_back(*Sym);
+
+  for (ImportFile *File : Symtab->ImportFiles)
+    for (SymbolBody *B : File->getSymbols())
+      if (Optional<coff_symbol16> Sym = createSymbol(cast<Defined>(B)))
+        OutputSymtab.push_back(*Sym);
+
+  OutputSection *LastSection = OutputSections.back();
+  // We position the symbol table to be adjacent to the end of the last section.
+  uint64_t FileOff = LastSection->getFileOff() +
+                     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 <typename PEHeaderTy> void Writer::writeHeader() {
+  // Write DOS stub
+  uint8_t *Buf = Buffer->getBufferStart();
+  auto *DOS = reinterpret_cast<dos_header *>(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<coff_file_header *>(Buf);
+  Buf += sizeof(*COFF);
+  COFF->Machine = Config->Machine;
+  COFF->NumberOfSections = OutputSections.size();
+  COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+  if (Config->LargeAddressAware)
+    COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+  if (!Config->is64())
+    COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+  if (Config->DLL)
+    COFF->Characteristics |= IMAGE_FILE_DLL;
+  if (!Config->Relocatable)
+    COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+  COFF->SizeOfOptionalHeader =
+      sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory;
+
+  // Write PE header
+  auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
+  Buf += sizeof(*PE);
+  PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+  PE->ImageBase = Config->ImageBase;
+  PE->SectionAlignment = PageSize;
+  PE->FileAlignment = SectorSize;
+  PE->MajorImageVersion = Config->MajorImageVersion;
+  PE->MinorImageVersion = Config->MinorImageVersion;
+  PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
+  PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
+  PE->MajorSubsystemVersion = Config->MajorOSVersion;
+  PE->MinorSubsystemVersion = Config->MinorOSVersion;
+  PE->Subsystem = Config->Subsystem;
+  PE->SizeOfImage = SizeOfImage;
+  PE->SizeOfHeaders = SizeOfHeaders;
+  if (!Config->NoEntry) {
+    Defined *Entry = cast<Defined>(Config->Entry->repl());
+    PE->AddressOfEntryPoint = Entry->getRVA();
+    // Pointer to thumb code must have the LSB set, so adjust it.
+    if (Config->Machine == ARMNT)
+      PE->AddressOfEntryPoint |= 1;
+  }
+  PE->SizeOfStackReserve = Config->StackReserve;
+  PE->SizeOfStackCommit = Config->StackCommit;
+  PE->SizeOfHeapReserve = Config->HeapReserve;
+  PE->SizeOfHeapCommit = Config->HeapCommit;
+  if (Config->DynamicBase)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
+  if (Config->HighEntropyVA)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
+  if (!Config->AllowBind)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+  if (Config->NxCompat)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
+  if (!Config->AllowIsolation)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+  if (Config->TerminalServerAware)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+  PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
+  if (OutputSection *Text = findSection(".text")) {
+    PE->BaseOfCode = Text->getRVA();
+    PE->SizeOfCode = Text->getRawSize();
+  }
+  PE->SizeOfInitializedData = getSizeOfInitializedData();
+
+  // Write data directory
+  auto *Dir = reinterpret_cast<data_directory *>(Buf);
+  Buf += sizeof(*Dir) * NumberfOfDataDirectory;
+  if (OutputSection *Sec = findSection(".edata")) {
+    Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (!Idata.empty()) {
+    Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
+    Dir[IMPORT_TABLE].Size = Idata.getDirSize();
+    Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
+    Dir[IAT].Size = Idata.getIATSize();
+  }
+  if (!DelayIdata.empty()) {
+    Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
+        DelayIdata.getDirRVA();
+    Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize();
+  }
+  if (OutputSection *Sec = findSection(".rsrc")) {
+    Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (OutputSection *Sec = findSection(".reloc")) {
+    Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (OutputSection *Sec = findSection(".pdata")) {
+    Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
+    if (Defined *B = dyn_cast<Defined>(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 (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
+    if (auto *B = dyn_cast<DefinedRegular>(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<uint8_t> SecContents = SC->getContents();
+      uint32_t LoadConfigSize =
+          *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]);
+      if (OffsetInChunk + LoadConfigSize > SC->getSize())
+        fatal("_load_config_used is too large");
+      Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
+      Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize;
+    }
+  }
+
+  // Write section table
+  for (OutputSection *Sec : OutputSections) {
+    Sec->writeHeaderTo(Buf);
+    Buf += sizeof(coff_section);
+  }
+
+  if (OutputSymtab.empty())
+    return;
+
+  COFF->PointerToSymbolTable = PointerToSymbolTable;
+  uint32_t NumberOfSymbols = OutputSymtab.size();
+  COFF->NumberOfSymbols = NumberOfSymbols;
+  auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
+      Buffer->getBufferStart() + COFF->PointerToSymbolTable);
+  for (size_t I = 0; I != NumberOfSymbols; ++I)
+    SymbolTable[I] = OutputSymtab[I];
+  // Create the string table, it follows immediately after the symbol table.
+  // The first 4 bytes is length including itself.
+  Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
+  write32le(Buf, Strtab.size() + 4);
+  if (!Strtab.empty())
+    memcpy(Buf + 4, Strtab.data(), Strtab.size());
+}
+
+void Writer::openFile(StringRef Path) {
+  Buffer = check(
+      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable),
+      "failed to open " + Path);
+}
+
+void Writer::fixSafeSEHSymbols() {
+  if (!SEHTable)
+    return;
+  Config->SEHTable->setRVA(SEHTable->getRVA());
+  Config->SEHCount->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() {
+  uint8_t *Buf = Buffer->getBufferStart();
+  for (OutputSection *Sec : OutputSections) {
+    uint8_t *SecBuf = Buf + Sec->getFileOff();
+    // Fill gaps between functions in .text with INT3 instructions
+    // instead of leaving as NUL bytes (which can be interpreted as
+    // ADD instructions).
+    if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
+      memset(SecBuf, 0xCC, Sec->getRawSize());
+    parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(),
+                      [&](Chunk *C) { C->writeTo(SecBuf); });
+  }
+}
+
+// Sort .pdata section contents according to PE/COFF spec 5.5.
+void Writer::sortExceptionTable() {
+  OutputSection *Sec = findSection(".pdata");
+  if (!Sec)
+    return;
+  // We assume .pdata contains function table entries only.
+  uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
+  uint8_t *End = Begin + Sec->getVirtualSize();
+  if (Config->Machine == AMD64) {
+    struct Entry { ulittle32_t Begin, End, Unwind; };
+    parallel_sort(
+        (Entry *)Begin, (Entry *)End,
+        [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+    return;
+  }
+  if (Config->Machine == ARMNT) {
+    struct Entry { ulittle32_t Begin, Unwind; };
+    parallel_sort(
+        (Entry *)Begin, (Entry *)End,
+        [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+    return;
+  }
+  errs() << "warning: don't know how to handle .pdata.\n";
+}
+
+OutputSection *Writer::findSection(StringRef Name) {
+  for (OutputSection *Sec : OutputSections)
+    if (Sec->getName() == Name)
+      return Sec;
+  return nullptr;
+}
+
+uint32_t Writer::getSizeOfInitializedData() {
+  uint32_t Res = 0;
+  for (OutputSection *S : OutputSections)
+    if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+      Res += S->getRawSize();
+  return Res;
+}
+
+// Returns an existing section or create a new one if not found.
+OutputSection *Writer::createSection(StringRef Name) {
+  if (auto *Sec = findSection(Name))
+    return Sec;
+  const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+  const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+  const auto CODE = IMAGE_SCN_CNT_CODE;
+  const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+  const auto R = IMAGE_SCN_MEM_READ;
+  const auto W = IMAGE_SCN_MEM_WRITE;
+  const auto X = IMAGE_SCN_MEM_EXECUTE;
+  uint32_t Perms = StringSwitch<uint32_t>(Name)
+                       .Case(".bss", BSS | R | W)
+                       .Case(".data", DATA | R | W)
+                       .Case(".didat", DATA | R)
+                       .Case(".edata", DATA | R)
+                       .Case(".idata", DATA | R)
+                       .Case(".rdata", DATA | R)
+                       .Case(".reloc", DATA | DISCARDABLE | R)
+                       .Case(".text", CODE | R | X)
+                       .Default(0);
+  if (!Perms)
+    llvm_unreachable("unknown section name");
+  auto Sec = new (CAlloc.Allocate()) OutputSection(Name);
+  Sec->addPermissions(Perms);
+  OutputSections.push_back(Sec);
+  return Sec;
+}
+
+// Dest is .reloc section. Add contents to that section.
+void Writer::addBaserels(OutputSection *Dest) {
+  std::vector<Baserel> 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<Baserel> &V) {
+  const uint32_t Mask = ~uint32_t(PageSize - 1);
+  uint32_t Page = V[0].RVA & Mask;
+  size_t I = 0, J = 1;
+  for (size_t E = V.size(); J < E; ++J) {
+    uint32_t P = V[J].RVA & Mask;
+    if (P == Page)
+      continue;
+    BaserelChunk *Buf = BAlloc.Allocate();
+    Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J));
+    I = J;
+    Page = P;
+  }
+  if (I == J)
+    return;
+  BaserelChunk *Buf = BAlloc.Allocate();
+  Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J));
+}
diff --git a/COFF/Writer.h b/COFF/Writer.h
new file mode 100644 (file)
index 0000000..0473315
--- /dev/null
@@ -0,0 +1,26 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_WRITER_H
+#define LLD_COFF_WRITER_H
+
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class OutputSection;
+
+void writeResult(SymbolTable *T);
+
+}
+}
+
+#endif
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a1b65ad
--- /dev/null
@@ -0,0 +1,50 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ELFOptionsTableGen)
+
+add_lld_library(lldELF
+  Driver.cpp
+  DriverUtils.cpp
+  EhFrame.cpp
+  Error.cpp
+  ICF.cpp
+  InputFiles.cpp
+  InputSection.cpp
+  LTO.cpp
+  LinkerScript.cpp
+  MarkLive.cpp
+  OutputSections.cpp
+  Relocations.cpp
+  ScriptParser.cpp
+  Strings.cpp
+  SymbolListFile.cpp
+  SymbolTable.cpp
+  Symbols.cpp
+  Target.cpp
+  Thunks.cpp
+  Writer.cpp
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  Analysis
+  BitReader
+  BitWriter
+  Codegen
+  Core
+  IPO
+  Linker
+  LTO
+  Object
+  Option
+  Passes
+  MC
+  Support
+  Target
+  TransformUtils
+
+  LINK_LIBS
+  lldConfig
+  ${PTHREAD_LIB}
+  )
+
+add_dependencies(lldELF intrinsics_gen ELFOptionsTableGen)
diff --git a/ELF/Config.h b/ELF/Config.h
new file mode 100644 (file)
index 0000000..2ccd95e
--- /dev/null
@@ -0,0 +1,134 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CONFIG_H
+#define LLD_ELF_CONFIG_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ELF.h"
+
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class InputFile;
+struct Symbol;
+
+enum ELFKind {
+  ELFNoneKind,
+  ELF32LEKind,
+  ELF32BEKind,
+  ELF64LEKind,
+  ELF64BEKind
+};
+
+enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
+
+enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
+
+struct SymbolVersion {
+  llvm::StringRef Name;
+  bool IsExternCpp;
+};
+
+// This struct contains symbols version definition that
+// can be found in version script if it is used for link.
+struct VersionDefinition {
+  VersionDefinition(llvm::StringRef Name, size_t Id) : Name(Name), Id(Id) {}
+  llvm::StringRef Name;
+  size_t Id;
+  std::vector<SymbolVersion> Globals;
+  size_t NameOff; // Offset in string table.
+};
+
+// This struct contains the global configuration for the linker.
+// Most fields are direct mapping from the command line options
+// and such fields have the same name as the corresponding options.
+// Most fields are initialized by the driver.
+struct Configuration {
+  Symbol *EntrySym = nullptr;
+  InputFile *FirstElf = nullptr;
+  llvm::StringRef DynamicLinker;
+  llvm::StringRef Entry;
+  llvm::StringRef Emulation;
+  llvm::StringRef Fini;
+  llvm::StringRef Init;
+  llvm::StringRef LtoAAPipeline;
+  llvm::StringRef LtoNewPmPasses;
+  llvm::StringRef OutputFile;
+  llvm::StringRef SoName;
+  llvm::StringRef Sysroot;
+  std::string RPath;
+  std::vector<VersionDefinition> VersionDefinitions;
+  std::vector<llvm::StringRef> DynamicList;
+  std::vector<llvm::StringRef> SearchPaths;
+  std::vector<llvm::StringRef> Undefined;
+  std::vector<SymbolVersion> VersionScriptGlobals;
+  std::vector<uint8_t> BuildIdVector;
+  bool AllowMultipleDefinition;
+  bool AsNeeded = false;
+  bool Bsymbolic;
+  bool BsymbolicFunctions;
+  bool Demangle = true;
+  bool DisableVerify;
+  bool DiscardAll;
+  bool DiscardLocals;
+  bool DiscardNone;
+  bool EhFrameHdr;
+  bool EnableNewDtags;
+  bool ExportDynamic;
+  bool FatalWarnings;
+  bool GcSections;
+  bool GnuHash = false;
+  bool ICF;
+  bool Mips64EL = false;
+  bool NoGnuUnique;
+  bool NoUndefinedVersion;
+  bool Pic;
+  bool Pie;
+  bool PrintGcSections;
+  bool Rela;
+  bool Relocatable;
+  bool SaveTemps;
+  bool Shared;
+  bool Static = false;
+  bool StripAll;
+  bool StripDebug;
+  bool SysvHash = true;
+  bool Threads;
+  bool Trace;
+  bool Verbose;
+  bool WarnCommon;
+  bool ZCombreloc;
+  bool ZExecStack;
+  bool ZNodelete;
+  bool ZNow;
+  bool ZOrigin;
+  bool ZRelro;
+  UnresolvedPolicy UnresolvedSymbols;
+  BuildIdKind BuildId = BuildIdKind::None;
+  ELFKind EKind = ELFNoneKind;
+  uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
+  uint16_t EMachine = llvm::ELF::EM_NONE;
+  uint64_t EntryAddr = -1;
+  uint64_t ImageBase;
+  unsigned LtoJobs;
+  unsigned LtoO;
+  unsigned Optimize;
+};
+
+// 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 (file)
index 0000000..c6ca263
--- /dev/null
@@ -0,0 +1,588 @@
+//===- 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 "ICF.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Strings.h"
+#include "SymbolListFile.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+Configuration *elf::Config;
+LinkerDriver *elf::Driver;
+
+bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) {
+  HasError = false;
+  ErrorOS = &Error;
+
+  Configuration C;
+  LinkerDriver D;
+  ScriptConfiguration SC;
+  Config = &C;
+  Driver = &D;
+  ScriptConfig = &SC;
+
+  Driver->main(Args);
+  return !HasError;
+}
+
+// Parses a linker -m option.
+static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
+  if (S.endswith("_fbsd"))
+    S = S.drop_back(5);
+
+  std::pair<ELFKind, uint16_t> Ret =
+      StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+          .Case("aarch64linux", {ELF64LEKind, EM_AARCH64})
+          .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
+          .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
+          .Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
+          .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
+          .Case("elf32ppc", {ELF32BEKind, EM_PPC})
+          .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
+          .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+          .Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+          .Case("elf_i386", {ELF32LEKind, EM_386})
+          .Case("elf_x86_64", {ELF64LEKind, EM_X86_64})
+          .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: " + S);
+    else
+      error("unknown emulation: " + S);
+  }
+  return Ret;
+}
+
+// Returns slices of MB by parsing MB as an archive file.
+// Each slice consists of a member file in the archive.
+std::vector<MemoryBufferRef>
+LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
+  std::unique_ptr<Archive> File =
+      check(Archive::create(MB), "failed to parse archive");
+
+  std::vector<MemoryBufferRef> V;
+  Error Err;
+  for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+    Archive::Child C = check(COrErr, "could not get the child of the archive " +
+                                         File->getFileName());
+    MemoryBufferRef MBRef =
+        check(C.getMemoryBufferRef(),
+              "could not get the buffer for a child of the archive " +
+                  File->getFileName());
+    V.push_back(MBRef);
+  }
+  if (Err)
+    Error(Err);
+
+  // Take ownership of memory buffers created for members of thin archives.
+  for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
+    OwningMBs.push_back(std::move(MB));
+
+  return V;
+}
+
+// Opens and parses a file. Path has to be resolved already.
+// Newly created memory buffers are owned by this driver.
+void LinkerDriver::addFile(StringRef Path) {
+  using namespace sys::fs;
+  if (Config->Verbose)
+    outs() << Path << "\n";
+
+  Optional<MemoryBufferRef> Buffer = readFile(Path);
+  if (!Buffer.hasValue())
+    return;
+  MemoryBufferRef MBRef = *Buffer;
+
+  switch (identify_magic(MBRef.getBuffer())) {
+  case file_magic::unknown:
+    readLinkerScript(MBRef);
+    return;
+  case file_magic::archive:
+    if (WholeArchive) {
+      for (MemoryBufferRef MB : getArchiveMembers(MBRef))
+        Files.push_back(createObjectFile(MB, Path));
+      return;
+    }
+    Files.push_back(make_unique<ArchiveFile>(MBRef));
+    return;
+  case file_magic::elf_shared_object:
+    if (Config->Relocatable) {
+      error("attempted static link of dynamic object " + Path);
+      return;
+    }
+    Files.push_back(createSharedFile(MBRef));
+    return;
+  default:
+    if (InLib)
+      Files.push_back(make_unique<LazyObjectFile>(MBRef));
+    else
+      Files.push_back(createObjectFile(MBRef));
+  }
+}
+
+Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
+  auto MBOrErr = MemoryBuffer::getFile(Path);
+  if (auto EC = MBOrErr.getError()) {
+    error(EC, "cannot open " + Path);
+    return None;
+  }
+  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  OwningMBs.push_back(std::move(MB)); // take MB ownership
+
+  if (Cpio)
+    Cpio->append(relativeToRoot(Path), MBRef.getBuffer());
+
+  return MBRef;
+}
+
+// Add a given library by searching it from input search paths.
+void LinkerDriver::addLibrary(StringRef Name) {
+  std::string Path = searchLibrary(Name);
+  if (Path.empty())
+    error("unable to find library -l" + Name);
+  else
+    addFile(Path);
+}
+
+// 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();
+
+  // This is a flag to discard all but GlobalValue names.
+  // We want to enable it by default because it saves memory.
+  // Disable it only when a developer option (-save-temps) is given.
+  Driver->Context.setDiscardValueNames(!Config->SaveTemps);
+  Driver->Context.enableDebugTypeODRUniquing();
+
+  // Parse and evaluate -mllvm options.
+  std::vector<const char *> 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->EMachine == EM_AMDGPU && !Config->Entry.empty())
+    error("-e option is not valid for AMDGPU.");
+
+  if (Config->Pie && Config->Shared)
+    error("-shared and -pie may not be used together");
+
+  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 StringRef
+getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") {
+  if (auto *Arg = Args.getLastArg(Key))
+    return Arg->getValue();
+  return Default;
+}
+
+static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
+  int V = Default;
+  if (auto *Arg = Args.getLastArg(Key)) {
+    StringRef S = Arg->getValue();
+    if (S.getAsInteger(10, V))
+      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;
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
+  ELFOptTable Parser;
+  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+  if (Args.hasArg(OPT_help)) {
+    printHelp(ArgsArr[0]);
+    return;
+  }
+  if (Args.hasArg(OPT_version)) {
+    outs() << getVersionString();
+    return;
+  }
+
+  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.
+    Cpio.reset(CpioFile::create(Path));
+    if (Cpio) {
+      Cpio->append("response.txt", createResponseFile(Args));
+      Cpio->append("version.txt", getVersionString());
+    }
+  }
+
+  readConfigs(Args);
+  initLLVM(Args);
+  createFiles(Args);
+  checkOptions(Args);
+  if (HasError)
+    return;
+
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    link<ELF32LE>(Args);
+    return;
+  case ELF32BEKind:
+    link<ELF32BE>(Args);
+    return;
+  case ELF64LEKind:
+    link<ELF64LE>(Args);
+    return;
+  case ELF64BEKind:
+    link<ELF64BE>(Args);
+    return;
+  default:
+    error("-m or at least a .o file required");
+  }
+}
+
+static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
+  if (Args.hasArg(OPT_noinhibit_exec))
+    return UnresolvedPolicy::Warn;
+  if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"))
+    return UnresolvedPolicy::NoUndef;
+  if (Config->Relocatable)
+    return UnresolvedPolicy::Ignore;
+
+  if (auto *Arg = Args.getLastArg(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 UnresolvedPolicy::Error;
+    error("unknown --unresolved-symbols value: " + S);
+  }
+  return UnresolvedPolicy::Error;
+}
+
+// Initializes Config members by the command line options.
+void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+  for (auto *Arg : Args.filtered(OPT_L))
+    Config->SearchPaths.push_back(Arg->getValue());
+
+  std::vector<StringRef> RPaths;
+  for (auto *Arg : Args.filtered(OPT_rpath))
+    RPaths.push_back(Arg->getValue());
+  if (!RPaths.empty())
+    Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
+
+  if (auto *Arg = Args.getLastArg(OPT_m)) {
+    // Parse ELF{32,64}{LE,BE} and CPU type.
+    StringRef S = Arg->getValue();
+    std::tie(Config->EKind, Config->EMachine) = parseEmulation(S);
+    Config->Emulation = S;
+  }
+
+  Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
+  Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
+  Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+  Config->Demangle = !Args.hasArg(OPT_no_demangle);
+  Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+  Config->DiscardAll = Args.hasArg(OPT_discard_all);
+  Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
+  Config->DiscardNone = Args.hasArg(OPT_discard_none);
+  Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
+  Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
+  Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
+  Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings);
+  Config->GcSections = Args.hasArg(OPT_gc_sections);
+  Config->ICF = Args.hasArg(OPT_icf);
+  Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+  Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
+  Config->Pie = Args.hasArg(OPT_pie);
+  Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+  Config->Relocatable = Args.hasArg(OPT_relocatable);
+  Config->SaveTemps = Args.hasArg(OPT_save_temps);
+  Config->Shared = Args.hasArg(OPT_shared);
+  Config->StripAll = Args.hasArg(OPT_strip_all);
+  Config->StripDebug = Args.hasArg(OPT_strip_debug);
+  Config->Threads = Args.hasArg(OPT_threads);
+  Config->Trace = Args.hasArg(OPT_trace);
+  Config->Verbose = Args.hasArg(OPT_verbose);
+  Config->WarnCommon = Args.hasArg(OPT_warn_common);
+
+  Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
+  Config->Entry = getString(Args, OPT_entry);
+  Config->Fini = getString(Args, OPT_fini, "_fini");
+  Config->Init = getString(Args, OPT_init, "_init");
+  Config->LtoAAPipeline = getString(Args, OPT_lto_aa_pipeline);
+  Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes);
+  Config->OutputFile = getString(Args, OPT_o);
+  Config->SoName = getString(Args, OPT_soname);
+  Config->Sysroot = getString(Args, OPT_sysroot);
+
+  Config->Optimize = getInteger(Args, OPT_O, 1);
+  Config->LtoO = getInteger(Args, OPT_lto_O, 2);
+  if (Config->LtoO > 3)
+    error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
+  Config->LtoJobs = getInteger(Args, OPT_lto_jobs, 1);
+  if (Config->LtoJobs == 0)
+    error("number of threads must be > 0");
+
+  Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
+  Config->ZExecStack = hasZOption(Args, "execstack");
+  Config->ZNodelete = hasZOption(Args, "nodelete");
+  Config->ZNow = hasZOption(Args, "now");
+  Config->ZOrigin = hasZOption(Args, "origin");
+  Config->ZRelro = !hasZOption(Args, "norelro");
+
+  if (Config->Relocatable)
+    Config->StripAll = false;
+
+  // --strip-all implies --strip-debug.
+  if (Config->StripAll)
+    Config->StripDebug = true;
+
+  // Config->Pic is true if we are generating position-independent code.
+  Config->Pic = Config->Pie || Config->Shared;
+
+  if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
+    StringRef S = Arg->getValue();
+    if (S == "gnu") {
+      Config->GnuHash = true;
+      Config->SysvHash = false;
+    } else if (S == "both") {
+      Config->GnuHash = true;
+    } else if (S != "sysv")
+      error("unknown hash style: " + S);
+  }
+
+  // Parse --build-id or --build-id=<style>.
+  if (Args.hasArg(OPT_build_id))
+    Config->BuildId = BuildIdKind::Fnv1;
+  if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
+    StringRef S = Arg->getValue();
+    if (S == "md5") {
+      Config->BuildId = BuildIdKind::Md5;
+    } else if (S == "sha1") {
+      Config->BuildId = BuildIdKind::Sha1;
+    } else if (S == "none") {
+      Config->BuildId = BuildIdKind::None;
+    } else if (S.startswith("0x")) {
+      Config->BuildId = BuildIdKind::Hexstring;
+      Config->BuildIdVector = parseHex(S.substr(2));
+    } else {
+      error("unknown --build-id style: " + S);
+    }
+  }
+
+  for (auto *Arg : Args.filtered(OPT_undefined))
+    Config->Undefined.push_back(Arg->getValue());
+
+  Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+
+  if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      parseDynamicList(*Buffer);
+
+  for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+    Config->DynamicList.push_back(Arg->getValue());
+
+  if (auto *Arg = Args.getLastArg(OPT_version_script))
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      parseVersionScript(*Buffer);
+}
+
+void LinkerDriver::createFiles(opt::InputArgList &Args) {
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_l:
+      addLibrary(Arg->getValue());
+      break;
+    case OPT_alias_script_T:
+    case OPT_INPUT:
+    case OPT_script:
+      addFile(Arg->getValue());
+      break;
+    case OPT_as_needed:
+      Config->AsNeeded = true;
+      break;
+    case OPT_no_as_needed:
+      Config->AsNeeded = false;
+      break;
+    case OPT_Bstatic:
+      Config->Static = true;
+      break;
+    case OPT_Bdynamic:
+      Config->Static = false;
+      break;
+    case OPT_whole_archive:
+      WholeArchive = true;
+      break;
+    case OPT_no_whole_archive:
+      WholeArchive = false;
+      break;
+    case OPT_start_lib:
+      InLib = true;
+      break;
+    case OPT_end_lib:
+      InLib = false;
+      break;
+    }
+  }
+
+  if (Files.empty() && !HasError)
+    error("no input files.");
+
+  // If -m <machine_type> was not given, infer it from object files.
+  if (Config->EKind == ELFNoneKind) {
+    for (std::unique_ptr<InputFile> &F : Files) {
+      if (F->EKind == ELFNoneKind)
+        continue;
+      Config->EKind = F->EKind;
+      Config->EMachine = F->EMachine;
+      break;
+    }
+  }
+}
+
+// Do actual linking. Note that when this function is called,
+// all linker scripts have already been parsed.
+template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
+  SymbolTable<ELFT> Symtab;
+  elf::Symtab<ELFT>::X = &Symtab;
+
+  std::unique_ptr<TargetInfo> TI(createTarget());
+  Target = TI.get();
+  LinkerScript<ELFT> LS;
+  Script<ELFT>::X = &LS;
+
+  Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64;
+  Config->Mips64EL =
+      (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
+
+  // Add entry symbol. Note that AMDGPU binaries have no entry points.
+  if (Config->Entry.empty() && !Config->Shared && !Config->Relocatable &&
+      Config->EMachine != EM_AMDGPU)
+    Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
+
+  // Default output filename is "a.out" by the Unix tradition.
+  if (Config->OutputFile.empty())
+    Config->OutputFile = "a.out";
+
+  // Handle --trace-symbol.
+  for (auto *Arg : Args.filtered(OPT_trace_symbol))
+    Symtab.trace(Arg->getValue());
+
+  // Set either EntryAddr (if S is a number) or EntrySym (otherwise).
+  if (!Config->Entry.empty()) {
+    StringRef S = Config->Entry;
+    if (S.getAsInteger(0, Config->EntryAddr))
+      Config->EntrySym = Symtab.addUndefined(S);
+  }
+
+  // Initialize Config->ImageBase.
+  if (auto *Arg = Args.getLastArg(OPT_image_base)) {
+    StringRef S = Arg->getValue();
+    if (S.getAsInteger(0, Config->ImageBase))
+      error(Arg->getSpelling() + ": number expected, but got " + S);
+    else if ((Config->ImageBase % Target->PageSize) != 0)
+      warning(Arg->getSpelling() + ": address isn't multiple of page size");
+  } else {
+    Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase;
+  }
+
+  for (std::unique_ptr<InputFile> &F : Files)
+    Symtab.addFile(std::move(F));
+  if (HasError)
+    return; // There were duplicate symbols or incompatible files
+
+  Symtab.scanUndefinedFlags();
+  Symtab.scanShlibUndefined();
+  Symtab.scanDynamicList();
+  Symtab.scanVersionScript();
+  Symtab.scanSymbolVersions();
+
+  Symtab.addCombinedLtoObject();
+  if (HasError)
+    return;
+
+  for (auto *Arg : Args.filtered(OPT_wrap))
+    Symtab.wrap(Arg->getValue());
+
+  // Write the result to the file.
+  if (Config->GcSections)
+    markLive<ELFT>();
+  if (Config->ICF)
+    doIcf<ELFT>();
+
+  // MergeInputSection::splitIntoPieces needs to be called before
+  // any call of MergeInputSection::getOffset. Do that.
+  for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+       Symtab.getObjectFiles())
+    for (InputSectionBase<ELFT> *S : F->getSections()) {
+      if (!S || S == &InputSection<ELFT>::Discarded || !S->Live)
+        continue;
+      if (S->Compressed)
+        S->uncompress();
+      if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
+        MS->splitIntoPieces();
+    }
+
+  writeResult<ELFT>(&Symtab);
+}
diff --git a/ELF/Driver.h b/ELF/Driver.h
new file mode 100644 (file)
index 0000000..6b9b9bb
--- /dev/null
@@ -0,0 +1,111 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_DRIVER_H
+#define LLD_ELF_DRIVER_H
+
+#include "SymbolTable.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace elf {
+
+extern class LinkerDriver *Driver;
+
+class CpioFile;
+
+class LinkerDriver {
+public:
+  void main(ArrayRef<const char *> Args);
+  void addFile(StringRef Path);
+  void addLibrary(StringRef Name);
+  llvm::LLVMContext Context;      // to parse bitcode ifles
+  std::unique_ptr<CpioFile> Cpio; // for reproduce
+
+private:
+  std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
+  llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+  void readConfigs(llvm::opt::InputArgList &Args);
+  void createFiles(llvm::opt::InputArgList &Args);
+  template <class ELFT> void link(llvm::opt::InputArgList &Args);
+
+  // True if we are in --whole-archive and --no-whole-archive.
+  bool WholeArchive = false;
+
+  // True if we are in --start-lib and --end-lib.
+  bool InLib = false;
+
+  llvm::BumpPtrAllocator Alloc;
+  std::vector<std::unique_ptr<InputFile>> Files;
+  std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
+};
+
+// Parses command line options.
+class ELFOptTable : public llvm::opt::OptTable {
+public:
+  ELFOptTable();
+  llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
+
+private:
+  llvm::BumpPtrAllocator Alloc;
+};
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+// This is the class to create a .cpio file for --reproduce.
+//
+// If "--reproduce foo" is given, we create a file "foo.cpio" and
+// copy all input files to the archive, along with a response file
+// to re-run the same command with the same inputs.
+// It is useful for reporting issues to LLD developers.
+//
+// Cpio as a file format is a deliberate choice. It's standardized in
+// POSIX and very easy to create. cpio command is available virtually
+// on all Unix systems. See
+// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07
+// for the format details.
+class CpioFile {
+public:
+  static CpioFile *create(StringRef OutputPath);
+  void append(StringRef Path, StringRef Data);
+
+private:
+  CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename);
+
+  std::unique_ptr<llvm::raw_fd_ostream> OS;
+  llvm::StringSet<> Seen;
+  std::string Basename;
+};
+
+void printHelp(const char *Argv0);
+std::string getVersionString();
+std::vector<uint8_t> parseHexstring(StringRef S);
+
+std::string createResponseFile(const llvm::opt::InputArgList &Args);
+std::string relativeToRoot(StringRef Path);
+
+std::string findFromSearchPaths(StringRef Path);
+std::string searchLibrary(StringRef Path);
+std::string buildSysrootedPath(llvm::StringRef Dir, llvm::StringRef File);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
new file mode 100644 (file)
index 0000000..3f18259
--- /dev/null
@@ -0,0 +1,276 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Error.h"
+#include "lld/Config/Version.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const opt::OptTable::Info OptInfo[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)            \
+  {                                                                            \
+    X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP,  \
+        OPT_##ALIAS, X6                                                        \
+  },
+#include "Options.inc"
+#undef OPTION
+};
+
+ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
+  if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
+    StringRef S = Arg->getValue();
+    if (S != "windows" && S != "posix")
+      error("invalid response file quoting: " + S);
+    if (S == "windows")
+      return cl::TokenizeWindowsCommandLine;
+    return cl::TokenizeGNUCommandLine;
+  }
+  if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
+    return cl::TokenizeWindowsCommandLine;
+  return cl::TokenizeGNUCommandLine;
+}
+
+// Parses a given list of options.
+opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
+  // Make InputArgList from string vectors.
+  unsigned MissingIndex;
+  unsigned MissingCount;
+  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+  // We need to get the quoting style for response files before parsing all
+  // options so we parse here before and ignore all the options but
+  // --rsp-quoting.
+  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+  // Expand response files. '@<filename>' is replaced by the file's contents.
+  StringSaver Saver(Alloc);
+  cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+
+  // Parse options and then do error checking.
+  Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+  if (MissingCount)
+    error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
+          "\", expected " + Twine(MissingCount) +
+          (MissingCount == 1 ? " argument.\n" : " arguments"));
+
+  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+    error("unknown argument: " + Arg->getSpelling());
+  return Args;
+}
+
+void elf::printHelp(const char *Argv0) {
+  ELFOptTable Table;
+  Table.PrintHelp(outs(), Argv0, "lld", false);
+}
+
+std::string elf::getVersionString() {
+  std::string Version = getLLDVersion();
+  std::string Repo = getLLDRepositoryVersion();
+  if (Repo.empty())
+    return "LLD " + Version + "\n";
+  return "LLD " + Version + " " + Repo + "\n";
+}
+
+// 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 elf::relativeToRoot(StringRef Path) {
+  SmallString<128> Abs = Path;
+  if (std::error_code EC = fs::make_absolute(Abs))
+    fatal("make_absolute failed: " + EC.message());
+  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 Res.str();
+}
+
+CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
+    : OS(std::move(OS)), Basename(S) {}
+
+CpioFile *CpioFile::create(StringRef OutputPath) {
+  std::string Path = (OutputPath + ".cpio").str();
+  std::error_code EC;
+  auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None);
+  if (EC) {
+    error(EC, "--reproduce: failed to open " + Path);
+    return nullptr;
+  }
+  return new CpioFile(std::move(OS), path::filename(OutputPath));
+}
+
+static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
+  // The c_dev/c_ino pair should be unique according to the spec,
+  // but no one seems to care.
+  OS << "070707";                        // c_magic
+  OS << "000000";                        // c_dev
+  OS << "000000";                        // c_ino
+  OS << "100664";                        // c_mode: C_ISREG | rw-rw-r--
+  OS << "000000";                        // c_uid
+  OS << "000000";                        // c_gid
+  OS << "000001";                        // c_nlink
+  OS << "000000";                        // c_rdev
+  OS << "00000000000";                   // c_mtime
+  OS << format("%06o", Path.size() + 1); // c_namesize
+  OS << format("%011o", Data.size());    // c_filesize
+  OS << Path << '\0';                    // c_name
+  OS << Data;                            // c_filedata
+}
+
+void CpioFile::append(StringRef Path, StringRef Data) {
+  if (!Seen.insert(Path).second)
+    return;
+
+  // Construct an in-archive filename so that /home/foo/bar is stored
+  // as baz/home/foo/bar where baz is the basename of the output file.
+  // (i.e. in that case we are creating baz.cpio.)
+  SmallString<128> Fullpath;
+  path::append(Fullpath, Basename, Path);
+
+  // Use unix path separators so the cpio can be extracted on both unix and
+  // windows.
+  std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/');
+
+  writeMember(*OS, Fullpath, Data);
+
+  // Print the trailer and seek back.
+  // This way we have a valid archive if we crash.
+  uint64_t Pos = OS->tell();
+  writeMember(*OS, "TRAILER!!!", "");
+  OS->seek(Pos);
+}
+
+// Quote a given string if it contains a space character.
+static std::string quote(StringRef S) {
+  if (S.find(' ') == StringRef::npos)
+    return S;
+  return ("\"" + S + "\"").str();
+}
+
+static std::string rewritePath(StringRef S) {
+  if (fs::exists(S))
+    return relativeToRoot(S);
+  return S;
+}
+
+static std::string stringize(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;
+}
+
+// Reconstructs command line arguments so that so that you can re-run
+// the same command with the same inputs. This is for --reproduce.
+std::string elf::createResponseFile(const opt::InputArgList &Args) {
+  SmallString<0> Data;
+  raw_svector_ostream OS(Data);
+
+  // Copy the command line to the output while rewriting paths.
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_reproduce:
+      break;
+    case OPT_INPUT:
+      OS << quote(rewritePath(Arg->getValue())) << "\n";
+      break;
+    case OPT_L:
+    case OPT_dynamic_list:
+    case OPT_rpath:
+    case OPT_alias_script_T:
+    case OPT_script:
+    case OPT_version_script:
+      OS << Arg->getSpelling() << " "
+         << quote(rewritePath(Arg->getValue())) << "\n";
+      break;
+    default:
+      OS << stringize(Arg) << "\n";
+    }
+  }
+  return Data.str();
+}
+
+std::string elf::findFromSearchPaths(StringRef Path) {
+  for (StringRef Dir : Config->SearchPaths) {
+    std::string FullPath = buildSysrootedPath(Dir, Path);
+    if (fs::exists(FullPath))
+      return FullPath;
+  }
+  return "";
+}
+
+// Searches a given library from input search paths, which are filled
+// from -L command line switches. Returns a path to an existent library file.
+std::string elf::searchLibrary(StringRef Path) {
+  if (Path.startswith(":"))
+    return findFromSearchPaths(Path.substr(1));
+  for (StringRef Dir : Config->SearchPaths) {
+    if (!Config->Static) {
+      std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str());
+      if (fs::exists(S))
+        return S;
+    }
+    std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str());
+    if (fs::exists(S))
+      return S;
+  }
+  return "";
+}
+
+// Makes a path by concatenating Dir and File.
+// If Dir starts with '=' the result will be preceded by Sysroot,
+// which can be set with --sysroot command line switch.
+std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) {
+  SmallString<128> Path;
+  if (Dir.startswith("="))
+    path::append(Path, Config->Sysroot, Dir.substr(1), File);
+  else
+    path::append(Path, Dir, File);
+  return Path.str();
+}
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
new file mode 100644 (file)
index 0000000..b130ac1
--- /dev/null
@@ -0,0 +1,167 @@
+//===- EhFrame.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// .eh_frame section contains information on how to unwind the stack when
+// an exception is thrown. The section consists of sequence of CIE and FDE
+// records. The linker needs to merge CIEs and associate FDEs to CIEs.
+// That means the linker has to understand the format of the section.
+//
+// This file contains a few utility functions to read .eh_frame contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EhFrame.h"
+#include "Error.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+// .eh_frame section is a sequence of records. Each record starts with
+// a 4 byte length field. This function reads the length.
+template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> D) {
+  const endianness E = ELFT::TargetEndianness;
+  if (D.size() < 4)
+    fatal("CIE/FDE too small");
+
+  // First 4 bytes of CIE/FDE is the size of the record.
+  // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
+  // but we do not support that format yet.
+  uint64_t V = read32<E>(D.data());
+  if (V == UINT32_MAX)
+    fatal("CIE/FDE too large");
+  uint64_t Size = V + 4;
+  if (Size > D.size())
+    fatal("CIE/FIE ends past the end of the section");
+  return Size;
+}
+
+// Read a byte and advance D by one byte.
+static uint8_t readByte(ArrayRef<uint8_t> &D) {
+  if (D.empty())
+    fatal("corrupted or unsupported CIE information");
+  uint8_t B = D.front();
+  D = D.slice(1);
+  return B;
+}
+
+// Skip an integer encoded in the LEB128 format.
+// Actual number is not of interest because only the runtime needs it.
+// But we need to be at least able to skip it so that we can read
+// the field that follows a LEB128 number.
+static void skipLeb128(ArrayRef<uint8_t> &D) {
+  while (!D.empty()) {
+    uint8_t Val = D.front();
+    D = D.slice(1);
+    if ((Val & 0x80) == 0)
+      return;
+  }
+  fatal("corrupted or unsupported CIE information");
+}
+
+template <class ELFT> static size_t getAugPSize(unsigned Enc) {
+  switch (Enc & 0x0f) {
+  case DW_EH_PE_absptr:
+  case DW_EH_PE_signed:
+    return ELFT::Is64Bits ? 8 : 4;
+  case DW_EH_PE_udata2:
+  case DW_EH_PE_sdata2:
+    return 2;
+  case DW_EH_PE_udata4:
+  case DW_EH_PE_sdata4:
+    return 4;
+  case DW_EH_PE_udata8:
+  case DW_EH_PE_sdata8:
+    return 8;
+  }
+  fatal("unknown FDE encoding");
+}
+
+template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
+  uint8_t Enc = readByte(D);
+  if ((Enc & 0xf0) == DW_EH_PE_aligned)
+    fatal("DW_EH_PE_aligned encoding is not supported");
+  size_t Size = getAugPSize<ELFT>(Enc);
+  if (Size >= D.size())
+    fatal("corrupted CIE");
+  D = D.slice(Size);
+}
+
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> D) {
+  if (D.size() < 8)
+    fatal("CIE too small");
+  D = D.slice(8);
+
+  uint8_t Version = readByte(D);
+  if (Version != 1 && Version != 3)
+    fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
+
+  const unsigned char *AugEnd = std::find(D.begin(), D.end(), '\0');
+  if (AugEnd == D.end())
+    fatal("corrupted CIE");
+  StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin());
+  D = D.slice(Aug.size() + 1);
+
+  // Code alignment factor should always be 1 for .eh_frame.
+  if (readByte(D) != 1)
+    fatal("CIE code alignment must be 1");
+
+  // Skip data alignment factor.
+  skipLeb128(D);
+
+  // Skip the return address register. In CIE version 1 this is a single
+  // byte. In CIE version 3 this is an unsigned LEB128.
+  if (Version == 1)
+    readByte(D);
+  else
+    skipLeb128(D);
+
+  // We only care about an 'R' value, but other records may precede an 'R'
+  // record. Unfortunately records are not in TLV (type-length-value) format,
+  // so we need to teach the linker how to skip records for each type.
+  for (char C : Aug) {
+    if (C == 'R')
+      return readByte(D);
+    if (C == 'z') {
+      skipLeb128(D);
+      continue;
+    }
+    if (C == 'P') {
+      skipAugP<ELFT>(D);
+      continue;
+    }
+    if (C == 'L') {
+      readByte(D);
+      continue;
+    }
+    fatal("unknown .eh_frame augmentation string: " + Aug);
+  }
+  return DW_EH_PE_absptr;
+}
+
+template size_t readEhRecordSize<ELF32LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF32BE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64BE>(ArrayRef<uint8_t>);
+
+template uint8_t getFdeEncoding<ELF32LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF32BE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64BE>(ArrayRef<uint8_t>);
+}
+}
diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h
new file mode 100644 (file)
index 0000000..0d5a2ff
--- /dev/null
@@ -0,0 +1,22 @@
+//===- EhFrame.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_EHFRAME_H
+#define LLD_ELF_EHFRAME_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> Data);
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> Data);
+}
+}
+
+#endif
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
new file mode 100644 (file)
index 0000000..59a49c1
--- /dev/null
@@ -0,0 +1,65 @@
+//===- 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/raw_ostream.h"
+
+using namespace llvm;
+
+namespace lld {
+namespace elf {
+
+bool HasError;
+raw_ostream *ErrorOS;
+
+void log(const Twine &Msg) {
+  if (Config->Verbose)
+    outs() << Msg << "\n";
+}
+
+void warning(const Twine &Msg) {
+  if (Config->FatalWarnings)
+    error(Msg);
+  else
+    *ErrorOS << Msg << "\n";
+}
+
+void error(const Twine &Msg) {
+  *ErrorOS << Msg << "\n";
+  HasError = true;
+}
+
+void error(std::error_code EC, const Twine &Prefix) {
+  error(Prefix + ": " + EC.message());
+}
+
+void fatal(const Twine &Msg) {
+  *ErrorOS << Msg << "\n";
+  exit(1);
+}
+
+void fatal(const Twine &Msg, const Twine &Prefix) {
+  fatal(Prefix + ": " + Msg);
+}
+
+void check(std::error_code EC) {
+  if (EC)
+    fatal(EC.message());
+}
+
+void check(Error Err) {
+  check(errorToErrorCode(std::move(Err)));
+}
+
+} // namespace elf
+} // namespace lld
diff --git a/ELF/Error.h b/ELF/Error.h
new file mode 100644 (file)
index 0000000..552f504
--- /dev/null
@@ -0,0 +1,61 @@
+//===- Error.h --------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_ERROR_H
+#define LLD_COFF_ERROR_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+
+extern bool HasError;
+extern llvm::raw_ostream *ErrorOS;
+
+void log(const Twine &Msg);
+void warning(const Twine &Msg);
+
+void error(const Twine &Msg);
+void error(std::error_code EC, const Twine &Prefix);
+
+template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
+  error(V.getError(), Prefix);
+}
+
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg, const Twine &Prefix);
+
+template <class T> T check(ErrorOr<T> E) {
+  if (auto EC = E.getError())
+    fatal(EC.message());
+  return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E) {
+  if (!E)
+    fatal(errorToErrorCode(E.takeError()).message());
+  return std::move(*E);
+}
+
+template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
+  if (auto EC = E.getError())
+    fatal(EC.message(), Prefix);
+  return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+  if (!E)
+    fatal(errorToErrorCode(E.takeError()).message(), Prefix);
+  return std::move(*E);
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
new file mode 100644 (file)
index 0000000..10a2603
--- /dev/null
@@ -0,0 +1,345 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Identical Code Folding is a feature to merge sections not by name (which
+// is regular comdat handling) but by contents. If two non-writable sections
+// have the same data, relocations, attributes, etc., then the two
+// are considered identical and merged by the linker. This optimization
+// makes outputs smaller.
+//
+// ICF is theoretically a problem of reducing graphs by merging as many
+// identical subgraphs as possible if we consider sections as vertices and
+// relocations as edges. It may sound simple, but it is a bit more
+// complicated than you might think. The order of processing sections
+// matters because merging two sections can make other sections, whose
+// relocations now point to the same section, mergeable. Graphs may contain
+// cycles. We need a sophisticated algorithm to do this properly and
+// efficiently.
+//
+// What we do in this file is this. We split sections into groups. Sections
+// in the same group are considered identical.
+//
+// We begin by optimistically putting all sections into a single equivalence
+// class. Then we apply a series of checks that split this initial
+// equivalence class into more and more refined equivalence classes based on
+// the properties by which a section can be distinguished.
+//
+// We begin by checking that the section contents and flags are the
+// same. This only needs to be done once since these properties don't depend
+// on the current equivalence class assignment.
+//
+// Then we split the equivalence classes based on checking that their
+// relocations are the same, where relocation targets are compared by their
+// equivalence class, not the concrete section. This may need to be done
+// multiple times because as the equivalence classes are refined, two
+// sections that had a relocation target in the same equivalence class may
+// now target different equivalence classes, and hence these two sections
+// must be put in different equivalence classes (whereas in the previous
+// iteration they were not since the relocation target was the same.)
+//
+// Our algorithm is smart enough to merge the following mutually-recursive
+// functions.
+//
+//   void foo() { bar(); }
+//   void bar() { foo(); }
+//
+// This algorithm is so-called "optimistic" algorithm described in
+// http://research.google.com/pubs/pub36912.html. (Note that what GNU
+// gold implemented is different from the optimistic algorithm.)
+//
+//===----------------------------------------------------------------------===//
+
+#include "ICF.h"
+#include "Config.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+namespace lld {
+namespace elf {
+template <class ELFT> class ICF {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+  typedef Elf_Rel_Impl<ELFT, false> Elf_Rel;
+
+  using Comparator = std::function<bool(const InputSection<ELFT> *,
+                                        const InputSection<ELFT> *)>;
+
+public:
+  void run();
+
+private:
+  uint64_t NextId = 1;
+
+  static void setLive(SymbolTable<ELFT> *S);
+  static uint64_t relSize(InputSection<ELFT> *S);
+  static uint64_t getHash(InputSection<ELFT> *S);
+  static bool isEligible(InputSectionBase<ELFT> *Sec);
+  static std::vector<InputSection<ELFT> *> getSections();
+
+  void segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End,
+                 Comparator Eq);
+
+  void forEachGroup(std::vector<InputSection<ELFT> *> &V, Comparator Eq);
+
+  template <class RelTy>
+  static bool relocationEq(ArrayRef<RelTy> RA, ArrayRef<RelTy> RB);
+
+  template <class RelTy>
+  static bool variableEq(const InputSection<ELFT> *A,
+                         const InputSection<ELFT> *B, ArrayRef<RelTy> RA,
+                         ArrayRef<RelTy> RB);
+
+  static bool equalsConstant(const InputSection<ELFT> *A,
+                             const InputSection<ELFT> *B);
+
+  static bool equalsVariable(const InputSection<ELFT> *A,
+                             const InputSection<ELFT> *B);
+};
+}
+}
+
+// Returns a hash value for S. Note that the information about
+// relocation targets is not included in the hash value.
+template <class ELFT> uint64_t ICF<ELFT>::getHash(InputSection<ELFT> *S) {
+  uint64_t Flags = S->getSectionHdr()->sh_flags;
+  uint64_t H = hash_combine(Flags, S->getSize());
+  for (const Elf_Shdr *Rel : S->RelocSections)
+    H = hash_combine(H, (uint64_t)Rel->sh_size);
+  return H;
+}
+
+// Returns true if Sec is subject of ICF.
+template <class ELFT> bool ICF<ELFT>::isEligible(InputSectionBase<ELFT> *Sec) {
+  if (!Sec || Sec == &InputSection<ELFT>::Discarded || !Sec->Live)
+    return false;
+  auto *S = dyn_cast<InputSection<ELFT>>(Sec);
+  if (!S)
+    return false;
+
+  // .init and .fini contains instructions that must be executed to
+  // initialize and finalize the process. They cannot and should not
+  // be merged.
+  StringRef Name = S->getSectionName();
+  if (Name == ".init" || Name == ".fini")
+    return false;
+
+  const Elf_Shdr &H = *S->getSectionHdr();
+  return (H.sh_flags & SHF_ALLOC) && (~H.sh_flags & SHF_WRITE);
+}
+
+template <class ELFT>
+std::vector<InputSection<ELFT> *> ICF<ELFT>::getSections() {
+  std::vector<InputSection<ELFT> *> V;
+  for (const std::unique_ptr<ObjectFile<ELFT>> &F :
+       Symtab<ELFT>::X->getObjectFiles())
+    for (InputSectionBase<ELFT> *S : F->getSections())
+      if (isEligible(S))
+        V.push_back(cast<InputSection<ELFT>>(S));
+  return V;
+}
+
+// All sections between Begin and End must have the same group ID before
+// you call this function. This function compare sections between Begin
+// and End using Eq and assign new group IDs for new groups.
+template <class ELFT>
+void ICF<ELFT>::segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End,
+                          Comparator Eq) {
+  // This loop rearranges [Begin, End) so that all sections that are
+  // equal in terms of Eq are contiguous. The algorithm is quadratic in
+  // the worst case, but that is not an issue in practice because the
+  // number of distinct sections in [Begin, End) is usually very small.
+  InputSection<ELFT> **I = Begin;
+  for (;;) {
+    InputSection<ELFT> *Head = *I;
+    auto Bound = std::stable_partition(
+        I + 1, End, [&](InputSection<ELFT> *S) { return Eq(Head, S); });
+    if (Bound == End)
+      return;
+    uint64_t Id = NextId++;
+    for (; I != Bound; ++I)
+      (*I)->GroupId = Id;
+  }
+}
+
+template <class ELFT>
+void ICF<ELFT>::forEachGroup(std::vector<InputSection<ELFT> *> &V,
+                             Comparator Eq) {
+  for (InputSection<ELFT> **I = V.data(), **E = I + V.size(); I != E;) {
+    InputSection<ELFT> *Head = *I;
+    auto Bound = std::find_if(I + 1, E, [&](InputSection<ELFT> *S) {
+      return S->GroupId != Head->GroupId;
+    });
+    segregate(I, Bound, Eq);
+    I = Bound;
+  }
+}
+
+// Compare two lists of relocations.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::relocationEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
+  const RelTy *IA = RelsA.begin();
+  const RelTy *EA = RelsA.end();
+  const RelTy *IB = RelsB.begin();
+  const RelTy *EB = RelsB.end();
+  if (EA - IA != EB - IB)
+    return false;
+  for (; IA != EA; ++IA, ++IB)
+    if (IA->r_offset != IB->r_offset ||
+        IA->getType(Config->Mips64EL) != IB->getType(Config->Mips64EL) ||
+        getAddend<ELFT>(*IA) != getAddend<ELFT>(*IB))
+      return false;
+  return true;
+}
+
+// Compare "non-moving" part of two InputSections, namely everything
+// except relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A,
+                               const InputSection<ELFT> *B) {
+  if (A->RelocSections.size() != B->RelocSections.size())
+    return false;
+
+  for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) {
+    const Elf_Shdr *RA = A->RelocSections[I];
+    const Elf_Shdr *RB = B->RelocSections[I];
+    ELFFile<ELFT> &FileA = A->File->getObj();
+    ELFFile<ELFT> &FileB = B->File->getObj();
+    if (RA->sh_type == SHT_RELA) {
+      if (!relocationEq(FileA.relas(RA), FileB.relas(RB)))
+        return false;
+    } else {
+      if (!relocationEq(FileA.rels(RA), FileB.rels(RB)))
+        return false;
+    }
+  }
+
+  return A->getSectionHdr()->sh_flags == B->getSectionHdr()->sh_flags &&
+         A->getSize() == B->getSize() &&
+         A->getSectionData() == B->getSectionData();
+}
+
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A,
+                           const InputSection<ELFT> *B, ArrayRef<RelTy> RelsA,
+                           ArrayRef<RelTy> RelsB) {
+  const RelTy *IA = RelsA.begin();
+  const RelTy *EA = RelsA.end();
+  const RelTy *IB = RelsB.begin();
+  for (; IA != EA; ++IA, ++IB) {
+    SymbolBody &SA = A->File->getRelocTargetSym(*IA);
+    SymbolBody &SB = B->File->getRelocTargetSym(*IB);
+    if (&SA == &SB)
+      continue;
+
+    // Or, the symbols should be pointing to the same section
+    // in terms of the group ID.
+    auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
+    auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
+    if (!DA || !DB)
+      return false;
+    if (DA->Value != DB->Value)
+      return false;
+    InputSection<ELFT> *X = dyn_cast<InputSection<ELFT>>(DA->Section);
+    InputSection<ELFT> *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
+    if (X && Y && X->GroupId && X->GroupId == Y->GroupId)
+      continue;
+    return false;
+  }
+  return true;
+}
+
+// Compare "moving" part of two InputSections, namely relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A,
+                               const InputSection<ELFT> *B) {
+  for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) {
+    const Elf_Shdr *RA = A->RelocSections[I];
+    const Elf_Shdr *RB = B->RelocSections[I];
+    ELFFile<ELFT> &FileA = A->File->getObj();
+    ELFFile<ELFT> &FileB = B->File->getObj();
+    if (RA->sh_type == SHT_RELA) {
+      if (!variableEq(A, B, FileA.relas(RA), FileB.relas(RB)))
+        return false;
+    } else {
+      if (!variableEq(A, B, FileA.rels(RA), FileB.rels(RB)))
+        return false;
+    }
+  }
+  return true;
+}
+
+// The main function of ICF.
+template <class ELFT> void ICF<ELFT>::run() {
+  // Initially, we use hash values as section group IDs. Therefore,
+  // if two sections have the same ID, they are likely (but not
+  // guaranteed) to have the same static contents in terms of ICF.
+  std::vector<InputSection<ELFT> *> V = getSections();
+  for (InputSection<ELFT> *S : V)
+    // Set MSB on to avoid collisions with serial group IDs
+    S->GroupId = getHash(S) | (uint64_t(1) << 63);
+
+  // From now on, sections in V are ordered so that sections in
+  // the same group are consecutive in the vector.
+  std::stable_sort(V.begin(), V.end(),
+                   [](InputSection<ELFT> *A, InputSection<ELFT> *B) {
+                     return A->GroupId < B->GroupId;
+                   });
+
+  // Compare static contents and assign unique IDs for each static content.
+  forEachGroup(V, equalsConstant);
+
+  // Split groups by comparing relocations until we get a convergence.
+  int Cnt = 1;
+  for (;;) {
+    ++Cnt;
+    uint64_t Id = NextId;
+    forEachGroup(V, equalsVariable);
+    if (Id == NextId)
+      break;
+  }
+  log("ICF needed " + Twine(Cnt) + " iterations.");
+
+  // Merge sections in the same group.
+  for (auto I = V.begin(), E = V.end(); I != E;) {
+    InputSection<ELFT> *Head = *I++;
+    auto Bound = std::find_if(I, E, [&](InputSection<ELFT> *S) {
+      return Head->GroupId != S->GroupId;
+    });
+    if (I == Bound)
+      continue;
+    log("selected " + Head->getSectionName());
+    while (I != Bound) {
+      InputSection<ELFT> *S = *I++;
+      log("  removed " + S->getSectionName());
+      Head->replace(S);
+    }
+  }
+}
+
+// ICF entry point function.
+template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); }
+
+template void elf::doIcf<ELF32LE>();
+template void elf::doIcf<ELF32BE>();
+template void elf::doIcf<ELF64LE>();
+template void elf::doIcf<ELF64BE>();
diff --git a/ELF/ICF.h b/ELF/ICF.h
new file mode 100644 (file)
index 0000000..502e128
--- /dev/null
+++ b/ELF/ICF.h
@@ -0,0 +1,19 @@
+//===- ICF.h --------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ICF_H
+#define LLD_ELF_ICF_H
+
+namespace lld {
+namespace elf {
+template <class ELFT> void doIcf();
+}
+}
+
+#endif
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
new file mode 100644 (file)
index 0000000..426d9c3
--- /dev/null
@@ -0,0 +1,829 @@
+//===- 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 "Driver.h"
+#include "Error.h"
+#include "InputSection.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys::fs;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string elf::getFilename(const InputFile *F) {
+  if (!F)
+    return "(internal)";
+  if (!F->ArchiveName.empty())
+    return (F->ArchiveName + "(" + F->getName() + ")").str();
+  return F->getName();
+}
+
+template <class ELFT>
+static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) {
+  std::error_code EC;
+  ELFFile<ELFT> F(MB.getBuffer(), EC);
+  if (EC)
+    error(EC, "failed to read " + MB.getBufferIdentifier());
+  return F;
+}
+
+template <class ELFT> static ELFKind getELFKind() {
+  if (ELFT::TargetEndianness == support::little)
+    return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
+  return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+}
+
+template <class ELFT>
+ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB)
+    : InputFile(K, MB), ELFObj(createELFObj<ELFT>(MB)) {
+  EKind = getELFKind<ELFT>();
+  EMachine = ELFObj.getHeader()->e_machine;
+}
+
+template <class ELFT>
+typename ELFT::SymRange ELFFileBase<ELFT>::getElfSymbols(bool OnlyGlobals) {
+  if (!Symtab)
+    return Elf_Sym_Range(nullptr, nullptr);
+  Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
+  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
+  uint32_t FirstNonLocal = Symtab->sh_info;
+  if (FirstNonLocal > NumSymbols)
+    fatal(getFilename(this) + ": invalid sh_info in symbol table");
+
+  if (OnlyGlobals)
+    return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end());
+  return makeArrayRef(Syms.begin(), Syms.end());
+}
+
+template <class ELFT>
+uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
+  uint32_t I = Sym.st_shndx;
+  if (I == ELF::SHN_XINDEX)
+    return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX);
+  if (I >= ELF::SHN_LORESERVE)
+    return 0;
+  return I;
+}
+
+template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
+  if (!Symtab)
+    return;
+  StringTable = check(ELFObj.getStringTableForSymtab(*Symtab));
+}
+
+template <class ELFT>
+elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
+    : ELFFileBase<ELFT>(Base::ObjectKind, M) {}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
+  if (!this->Symtab)
+    return this->SymbolBodies;
+  uint32_t FirstNonLocal = this->Symtab->sh_info;
+  return makeArrayRef(this->SymbolBodies).slice(FirstNonLocal);
+}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
+  if (!this->Symtab)
+    return this->SymbolBodies;
+  uint32_t FirstNonLocal = this->Symtab->sh_info;
+  return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1);
+}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
+  if (!this->Symtab)
+    return this->SymbolBodies;
+  return makeArrayRef(this->SymbolBodies).slice(1);
+}
+
+template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const {
+  if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo)
+    return MipsOptions->Reginfo->ri_gp_value;
+  if (!ELFT::Is64Bits && MipsReginfo && MipsReginfo->Reginfo)
+    return MipsReginfo->Reginfo->ri_gp_value;
+  return 0;
+}
+
+template <class ELFT>
+void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
+  // Read section and symbol tables.
+  initializeSections(ComdatGroups);
+  initializeSymbols();
+}
+
+// Sections with SHT_GROUP and comdat bits define comdat section groups.
+// They are identified and deduplicated by group name. This function
+// returns a group name.
+template <class ELFT>
+StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
+  const ELFFile<ELFT> &Obj = this->ELFObj;
+  const Elf_Shdr *Symtab = check(Obj.getSection(Sec.sh_link));
+  const Elf_Sym *Sym = Obj.getSymbol(Symtab, Sec.sh_info);
+  StringRef Strtab = check(Obj.getStringTableForSymtab(*Symtab));
+  return check(Sym->getName(Strtab));
+}
+
+template <class ELFT>
+ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
+elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
+  const ELFFile<ELFT> &Obj = this->ELFObj;
+  ArrayRef<Elf_Word> Entries =
+      check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
+  if (Entries.empty() || Entries[0] != GRP_COMDAT)
+    fatal(getFilename(this) + ": unsupported SHT_GROUP format");
+  return Entries.slice(1);
+}
+
+template <class ELFT>
+bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
+  // We don't merge sections if -O0 (default is -O1). This makes sometimes
+  // the linker significantly faster, although the output will be bigger.
+  if (Config->Optimize == 0)
+    return false;
+
+  uintX_t Flags = Sec.sh_flags;
+  if (!(Flags & SHF_MERGE))
+    return false;
+  if (Flags & SHF_WRITE)
+    fatal(getFilename(this) + ": writable SHF_MERGE section is not supported");
+  uintX_t EntSize = Sec.sh_entsize;
+  if (!EntSize || Sec.sh_size % EntSize)
+    fatal(getFilename(this) +
+          ": SHF_MERGE section size must be a multiple of sh_entsize");
+
+  // Don't try to merge if the alignment is larger than the sh_entsize and this
+  // is not SHF_STRINGS.
+  //
+  // Since this is not a SHF_STRINGS, we would need to pad after every entity.
+  // It would be equivalent for the producer of the .o to just set a larger
+  // sh_entsize.
+  if (Flags & SHF_STRINGS)
+    return true;
+
+  return Sec.sh_addralign <= EntSize;
+}
+
+template <class ELFT>
+void elf::ObjectFile<ELFT>::initializeSections(
+    DenseSet<StringRef> &ComdatGroups) {
+  uint64_t Size = this->ELFObj.getNumSections();
+  Sections.resize(Size);
+  unsigned I = -1;
+  const ELFFile<ELFT> &Obj = this->ELFObj;
+  for (const Elf_Shdr &Sec : Obj.sections()) {
+    ++I;
+    if (Sections[I] == &InputSection<ELFT>::Discarded)
+      continue;
+
+    switch (Sec.sh_type) {
+    case SHT_GROUP:
+      Sections[I] = &InputSection<ELFT>::Discarded;
+      if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
+        continue;
+      for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
+        if (SecIndex >= Size)
+          fatal(getFilename(this) + ": invalid section index in group: " +
+                Twine(SecIndex));
+        Sections[SecIndex] = &InputSection<ELFT>::Discarded;
+      }
+      break;
+    case SHT_SYMTAB:
+      this->Symtab = &Sec;
+      break;
+    case SHT_SYMTAB_SHNDX:
+      this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
+      break;
+    case SHT_STRTAB:
+    case SHT_NULL:
+      break;
+    case SHT_RELA:
+    case SHT_REL: {
+      // This section contains relocation information.
+      // If -r is given, we do not interpret or apply relocation
+      // but just copy relocation sections to output.
+      if (Config->Relocatable) {
+        Sections[I] = new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
+        break;
+      }
+
+      // Find the relocation target section and associate this
+      // section with it.
+      InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
+      if (!Target)
+        break;
+      if (auto *S = dyn_cast<InputSection<ELFT>>(Target)) {
+        S->RelocSections.push_back(&Sec);
+        break;
+      }
+      if (auto *S = dyn_cast<EhInputSection<ELFT>>(Target)) {
+        if (S->RelocSection)
+          fatal(
+              getFilename(this) +
+              ": multiple relocation sections to .eh_frame are not supported");
+        S->RelocSection = &Sec;
+        break;
+      }
+      fatal(getFilename(this) +
+            ": relocations pointing to SHF_MERGE are not supported");
+    }
+    case SHT_ARM_ATTRIBUTES:
+      // FIXME: ARM meta-data section. At present attributes are ignored,
+      // they can be used to reason about object compatibility.
+      Sections[I] = &InputSection<ELFT>::Discarded;
+      break;
+    default:
+      Sections[I] = createInputSection(Sec);
+    }
+  }
+}
+
+template <class ELFT>
+InputSectionBase<ELFT> *
+elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+  uint32_t Idx = Sec.sh_info;
+  if (Idx >= Sections.size())
+    fatal(getFilename(this) + ": invalid relocated section index: " +
+          Twine(Idx));
+  InputSectionBase<ELFT> *Target = Sections[Idx];
+
+  // Strictly speaking, a relocation section must be included in the
+  // group of the section it relocates. However, LLVM 3.3 and earlier
+  // would fail to do so, so we gracefully handle that case.
+  if (Target == &InputSection<ELFT>::Discarded)
+    return nullptr;
+
+  if (!Target)
+    fatal(getFilename(this) + ": unsupported relocation reference");
+  return Target;
+}
+
+template <class ELFT>
+InputSectionBase<ELFT> *
+elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+  StringRef Name = check(this->ELFObj.getSectionName(&Sec));
+
+  // .note.GNU-stack is a marker section to control the presence of
+  // PT_GNU_STACK segment in outputs. Since the presence of the segment
+  // is controlled only by the command line option (-z execstack) in LLD,
+  // .note.GNU-stack is ignored.
+  if (Name == ".note.GNU-stack")
+    return &InputSection<ELFT>::Discarded;
+
+  if (Name == ".note.GNU-split-stack") {
+    error("objects using splitstacks are not supported");
+    return &InputSection<ELFT>::Discarded;
+  }
+
+  if (Config->StripDebug && Name.startswith(".debug"))
+    return &InputSection<ELFT>::Discarded;
+
+  // A MIPS object file has a special sections that contain register
+  // usage info, which need to be handled by the linker specially.
+  if (Config->EMachine == EM_MIPS) {
+    if (Name == ".reginfo") {
+      MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec));
+      return MipsReginfo.get();
+    }
+    if (Name == ".MIPS.options") {
+      MipsOptions.reset(new MipsOptionsInputSection<ELFT>(this, &Sec));
+      return MipsOptions.get();
+    }
+  }
+
+  // The linker merges EH (exception handling) frames and creates a
+  // .eh_frame_hdr section for runtime. So we handle them with a special
+  // class. For relocatable outputs, they are just passed through.
+  if (Name == ".eh_frame" && !Config->Relocatable)
+    return new (EHAlloc.Allocate()) EhInputSection<ELFT>(this, &Sec);
+
+  if (shouldMerge(Sec))
+    return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
+  return new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
+}
+
+template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
+  this->initStringTable();
+  Elf_Sym_Range Syms = this->getElfSymbols(false);
+  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
+  SymbolBodies.reserve(NumSymbols);
+  for (const Elf_Sym &Sym : Syms)
+    SymbolBodies.push_back(createSymbolBody(&Sym));
+}
+
+template <class ELFT>
+InputSectionBase<ELFT> *
+elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+  uint32_t Index = this->getSectionIndex(Sym);
+  if (Index == 0)
+    return nullptr;
+  if (Index >= Sections.size() || !Sections[Index])
+    fatal(getFilename(this) + ": invalid section index: " + Twine(Index));
+  InputSectionBase<ELFT> *S = Sections[Index];
+  if (S == &InputSectionBase<ELFT>::Discarded)
+    return S;
+  return S->Repl;
+}
+
+template <class ELFT>
+SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+  int Binding = Sym->getBinding();
+  InputSectionBase<ELFT> *Sec = getSection(*Sym);
+  if (Binding == STB_LOCAL) {
+    if (Sym->st_shndx == SHN_UNDEF)
+      return new (this->Alloc)
+          Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this);
+    return new (this->Alloc) DefinedRegular<ELFT>(*Sym, Sec);
+  }
+
+  StringRef Name = check(Sym->getName(this->StringTable));
+
+  switch (Sym->st_shndx) {
+  case SHN_UNDEF:
+    return elf::Symtab<ELFT>::X
+        ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
+                       /*CanOmitFromDynSym*/ false, this)
+        ->body();
+  case SHN_COMMON:
+    return elf::Symtab<ELFT>::X
+        ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other,
+                    Sym->getType(), this)
+        ->body();
+  }
+
+  switch (Binding) {
+  default:
+    fatal(getFilename(this) + ": unexpected binding: " + Twine(Binding));
+  case STB_GLOBAL:
+  case STB_WEAK:
+  case STB_GNU_UNIQUE:
+    if (Sec == &InputSection<ELFT>::Discarded)
+      return elf::Symtab<ELFT>::X
+          ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
+                         /*CanOmitFromDynSym*/ false, this)
+          ->body();
+    return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
+  }
+}
+
+template <class ELFT> void ArchiveFile::parse() {
+  File = check(Archive::create(MB), "failed to parse archive");
+
+  // Read the symbol table to construct Lazy objects.
+  for (const Archive::Symbol &Sym : File->symbols())
+    Symtab<ELFT>::X->addLazyArchive(this, Sym);
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
+  Archive::Child C =
+      check(Sym->getMember(),
+            "could not get the member for symbol " + Sym->getName());
+
+  if (!Seen.insert(C.getChildOffset()).second)
+    return MemoryBufferRef();
+
+  MemoryBufferRef Ret =
+      check(C.getMemoryBufferRef(),
+            "could not get the buffer for the member defining symbol " +
+                Sym->getName());
+
+  if (C.getParent()->isThin() && Driver->Cpio)
+    Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
+                         Ret.getBuffer());
+
+  return Ret;
+}
+
+template <class ELFT>
+SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
+    : ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
+
+template <class ELFT>
+const typename ELFT::Shdr *
+SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+  uint32_t Index = this->getSectionIndex(Sym);
+  if (Index == 0)
+    return nullptr;
+  return check(this->ELFObj.getSection(Index));
+}
+
+// Partially parse the shared object file so that we can call
+// getSoName on this object.
+template <class ELFT> void SharedFile<ELFT>::parseSoName() {
+  typedef typename ELFT::Dyn Elf_Dyn;
+  typedef typename ELFT::uint uintX_t;
+  const Elf_Shdr *DynamicSec = nullptr;
+
+  const ELFFile<ELFT> Obj = this->ELFObj;
+  for (const Elf_Shdr &Sec : Obj.sections()) {
+    switch (Sec.sh_type) {
+    default:
+      continue;
+    case SHT_DYNSYM:
+      this->Symtab = &Sec;
+      break;
+    case SHT_DYNAMIC:
+      DynamicSec = &Sec;
+      break;
+    case SHT_SYMTAB_SHNDX:
+      this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
+      break;
+    case SHT_GNU_versym:
+      this->VersymSec = &Sec;
+      break;
+    case SHT_GNU_verdef:
+      this->VerdefSec = &Sec;
+      break;
+    }
+  }
+
+  this->initStringTable();
+  SoName = sys::path::filename(this->getName());
+
+  if (!DynamicSec)
+    return;
+  auto *Begin =
+      reinterpret_cast<const Elf_Dyn *>(Obj.base() + DynamicSec->sh_offset);
+  const Elf_Dyn *End = Begin + DynamicSec->sh_size / sizeof(Elf_Dyn);
+
+  for (const Elf_Dyn &Dyn : make_range(Begin, End)) {
+    if (Dyn.d_tag == DT_SONAME) {
+      uintX_t Val = Dyn.getVal();
+      if (Val >= this->StringTable.size())
+        fatal(getFilename(this) + ": invalid DT_SONAME entry");
+      SoName = StringRef(this->StringTable.data() + Val);
+      return;
+    }
+  }
+}
+
+// Parse the version definitions in the object file if present. Returns a vector
+// whose nth element contains a pointer to the Elf_Verdef for version identifier
+// n. Version identifiers that are not definitions map to nullptr. The array
+// always has at least length 1.
+template <class ELFT>
+std::vector<const typename ELFT::Verdef *>
+SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
+  std::vector<const Elf_Verdef *> Verdefs(1);
+  // We only need to process symbol versions for this DSO if it has both a
+  // versym and a verdef section, which indicates that the DSO contains symbol
+  // version definitions.
+  if (!VersymSec || !VerdefSec)
+    return Verdefs;
+
+  // The location of the first global versym entry.
+  Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() +
+                                                VersymSec->sh_offset) +
+           this->Symtab->sh_info;
+
+  // We cannot determine the largest verdef identifier without inspecting
+  // every Elf_Verdef, but both bfd and gold assign verdef identifiers
+  // sequentially starting from 1, so we predict that the largest identifier
+  // will be VerdefCount.
+  unsigned VerdefCount = VerdefSec->sh_info;
+  Verdefs.resize(VerdefCount + 1);
+
+  // Build the Verdefs array by following the chain of Elf_Verdef objects
+  // from the start of the .gnu.version_d section.
+  const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset;
+  for (unsigned I = 0; I != VerdefCount; ++I) {
+    auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
+    Verdef += CurVerdef->vd_next;
+    unsigned VerdefIndex = CurVerdef->vd_ndx;
+    if (Verdefs.size() <= VerdefIndex)
+      Verdefs.resize(VerdefIndex + 1);
+    Verdefs[VerdefIndex] = CurVerdef;
+  }
+
+  return Verdefs;
+}
+
+// Fully parse the shared object file. This must be called after parseSoName().
+template <class ELFT> void SharedFile<ELFT>::parseRest() {
+  // Create mapping from version identifiers to Elf_Verdef entries.
+  const Elf_Versym *Versym = nullptr;
+  std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
+
+  Elf_Sym_Range Syms = this->getElfSymbols(true);
+  for (const Elf_Sym &Sym : Syms) {
+    unsigned VersymIndex = 0;
+    if (Versym) {
+      VersymIndex = Versym->vs_index;
+      ++Versym;
+    }
+
+    StringRef Name = check(Sym.getName(this->StringTable));
+    if (Sym.isUndefined()) {
+      Undefs.push_back(Name);
+      continue;
+    }
+
+    if (Versym) {
+      // Ignore local symbols and non-default versions.
+      if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN))
+        continue;
+    }
+
+    const Elf_Verdef *V =
+        VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
+    elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+  }
+}
+
+static ELFKind getELFKind(MemoryBufferRef MB) {
+  std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context);
+  Triple TheTriple(TripleStr);
+  bool Is64Bits = TheTriple.isArch64Bit();
+  if (TheTriple.isLittleEndian())
+    return Is64Bits ? ELF64LEKind : ELF32LEKind;
+  return Is64Bits ? ELF64BEKind : ELF32BEKind;
+}
+
+static uint8_t getMachineKind(MemoryBufferRef MB) {
+  std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context);
+  switch (Triple(TripleStr).getArch()) {
+  case Triple::aarch64:
+    return EM_AARCH64;
+  case Triple::arm:
+    return EM_ARM;
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
+    return EM_MIPS;
+  case Triple::ppc:
+    return EM_PPC;
+  case Triple::ppc64:
+    return EM_PPC64;
+  case Triple::x86:
+    return EM_386;
+  case Triple::x86_64:
+    return EM_X86_64;
+  default:
+    fatal(MB.getBufferIdentifier() +
+          ": could not infer e_machine from bitcode target triple " +
+          TripleStr);
+  }
+}
+
+BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
+  EKind = getELFKind(MB);
+  EMachine = getMachineKind(MB);
+}
+
+static uint8_t getGvVisibility(const GlobalValue *GV) {
+  switch (GV->getVisibility()) {
+  case GlobalValue::DefaultVisibility:
+    return STV_DEFAULT;
+  case GlobalValue::HiddenVisibility:
+    return STV_HIDDEN;
+  case GlobalValue::ProtectedVisibility:
+    return STV_PROTECTED;
+  }
+  llvm_unreachable("unknown visibility");
+}
+
+template <class ELFT>
+Symbol *BitcodeFile::createSymbol(const DenseSet<const Comdat *> &KeptComdats,
+                                  const IRObjectFile &Obj,
+                                  const BasicSymbolRef &Sym) {
+  const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl());
+
+  SmallString<64> Name;
+  raw_svector_ostream OS(Name);
+  Sym.printName(OS);
+  StringRef NameRef = Saver.save(StringRef(Name));
+
+  uint32_t Flags = Sym.getFlags();
+  bool IsWeak = Flags & BasicSymbolRef::SF_Weak;
+  uint32_t Binding = IsWeak ? STB_WEAK : STB_GLOBAL;
+
+  uint8_t Type = STT_NOTYPE;
+  bool CanOmitFromDynSym = false;
+  // FIXME: Expose a thread-local flag for module asm symbols.
+  if (GV) {
+    if (GV->isThreadLocal())
+      Type = STT_TLS;
+    CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
+  }
+
+  uint8_t Visibility;
+  if (GV)
+    Visibility = getGvVisibility(GV);
+  else
+    // FIXME: Set SF_Hidden flag correctly for module asm symbols, and expose
+    // protected visibility.
+    Visibility = STV_DEFAULT;
+
+  if (GV)
+    if (const Comdat *C = GV->getComdat())
+      if (!KeptComdats.count(C))
+        return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
+                                             CanOmitFromDynSym, this);
+
+  const Module &M = Obj.getModule();
+  if (Flags & BasicSymbolRef::SF_Undefined)
+    return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
+                                         CanOmitFromDynSym, this);
+  if (Flags & BasicSymbolRef::SF_Common) {
+    // FIXME: Set SF_Common flag correctly for module asm symbols, and expose
+    // size and alignment.
+    assert(GV);
+    const DataLayout &DL = M.getDataLayout();
+    uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
+    return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(),
+                                      Binding, Visibility, STT_OBJECT, this);
+  }
+  return Symtab<ELFT>::X->addBitcode(NameRef, IsWeak, Visibility, Type,
+                                     CanOmitFromDynSym, this);
+}
+
+bool BitcodeFile::shouldSkip(uint32_t Flags) {
+  return !(Flags & BasicSymbolRef::SF_Global) ||
+         (Flags & BasicSymbolRef::SF_FormatSpecific);
+}
+
+template <class ELFT>
+void BitcodeFile::parse(DenseSet<StringRef> &ComdatGroups) {
+  Obj = check(IRObjectFile::create(MB, Driver->Context));
+  const Module &M = Obj->getModule();
+
+  DenseSet<const Comdat *> KeptComdats;
+  for (const auto &P : M.getComdatSymbolTable()) {
+    StringRef N = Saver.save(P.first());
+    if (ComdatGroups.insert(N).second)
+      KeptComdats.insert(&P.second);
+  }
+
+  for (const BasicSymbolRef &Sym : Obj->symbols())
+    if (!shouldSkip(Sym.getFlags()))
+      Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym));
+}
+
+template <template <class> class T>
+static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) {
+  unsigned char Size;
+  unsigned char Endian;
+  std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+  if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
+    fatal("invalid data encoding: " + MB.getBufferIdentifier());
+
+  std::unique_ptr<InputFile> Obj;
+  if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
+    Obj.reset(new T<ELF32LE>(MB));
+  else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
+    Obj.reset(new T<ELF32BE>(MB));
+  else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
+    Obj.reset(new T<ELF64LE>(MB));
+  else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
+    Obj.reset(new T<ELF64BE>(MB));
+  else
+    fatal("invalid file class: " + MB.getBufferIdentifier());
+
+  if (!Config->FirstElf)
+    Config->FirstElf = Obj.get();
+  return Obj;
+}
+
+static bool isBitcode(MemoryBufferRef MB) {
+  using namespace sys::fs;
+  return identify_magic(MB.getBuffer()) == file_magic::bitcode;
+}
+
+std::unique_ptr<InputFile> elf::createObjectFile(MemoryBufferRef MB,
+                                                 StringRef ArchiveName) {
+  std::unique_ptr<InputFile> F;
+  if (isBitcode(MB))
+    F.reset(new BitcodeFile(MB));
+  else
+    F = createELFFile<ObjectFile>(MB);
+  F->ArchiveName = ArchiveName;
+  return F;
+}
+
+std::unique_ptr<InputFile> elf::createSharedFile(MemoryBufferRef MB) {
+  return createELFFile<SharedFile>(MB);
+}
+
+MemoryBufferRef LazyObjectFile::getBuffer() {
+  if (Seen)
+    return MemoryBufferRef();
+  Seen = true;
+  return MB;
+}
+
+template <class ELFT>
+void LazyObjectFile::parse() {
+  for (StringRef Sym : getSymbols())
+    Symtab<ELFT>::X->addLazyObject(Sym, *this);
+}
+
+template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+
+  const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
+  for (const Elf_Shdr &Sec : Obj.sections()) {
+    if (Sec.sh_type != SHT_SYMTAB)
+      continue;
+    Elf_Sym_Range Syms = Obj.symbols(&Sec);
+    uint32_t FirstNonLocal = Sec.sh_info;
+    StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
+    std::vector<StringRef> V;
+    for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+      if (Sym.st_shndx != SHN_UNDEF)
+        V.push_back(check(Sym.getName(StringTable)));
+    return V;
+  }
+  return {};
+}
+
+std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+  LLVMContext Context;
+  std::unique_ptr<IRObjectFile> Obj =
+      check(IRObjectFile::create(this->MB, Context));
+  std::vector<StringRef> V;
+  for (const BasicSymbolRef &Sym : Obj->symbols()) {
+    uint32_t Flags = Sym.getFlags();
+    if (BitcodeFile::shouldSkip(Flags))
+      continue;
+    if (Flags & BasicSymbolRef::SF_Undefined)
+      continue;
+    SmallString<64> Name;
+    raw_svector_ostream OS(Name);
+    Sym.printName(OS);
+    V.push_back(Saver.save(StringRef(Name)));
+  }
+  return V;
+}
+
+// Returns a vector of globally-visible defined symbol names.
+std::vector<StringRef> LazyObjectFile::getSymbols() {
+  if (isBitcode(this->MB))
+    return getBitcodeSymbols();
+
+  unsigned char Size;
+  unsigned char Endian;
+  std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer());
+  if (Size == ELFCLASS32) {
+    if (Endian == ELFDATA2LSB)
+      return getElfSymbols<ELF32LE>();
+    return getElfSymbols<ELF32BE>();
+  }
+  if (Endian == ELFDATA2LSB)
+    return getElfSymbols<ELF64LE>();
+  return getElfSymbols<ELF64BE>();
+}
+
+template void ArchiveFile::parse<ELF32LE>();
+template void ArchiveFile::parse<ELF32BE>();
+template void ArchiveFile::parse<ELF64LE>();
+template void ArchiveFile::parse<ELF64BE>();
+
+template void BitcodeFile::parse<ELF32LE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF32BE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF64LE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF64BE>(DenseSet<StringRef> &);
+
+template void LazyObjectFile::parse<ELF32LE>();
+template void LazyObjectFile::parse<ELF32BE>();
+template void LazyObjectFile::parse<ELF64LE>();
+template void LazyObjectFile::parse<ELF64BE>();
+
+template class elf::ELFFileBase<ELF32LE>;
+template class elf::ELFFileBase<ELF32BE>;
+template class elf::ELFFileBase<ELF64LE>;
+template class elf::ELFFileBase<ELF64BE>;
+
+template class elf::ObjectFile<ELF32LE>;
+template class elf::ObjectFile<ELF32BE>;
+template class elf::ObjectFile<ELF64LE>;
+template class elf::ObjectFile<ELF64BE>;
+
+template class elf::SharedFile<ELF32LE>;
+template class elf::SharedFile<ELF32BE>;
+template class elf::SharedFile<ELF64LE>;
+template class elf::SharedFile<ELF64BE>;
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
new file mode 100644 (file)
index 0000000..79cb751
--- /dev/null
@@ -0,0 +1,304 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_FILES_H
+#define LLD_ELF_INPUT_FILES_H
+
+#include "Config.h"
+#include "InputSection.h"
+#include "Error.h"
+#include "Symbols.h"
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Comdat.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/StringSaver.h"
+
+#include <map>
+
+namespace lld {
+namespace elf {
+
+using llvm::object::Archive;
+
+class InputFile;
+class Lazy;
+class SymbolBody;
+
+// The root class of input files.
+class InputFile {
+public:
+  enum Kind {
+    ObjectKind,
+    SharedKind,
+    LazyObjectKind,
+    ArchiveKind,
+    BitcodeKind,
+  };
+
+  Kind kind() const { return FileKind; }
+
+  StringRef getName() const { return MB.getBufferIdentifier(); }
+  MemoryBufferRef MB;
+
+  // Filename of .a which contained this file. If this file was
+  // not in an archive file, it is the empty string. We use this
+  // string for creating error messages.
+  StringRef ArchiveName;
+
+  // If this is an architecture-specific file, the following members
+  // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
+  ELFKind EKind = ELFNoneKind;
+  uint16_t EMachine = llvm::ELF::EM_NONE;
+
+protected:
+  InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
+private:
+  const Kind FileKind;
+};
+
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string getFilename(const InputFile *F);
+
+template <typename ELFT> class ELFFileBase : public InputFile {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Word Elf_Word;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+
+  ELFFileBase(Kind K, MemoryBufferRef M);
+  static bool classof(const InputFile *F) {
+    Kind K = F->kind();
+    return K == ObjectKind || K == SharedKind;
+  }
+
+  const llvm::object::ELFFile<ELFT> &getObj() const { return ELFObj; }
+  llvm::object::ELFFile<ELFT> &getObj() { return ELFObj; }
+
+  uint8_t getOSABI() const {
+    return getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
+  }
+
+  StringRef getStringTable() const { return StringTable; }
+
+  uint32_t getSectionIndex(const Elf_Sym &Sym) const;
+
+  Elf_Sym_Range getElfSymbols(bool OnlyGlobals);
+
+protected:
+  llvm::object::ELFFile<ELFT> ELFObj;
+  const Elf_Shdr *Symtab = nullptr;
+  ArrayRef<Elf_Word> SymtabSHNDX;
+  StringRef StringTable;
+  void initStringTable();
+};
+
+// .o file.
+template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
+  typedef ELFFileBase<ELFT> Base;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::Word Elf_Word;
+  typedef typename ELFT::uint uintX_t;
+
+  StringRef getShtGroupSignature(const Elf_Shdr &Sec);
+  ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
+
+public:
+  static bool classof(const InputFile *F) {
+    return F->kind() == Base::ObjectKind;
+  }
+
+  ArrayRef<SymbolBody *> getSymbols();
+  ArrayRef<SymbolBody *> getLocalSymbols();
+  ArrayRef<SymbolBody *> getNonLocalSymbols();
+
+  explicit ObjectFile(MemoryBufferRef M);
+  void parse(llvm::DenseSet<StringRef> &ComdatGroups);
+
+  ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
+  InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
+
+  SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
+    return *SymbolBodies[SymbolIndex];
+  }
+
+  template <typename RelT> SymbolBody &getRelocTargetSym(const RelT &Rel) const {
+    uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
+    return getSymbolBody(SymIndex);
+  }
+
+  const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
+
+  // Get MIPS GP0 value defined by this file. This value represents the gp value
+  // used to create the relocatable object and required to support
+  // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
+  uint32_t getMipsGp0() const;
+
+  // The number is the offset in the string table. It will be used as the
+  // st_name of the symbol.
+  std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms;
+
+  // SymbolBodies and Thunks for sections in this file are allocated
+  // using this buffer.
+  llvm::BumpPtrAllocator Alloc;
+
+private:
+  void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
+  void initializeSymbols();
+  InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
+  InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec);
+
+  bool shouldMerge(const Elf_Shdr &Sec);
+  SymbolBody *createSymbolBody(const Elf_Sym *Sym);
+
+  // List of all sections defined by this file.
+  std::vector<InputSectionBase<ELFT> *> Sections;
+
+  // List of all symbols referenced or defined by this file.
+  std::vector<SymbolBody *> SymbolBodies;
+
+  // MIPS .reginfo section defined by this file.
+  std::unique_ptr<MipsReginfoInputSection<ELFT>> MipsReginfo;
+  // MIPS .MIPS.options section defined by this file.
+  std::unique_ptr<MipsOptionsInputSection<ELFT>> MipsOptions;
+
+  llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc;
+  llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
+  llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc;
+};
+
+// LazyObjectFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjectFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjectFile : public InputFile {
+public:
+  explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
+
+  static bool classof(const InputFile *F) {
+    return F->kind() == LazyObjectKind;
+  }
+
+  template <class ELFT> void parse();
+  MemoryBufferRef getBuffer();
+
+private:
+  std::vector<StringRef> getSymbols();
+  template <class ELFT> std::vector<StringRef> getElfSymbols();
+  std::vector<StringRef> getBitcodeSymbols();
+
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver{Alloc};
+  bool Seen = false;
+};
+
+// An ArchiveFile object represents a .a file.
+class ArchiveFile : public InputFile {
+public:
+  explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+  template <class ELFT> void parse();
+
+  // Returns a memory buffer for a given symbol. An empty memory buffer
+  // is returned if we have already returned the same memory buffer.
+  // (So that we don't instantiate same members more than once.)
+  MemoryBufferRef getMember(const Archive::Symbol *Sym);
+
+private:
+  std::unique_ptr<Archive> File;
+  llvm::DenseSet<uint64_t> Seen;
+};
+
+class BitcodeFile : public InputFile {
+public:
+  explicit BitcodeFile(MemoryBufferRef M);
+  static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+  template <class ELFT>
+  void parse(llvm::DenseSet<StringRef> &ComdatGroups);
+  ArrayRef<Symbol *> getSymbols() { return Symbols; }
+  static bool shouldSkip(uint32_t Flags);
+  std::unique_ptr<llvm::object::IRObjectFile> Obj;
+
+private:
+  std::vector<Symbol *> Symbols;
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver{Alloc};
+  template <class ELFT>
+  Symbol *createSymbol(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
+                       const llvm::object::IRObjectFile &Obj,
+                       const llvm::object::BasicSymbolRef &Sym);
+};
+
+// .so file.
+template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
+  typedef ELFFileBase<ELFT> Base;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Word Elf_Word;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::Versym Elf_Versym;
+  typedef typename ELFT::Verdef Elf_Verdef;
+
+  std::vector<StringRef> Undefs;
+  StringRef SoName;
+  const Elf_Shdr *VersymSec = nullptr;
+  const Elf_Shdr *VerdefSec = nullptr;
+
+public:
+  StringRef getSoName() const { return SoName; }
+  const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
+  llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
+
+  static bool classof(const InputFile *F) {
+    return F->kind() == Base::SharedKind;
+  }
+
+  explicit SharedFile(MemoryBufferRef M);
+
+  void parseSoName();
+  void parseRest();
+  std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+
+  struct NeededVer {
+    // The string table offset of the version name in the output file.
+    size_t StrTab;
+
+    // The version identifier for this version name.
+    uint16_t Index;
+  };
+
+  // Mapping from Elf_Verdef data structures to information about Elf_Vernaux
+  // data structures in the output file.
+  std::map<const Elf_Verdef *, NeededVer> VerdefMap;
+
+  // Used for --as-needed
+  bool AsNeeded = false;
+  bool IsUsed = false;
+  bool isNeeded() const { return !AsNeeded || IsUsed; }
+};
+
+std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB,
+                                            StringRef ArchiveName = "");
+std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
new file mode 100644 (file)
index 0000000..6564e79
--- /dev/null
@@ -0,0 +1,691 @@
+//===- InputSection.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSection.h"
+#include "Config.h"
+#include "EhFrame.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Target.h"
+#include "Thunks.h"
+
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT> bool elf::isDiscarded(InputSectionBase<ELFT> *S) {
+  return !S || S == &InputSection<ELFT>::Discarded || !S->Live ||
+         Script<ELFT>::X->isDiscarded(S);
+}
+
+template <class ELFT>
+InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
+                                         const Elf_Shdr *Header,
+                                         Kind SectionKind)
+    : Header(Header), File(File), SectionKind(SectionKind), Repl(this),
+      Compressed(Header->sh_flags & SHF_COMPRESSED) {
+  // The garbage collector sets sections' Live bits.
+  // If GC is disabled, all sections are considered live by default.
+  Live = !Config->GcSections;
+
+  // The ELF spec states that a value of 0 means the section has
+  // no alignment constraits.
+  Alignment = std::max<uintX_t>(Header->sh_addralign, 1);
+}
+
+template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
+  if (auto *D = dyn_cast<InputSection<ELFT>>(this))
+    if (D->getThunksSize() > 0)
+      return D->getThunkOff() + D->getThunksSize();
+  return Header->sh_size;
+}
+
+template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
+  return check(File->getObj().getSectionName(this->Header));
+}
+
+template <class ELFT>
+ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
+  if (Compressed)
+    return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(),
+                             Uncompressed.size());
+  return check(this->File->getObj().getSectionContents(this->Header));
+}
+
+template <class ELFT>
+typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
+  switch (SectionKind) {
+  case Regular:
+    return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
+  case EHFrame:
+    return cast<EhInputSection<ELFT>>(this)->getOffset(Offset);
+  case Merge:
+    return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
+  case MipsReginfo:
+  case MipsOptions:
+    // MIPS .reginfo and .MIPS.options sections are consumed by the linker,
+    // and the linker produces a single output section. It is possible that
+    // input files contain section symbol points to the corresponding input
+    // section. Redirect it to the produced output section.
+    if (Offset != 0)
+      fatal("Unsupported reference to the middle of '" + getSectionName() +
+            "' section");
+    return this->OutSec->getVA();
+  }
+  llvm_unreachable("invalid section kind");
+}
+
+template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
+  if (!zlib::isAvailable())
+    fatal("build lld with zlib to enable compressed sections support");
+
+  // A compressed section consists of a header of Elf_Chdr type
+  // followed by compressed data.
+  ArrayRef<uint8_t> Data =
+      check(this->File->getObj().getSectionContents(this->Header));
+  if (Data.size() < sizeof(Elf_Chdr))
+    fatal("corrupt compressed section");
+
+  auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data());
+  Data = Data.slice(sizeof(Elf_Chdr));
+
+  if (Hdr->ch_type != ELFCOMPRESS_ZLIB)
+    fatal("unsupported compression type");
+
+  StringRef Buf((const char *)Data.data(), Data.size());
+  if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK)
+    fatal("error uncompressing section");
+}
+
+template <class ELFT>
+typename ELFT::uint
+InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
+  return getOffset(Sym.Value);
+}
+
+template <class ELFT>
+InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
+                                 const Elf_Shdr *Header)
+    : InputSectionBase<ELFT>(F, Header, Base::Regular) {}
+
+template <class ELFT>
+bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == Base::Regular;
+}
+
+template <class ELFT>
+InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
+  assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
+  ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
+  return Sections[this->Header->sh_info];
+}
+
+template <class ELFT>
+void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
+  Thunks.push_back(T);
+}
+
+template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
+  return this->Header->sh_size;
+}
+
+template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
+  uint64_t Total = 0;
+  for (const Thunk<ELFT> *T : Thunks)
+    Total += T->size();
+  return Total;
+}
+
+// This is used for -r. We can't use memcpy to copy relocations because we need
+// to update symbol table offset and section index for each relocation. So we
+// copy relocations one by one.
+template <class ELFT>
+template <class RelTy>
+void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+  InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
+
+  for (const RelTy &Rel : Rels) {
+    uint32_t Type = Rel.getType(Config->Mips64EL);
+    SymbolBody &Body = this->File->getRelocTargetSym(Rel);
+
+    RelTy *P = reinterpret_cast<RelTy *>(Buf);
+    Buf += sizeof(RelTy);
+
+    P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
+    P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL);
+  }
+}
+
+// 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.)
+static uint64_t getAArch64Page(uint64_t Expr) {
+  return Expr & (~static_cast<uint64_t>(0xFFF));
+}
+
+template <class ELFT>
+static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
+                                    typename ELFT::uint P,
+                                    const SymbolBody &Body, RelExpr Expr) {
+  typedef typename ELFT::uint uintX_t;
+
+  switch (Expr) {
+  case R_HINT:
+    llvm_unreachable("cannot relocate hint relocs");
+  case R_TLSLD:
+    return Out<ELFT>::Got->getTlsIndexOff() + A -
+           Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+  case R_TLSLD_PC:
+    return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+  case R_THUNK_ABS:
+    return Body.getThunkVA<ELFT>() + A;
+  case R_THUNK_PC:
+  case R_THUNK_PLT_PC:
+    return Body.getThunkVA<ELFT>() + A - P;
+  case R_PPC_TOC:
+    return getPPC64TocBase() + A;
+  case R_TLSGD:
+    return Out<ELFT>::Got->getGlobalDynOffset(Body) + A -
+           Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+  case R_TLSGD_PC:
+    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+  case R_TLSDESC:
+    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+  case R_TLSDESC_PAGE:
+    return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+           getAArch64Page(P);
+  case R_PLT:
+    return Body.getPltVA<ELFT>() + A;
+  case R_PLT_PC:
+  case R_PPC_PLT_OPD:
+    return Body.getPltVA<ELFT>() + A - P;
+  case R_SIZE:
+    return Body.getSize<ELFT>() + A;
+  case R_GOTREL:
+    return Body.getVA<ELFT>(A) - Out<ELFT>::Got->getVA();
+  case R_RELAX_TLS_GD_TO_IE_END:
+  case R_GOT_FROM_END:
+    return Body.getGotOffset<ELFT>() + A -
+           Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+  case R_RELAX_TLS_GD_TO_IE_ABS:
+  case R_GOT:
+    return Body.getGotVA<ELFT>() + A;
+  case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+  case R_GOT_PAGE_PC:
+    return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+  case R_RELAX_TLS_GD_TO_IE:
+  case R_GOT_PC:
+    return Body.getGotVA<ELFT>() + A - P;
+  case R_GOTONLY_PC:
+    return Out<ELFT>::Got->getVA() + A - P;
+  case R_RELAX_TLS_LD_TO_LE:
+  case R_RELAX_TLS_IE_TO_LE:
+  case R_RELAX_TLS_GD_TO_LE:
+  case R_TLS:
+    if (Target->TcbSize)
+      return Body.getVA<ELFT>(A) +
+             alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
+    return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz;
+  case R_RELAX_TLS_GD_TO_LE_NEG:
+  case R_NEG_TLS:
+    return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A);
+  case R_ABS:
+  case R_RELAX_GOT_PC_NOPIC:
+    return Body.getVA<ELFT>(A);
+  case R_GOT_OFF:
+    return Body.getGotOffset<ELFT>() + A;
+  case R_MIPS_GOT_LOCAL_PAGE:
+    // If relocation against MIPS local symbol requires GOT entry, this entry
+    // should be initialized by 'page address'. This address is high 16-bits
+    // of sum the symbol's value and the addend.
+    return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
+  case R_MIPS_GOT_OFF:
+    // In case of MIPS if a GOT relocation has non-zero addend this addend
+    // should be applied to the GOT entry content not to the GOT entry offset.
+    // That is why we use separate expression type.
+    return Out<ELFT>::Got->getMipsGotOffset(Body, A);
+  case R_MIPS_TLSGD:
+    return Out<ELFT>::Got->getGlobalDynOffset(Body) +
+           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+  case R_MIPS_TLSLD:
+    return Out<ELFT>::Got->getTlsIndexOff() +
+           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+  case R_PPC_OPD: {
+    uint64_t SymVA = Body.getVA<ELFT>(A);
+    // If we have an undefined weak symbol, we might get here with a symbol
+    // address of zero. That could overflow, but the code must be unreachable,
+    // so don't bother doing anything at all.
+    if (!SymVA)
+      return 0;
+    if (Out<ELF64BE>::Opd) {
+      // If this is a local call, and we currently have the address of a
+      // function-descriptor, get the underlying code address instead.
+      uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
+      uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+      bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
+      if (InOpd)
+        SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
+    }
+    return SymVA - P;
+  }
+  case R_PC:
+  case R_RELAX_GOT_PC:
+    return Body.getVA<ELFT>(A) - P;
+  case R_PLT_PAGE_PC:
+  case R_PAGE_PC:
+    return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
+  }
+  llvm_unreachable("Invalid expression");
+}
+
+// This function applies relocations to sections without SHF_ALLOC bit.
+// Such sections are never mapped to memory at runtime. Debug sections are
+// an example. Relocations in non-alloc sections are much easier to
+// handle than in allocated sections because it will never need complex
+// treatement such as GOT or PLT (because at runtime no one refers them).
+// So, we handle relocations for non-alloc sections directly in this
+// function as a performance optimization.
+template <class ELFT>
+template <class RelTy>
+void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+  const unsigned Bits = sizeof(uintX_t) * 8;
+  for (const RelTy &Rel : Rels) {
+    uint32_t Type = Rel.getType(Config->Mips64EL);
+    uintX_t Offset = this->getOffset(Rel.r_offset);
+    uint8_t *BufLoc = Buf + Offset;
+    uintX_t Addend = getAddend<ELFT>(Rel);
+    if (!RelTy::IsRela)
+      Addend += Target->getImplicitAddend(BufLoc, Type);
+
+    SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
+    if (Target->getRelExpr(Type, Sym) != R_ABS) {
+      error(this->getSectionName() + " has non-ABS reloc");
+      return;
+    }
+
+    uintX_t AddrLoc = this->OutSec->getVA() + Offset;
+    uint64_t SymVA =
+        SignExtend64<Bits>(getSymVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
+    Target->relocateOne(BufLoc, Type, SymVA);
+  }
+}
+
+template <class ELFT>
+void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+  // scanReloc function in Writer.cpp constructs Relocations
+  // vector only for SHF_ALLOC'ed sections. For other sections,
+  // we handle relocations directly here.
+  auto *IS = dyn_cast<InputSection<ELFT>>(this);
+  if (IS && !(IS->Header->sh_flags & SHF_ALLOC)) {
+    for (const Elf_Shdr *RelSec : IS->RelocSections) {
+      if (RelSec->sh_type == SHT_RELA)
+        IS->relocateNonAlloc(Buf, IS->File->getObj().relas(RelSec));
+      else
+        IS->relocateNonAlloc(Buf, IS->File->getObj().rels(RelSec));
+    }
+    return;
+  }
+
+  const unsigned Bits = sizeof(uintX_t) * 8;
+  for (const Relocation<ELFT> &Rel : Relocations) {
+    uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
+    uint8_t *BufLoc = Buf + Offset;
+    uint32_t Type = Rel.Type;
+    uintX_t A = Rel.Addend;
+
+    uintX_t AddrLoc = OutSec->getVA() + Offset;
+    RelExpr Expr = Rel.Expr;
+    uint64_t SymVA =
+        SignExtend64<Bits>(getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+
+    switch (Expr) {
+    case R_RELAX_GOT_PC:
+    case R_RELAX_GOT_PC_NOPIC:
+      Target->relaxGot(BufLoc, SymVA);
+      break;
+    case R_RELAX_TLS_IE_TO_LE:
+      Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
+      break;
+    case R_RELAX_TLS_LD_TO_LE:
+      Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
+      break;
+    case R_RELAX_TLS_GD_TO_LE:
+    case R_RELAX_TLS_GD_TO_LE_NEG:
+      Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
+      break;
+    case R_RELAX_TLS_GD_TO_IE:
+    case R_RELAX_TLS_GD_TO_IE_ABS:
+    case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+    case R_RELAX_TLS_GD_TO_IE_END:
+      Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
+      break;
+    case R_PPC_PLT_OPD:
+      // Patch a nop (0x60000000) to a ld.
+      if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
+        write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
+      // fallthrough
+    default:
+      Target->relocateOne(BufLoc, Type, SymVA);
+      break;
+    }
+  }
+}
+
+template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
+  if (this->Header->sh_type == SHT_NOBITS)
+    return;
+  ELFFile<ELFT> &EObj = this->File->getObj();
+
+  // If -r is given, then an InputSection may be a relocation section.
+  if (this->Header->sh_type == SHT_RELA) {
+    copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
+    return;
+  }
+  if (this->Header->sh_type == SHT_REL) {
+    copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+    return;
+  }
+
+  // Copy section contents from source object file to output file.
+  ArrayRef<uint8_t> Data = this->getSectionData();
+  memcpy(Buf + OutSecOff, Data.data(), Data.size());
+
+  // Iterate over all relocation sections that apply to this section.
+  uint8_t *BufEnd = Buf + OutSecOff + Data.size();
+  this->relocate(Buf, BufEnd);
+
+  // The section might have a data/code generated by the linker and need
+  // to be written after the section. Usually these are thunks - small piece
+  // of code used to jump between "incompatible" functions like PIC and non-PIC
+  // or if the jump target too far and its address does not fit to the short
+  // jump istruction.
+  if (!Thunks.empty()) {
+    Buf += OutSecOff + getThunkOff();
+    for (const Thunk<ELFT> *T : Thunks) {
+      T->writeTo(Buf);
+      Buf += T->size();
+    }
+  }
+}
+
+template <class ELFT>
+void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
+  this->Alignment = std::max(this->Alignment, Other->Alignment);
+  Other->Repl = this->Repl;
+  Other->Live = false;
+}
+
+template <class ELFT>
+SplitInputSection<ELFT>::SplitInputSection(
+    elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+    typename InputSectionBase<ELFT>::Kind SectionKind)
+    : InputSectionBase<ELFT>(File, Header, SectionKind) {}
+
+template <class ELFT>
+EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
+                                     const Elf_Shdr *Header)
+    : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {
+  // Mark .eh_frame sections as live by default because there are
+  // usually no relocations that point to .eh_frames. Otherwise,
+  // the garbage collector would drop all .eh_frame sections.
+  this->Live = true;
+}
+
+template <class ELFT>
+bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
+}
+
+// .eh_frame is a sequence of CIE or FDE records.
+// This function splits an input section into records and returns them.
+template <class ELFT>
+void EhInputSection<ELFT>::split() {
+  ArrayRef<uint8_t> Data = this->getSectionData();
+  for (size_t Off = 0, End = Data.size(); Off != End;) {
+    size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
+    this->Pieces.emplace_back(Off, Data.slice(Off, Size));
+    // The empty record is the end marker.
+    if (Size == 4)
+      break;
+    Off += Size;
+  }
+}
+
+template <class ELFT>
+typename ELFT::uint EhInputSection<ELFT>::getOffset(uintX_t Offset) const {
+  // The file crtbeginT.o has relocations pointing to the start of an empty
+  // .eh_frame that is known to be the first in the link. It does that to
+  // identify the start of the output .eh_frame. Handle this special case.
+  if (this->getSectionHdr()->sh_size == 0)
+    return Offset;
+  const SectionPiece *Piece = this->getSectionPiece(Offset);
+  if (Piece->OutputOff == size_t(-1))
+    return -1; // Not in the output
+
+  uintX_t Addend = Offset - Piece->InputOff;
+  return Piece->OutputOff + Addend;
+}
+
+static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
+  // Optimize the common case.
+  StringRef S((const char *)A.data(), A.size());
+  if (EntSize == 1)
+    return S.find(0);
+
+  for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
+    const char *B = S.begin() + I;
+    if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
+      return I;
+  }
+  return StringRef::npos;
+}
+
+// Split SHF_STRINGS section. Such section is a sequence of
+// null-terminated strings.
+static std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> Data,
+                                              size_t EntSize) {
+  std::vector<SectionPiece> V;
+  size_t Off = 0;
+  while (!Data.empty()) {
+    size_t End = findNull(Data, EntSize);
+    if (End == StringRef::npos)
+      fatal("string is not null terminated");
+    size_t Size = End + EntSize;
+    V.emplace_back(Off, Data.slice(0, Size));
+    Data = Data.slice(Size);
+    Off += Size;
+  }
+  return V;
+}
+
+// Split non-SHF_STRINGS section. Such section is a sequence of
+// fixed size records.
+static std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> Data,
+                                                 size_t EntSize) {
+  std::vector<SectionPiece> V;
+  size_t Size = Data.size();
+  assert((Size % EntSize) == 0);
+  for (unsigned I = 0, N = Size; I != N; I += EntSize)
+    V.emplace_back(I, Data.slice(I, EntSize));
+  return V;
+}
+
+template <class ELFT>
+MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
+                                           const Elf_Shdr *Header)
+    : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
+
+template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() {
+  ArrayRef<uint8_t> Data = this->getSectionData();
+  uintX_t EntSize = this->Header->sh_entsize;
+  if (this->Header->sh_flags & SHF_STRINGS)
+    this->Pieces = splitStrings(Data, EntSize);
+  else
+    this->Pieces = splitNonStrings(Data, EntSize);
+
+  if (Config->GcSections)
+    for (uintX_t Off : LiveOffsets)
+      this->getSectionPiece(Off)->Live = true;
+}
+
+template <class ELFT>
+bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == InputSectionBase<ELFT>::Merge;
+}
+
+// Do binary search to get a section piece at a given input offset.
+template <class ELFT>
+SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
+  auto *This = static_cast<const SplitInputSection<ELFT> *>(this);
+  return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+}
+
+template <class ELFT>
+const SectionPiece *
+SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
+  ArrayRef<uint8_t> D = this->getSectionData();
+  StringRef Data((const char *)D.data(), D.size());
+  uintX_t Size = Data.size();
+  if (Offset >= Size)
+    fatal("entry is past the end of the section");
+
+  // Find the element this offset points to.
+  auto I = std::upper_bound(
+      Pieces.begin(), Pieces.end(), Offset,
+      [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
+  --I;
+  return &*I;
+}
+
+// Returns the offset in an output section for a given input offset.
+// Because contents of a mergeable section is not contiguous in output,
+// it is not just an addition to a base output offset.
+template <class ELFT>
+typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+  auto It = OffsetMap.find(Offset);
+  if (It != OffsetMap.end())
+    return It->second;
+
+  // If Offset is not at beginning of a section piece, it is not in the map.
+  // In that case we need to search from the original section piece vector.
+  const SectionPiece &Piece = *this->getSectionPiece(Offset);
+  assert(Piece.Live);
+  uintX_t Addend = Offset - Piece.InputOff;
+  return Piece.OutputOff + Addend;
+}
+
+// Create a map from input offsets to output offsets for all section pieces.
+// It is called after finalize().
+template <class ELFT> void  MergeInputSection<ELFT>::finalizePieces() {
+  OffsetMap.grow(this->Pieces.size());
+  for (SectionPiece &Piece : this->Pieces) {
+    if (!Piece.Live)
+      continue;
+    if (Piece.OutputOff == size_t(-1)) {
+      // Offsets of tail-merged strings are computed lazily.
+      auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec);
+      ArrayRef<uint8_t> D = Piece.data();
+      StringRef S((const char *)D.data(), D.size());
+      Piece.OutputOff = OutSec->getOffset(S);
+    }
+    OffsetMap[Piece.InputOff] = Piece.OutputOff;
+  }
+}
+
+template <class ELFT>
+MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(elf::ObjectFile<ELFT> *F,
+                                                       const Elf_Shdr *Hdr)
+    : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) {
+  // Initialize this->Reginfo.
+  ArrayRef<uint8_t> D = this->getSectionData();
+  if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) {
+    error("invalid size of .reginfo section");
+    return;
+  }
+  Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
+}
+
+template <class ELFT>
+bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
+}
+
+template <class ELFT>
+MipsOptionsInputSection<ELFT>::MipsOptionsInputSection(elf::ObjectFile<ELFT> *F,
+                                                       const Elf_Shdr *Hdr)
+    : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsOptions) {
+  // Find ODK_REGINFO option in the section's content.
+  ArrayRef<uint8_t> D = this->getSectionData();
+  while (!D.empty()) {
+    if (D.size() < sizeof(Elf_Mips_Options<ELFT>)) {
+      error("invalid size of .MIPS.options section");
+      break;
+    }
+    auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(D.data());
+    if (O->kind == ODK_REGINFO) {
+      Reginfo = &O->getRegInfo();
+      break;
+    }
+    D = D.slice(O->size);
+  }
+}
+
+template <class ELFT>
+bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == InputSectionBase<ELFT>::MipsOptions;
+}
+
+template bool elf::isDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
+template bool elf::isDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
+template bool elf::isDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
+template bool elf::isDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
+
+template class elf::InputSectionBase<ELF32LE>;
+template class elf::InputSectionBase<ELF32BE>;
+template class elf::InputSectionBase<ELF64LE>;
+template class elf::InputSectionBase<ELF64BE>;
+
+template class elf::InputSection<ELF32LE>;
+template class elf::InputSection<ELF32BE>;
+template class elf::InputSection<ELF64LE>;
+template class elf::InputSection<ELF64BE>;
+
+template class elf::SplitInputSection<ELF32LE>;
+template class elf::SplitInputSection<ELF32BE>;
+template class elf::SplitInputSection<ELF64LE>;
+template class elf::SplitInputSection<ELF64BE>;
+
+template class elf::EhInputSection<ELF32LE>;
+template class elf::EhInputSection<ELF32BE>;
+template class elf::EhInputSection<ELF64LE>;
+template class elf::EhInputSection<ELF64BE>;
+
+template class elf::MergeInputSection<ELF32LE>;
+template class elf::MergeInputSection<ELF32BE>;
+template class elf::MergeInputSection<ELF64LE>;
+template class elf::MergeInputSection<ELF64BE>;
+
+template class elf::MipsReginfoInputSection<ELF32LE>;
+template class elf::MipsReginfoInputSection<ELF32BE>;
+template class elf::MipsReginfoInputSection<ELF64LE>;
+template class elf::MipsReginfoInputSection<ELF64BE>;
+
+template class elf::MipsOptionsInputSection<ELF32LE>;
+template class elf::MipsOptionsInputSection<ELF32BE>;
+template class elf::MipsOptionsInputSection<ELF64LE>;
+template class elf::MipsOptionsInputSection<ELF64BE>;
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
new file mode 100644 (file)
index 0000000..61a89c5
--- /dev/null
@@ -0,0 +1,270 @@
+//===- InputSection.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_SECTION_H
+#define LLD_ELF_INPUT_SECTION_H
+
+#include "Config.h"
+#include "Relocations.h"
+#include "Thunks.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
+
+class SymbolBody;
+
+template <class ELFT> class ICF;
+template <class ELFT> class DefinedRegular;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class OutputSection;
+template <class ELFT> class OutputSectionBase;
+
+// This corresponds to a section of an input file.
+template <class ELFT> class InputSectionBase {
+protected:
+  typedef typename ELFT::Chdr Elf_Chdr;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+  const Elf_Shdr *Header;
+
+  // The file this section is from.
+  ObjectFile<ELFT> *File;
+
+  // If a section is compressed, this vector has uncompressed section data.
+  SmallVector<char, 0> Uncompressed;
+
+public:
+  enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions };
+  Kind SectionKind;
+
+  InputSectionBase() : Repl(this) {}
+
+  InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+                   Kind SectionKind);
+  OutputSectionBase<ELFT> *OutSec = nullptr;
+  uint32_t Alignment;
+
+  // Used for garbage collection.
+  bool Live;
+
+  // This pointer points to the "real" instance of this instance.
+  // Usually Repl == this. However, if ICF merges two sections,
+  // Repl pointer of one section points to another section. So,
+  // if you need to get a pointer to this instance, do not use
+  // this but instead this->Repl.
+  InputSectionBase<ELFT> *Repl;
+
+  // Returns the size of this section (even if this is a common or BSS.)
+  size_t getSize() const;
+
+  static InputSectionBase<ELFT> Discarded;
+
+  StringRef getSectionName() const;
+  const Elf_Shdr *getSectionHdr() const { return Header; }
+  ObjectFile<ELFT> *getFile() const { return File; }
+  uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
+
+  // Translate an offset in the input section to an offset in the output
+  // section.
+  uintX_t getOffset(uintX_t Offset) const;
+
+  ArrayRef<uint8_t> getSectionData() const;
+
+  void uncompress();
+
+  void relocate(uint8_t *Buf, uint8_t *BufEnd);
+  std::vector<Relocation<ELFT>> Relocations;
+
+  bool Compressed;
+};
+
+template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
+
+// SectionPiece represents a piece of splittable section contents.
+struct SectionPiece {
+  SectionPiece(size_t Off, ArrayRef<uint8_t> Data)
+      : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()),
+        Live(!Config->GcSections) {}
+
+  ArrayRef<uint8_t> data() { return {Data, Size}; }
+  size_t size() const { return Size; }
+
+  size_t InputOff;
+  size_t OutputOff = -1;
+
+private:
+  // We use bitfields because SplitInputSection is accessed by
+  // std::upper_bound very often.
+  // We want to save bits to make it cache friendly.
+  const uint8_t *Data;
+  uint32_t Size : 31;
+
+public:
+  uint32_t Live : 1;
+};
+
+// Usually sections are copied to the output as atomic chunks of data,
+// but some special types of sections are split into small pieces of data
+// and each piece is copied to a different place in the output.
+// This class represents such special sections.
+template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+                    typename InputSectionBase<ELFT>::Kind SectionKind);
+
+  // Splittable sections are handled as a sequence of data
+  // rather than a single large blob of data.
+  std::vector<SectionPiece> Pieces;
+
+  // Returns the SectionPiece at a given input section offset.
+  SectionPiece *getSectionPiece(uintX_t Offset);
+  const SectionPiece *getSectionPiece(uintX_t Offset) const;
+};
+
+// This corresponds to a SHF_MERGE section of an input file.
+template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+public:
+  MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+  static bool classof(const InputSectionBase<ELFT> *S);
+  void splitIntoPieces();
+
+  // Mark the piece at a given offset live. Used by GC.
+  void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); }
+
+  // Translate an offset in the input section to an offset
+  // in the output section.
+  uintX_t getOffset(uintX_t Offset) const;
+
+  void finalizePieces();
+
+private:
+  llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+  llvm::DenseSet<uintX_t> LiveOffsets;
+};
+
+// This corresponds to a .eh_frame section of an input file.
+template <class ELFT> class EhInputSection : public SplitInputSection<ELFT> {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::uint uintX_t;
+  EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+  static bool classof(const InputSectionBase<ELFT> *S);
+  void split();
+
+  // Translate an offset in the input section to an offset in the output
+  // section.
+  uintX_t getOffset(uintX_t Offset) const;
+
+  // Relocation section that refer to this one.
+  const Elf_Shdr *RelocSection = nullptr;
+};
+
+// This corresponds to a non SHF_MERGE section of an input file.
+template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
+  friend ICF<ELFT>;
+  typedef InputSectionBase<ELFT> Base;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+
+  // Write this section to a mmap'ed file, assuming Buf is pointing to
+  // beginning of the output section.
+  void writeTo(uint8_t *Buf);
+
+  // Relocation sections that refer to this one.
+  llvm::TinyPtrVector<const Elf_Shdr *> RelocSections;
+
+  // The offset from beginning of the output sections this section was assigned
+  // to. The writer sets a value.
+  uint64_t OutSecOff = 0;
+
+  static bool classof(const InputSectionBase<ELFT> *S);
+
+  InputSectionBase<ELFT> *getRelocatedSection();
+
+  // Register thunk related to the symbol. When the section is written
+  // to a mmap'ed file, target is requested to write an actual thunk code.
+  // Now thunks is supported for MIPS and ARM target only.
+  void addThunk(const Thunk<ELFT> *T);
+
+  // The offset of synthetic thunk code from beginning of this section.
+  uint64_t getThunkOff() const;
+
+  // Size of chunk with thunks code.
+  uint64_t getThunksSize() const;
+
+  template <class RelTy>
+  void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+private:
+  template <class RelTy>
+  void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+  // Called by ICF to merge two input sections.
+  void replace(InputSection<ELFT> *Other);
+
+  // Used by ICF.
+  uint64_t GroupId = 0;
+
+  llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
+};
+
+// MIPS .reginfo section provides information on the registers used by the code
+// in the object file. Linker should collect this information and write a single
+// .reginfo section in the output file. The output section contains a union of
+// used registers masks taken from input .reginfo sections and final value
+// of the `_gp` symbol.  For details: Chapter 4 / "Register Information" at
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+template <class ELFT>
+class MipsReginfoInputSection : public InputSectionBase<ELFT> {
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+public:
+  MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
+  static bool classof(const InputSectionBase<ELFT> *S);
+
+  const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
+};
+
+template <class ELFT>
+class MipsOptionsInputSection : public InputSectionBase<ELFT> {
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+public:
+  MipsOptionsInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
+  static bool classof(const InputSectionBase<ELFT> *S);
+
+  const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
new file mode 100644 (file)
index 0000000..0e8006a
--- /dev/null
@@ -0,0 +1,325 @@
+//===- 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 "Driver.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/LoopPassManager.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/ParallelCG.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/LTO/legacy/UpdateCompilerUsed.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// This is for use when debugging LTO.
+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(EC, "cannot create " + Path);
+  OS << Buffer;
+}
+
+// This is for use when debugging LTO.
+static void saveBCFile(Module &M, const Twine &Path) {
+  std::error_code EC;
+  raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+  if (EC)
+    error(EC, "cannot create " + Path);
+  WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true);
+}
+
+static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) {
+  PassBuilder PB(&TM);
+
+  AAManager AA;
+
+  // Parse a custom AA pipeline if asked to.
+  if (!PB.parseAAPipeline(AA, Config->LtoAAPipeline)) {
+    error("Unable to parse AA pipeline description: " + Config->LtoAAPipeline);
+    return;
+  }
+
+  LoopAnalysisManager LAM;
+  FunctionAnalysisManager FAM;
+  CGSCCAnalysisManager CGAM;
+  ModuleAnalysisManager MAM;
+
+  // Register the AA manager first so that our version is the one used.
+  FAM.registerPass([&] { return std::move(AA); });
+
+  // Register all the basic analyses with the managers.
+  PB.registerModuleAnalyses(MAM);
+  PB.registerCGSCCAnalyses(CGAM);
+  PB.registerFunctionAnalyses(FAM);
+  PB.registerLoopAnalyses(LAM);
+  PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+  ModulePassManager MPM;
+  if (!Config->DisableVerify)
+    MPM.addPass(VerifierPass());
+
+  // Now, add all the passes we've been requested to.
+  if (!PB.parsePassPipeline(MPM, Config->LtoNewPmPasses)) {
+    error("unable to parse pass pipeline description: " +
+          Config->LtoNewPmPasses);
+    return;
+  }
+
+  if (!Config->DisableVerify)
+    MPM.addPass(VerifierPass());
+  MPM.run(M, MAM);
+}
+
+static void runOldLtoPasses(Module &M, TargetMachine &TM) {
+  // Note that the gold plugin has a similar piece of code, so
+  // it is probably better to move this code to a common place.
+  legacy::PassManager LtoPasses;
+  LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
+  PassManagerBuilder PMB;
+  PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
+  PMB.Inliner = createFunctionInliningPass();
+  PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify;
+  PMB.LoopVectorize = true;
+  PMB.SLPVectorize = true;
+  PMB.OptLevel = Config->LtoO;
+  PMB.populateLTOPassManager(LtoPasses);
+  LtoPasses.run(M);
+}
+
+static void runLTOPasses(Module &M, TargetMachine &TM) {
+  if (!Config->LtoNewPmPasses.empty()) {
+    // The user explicitly asked for a set of passes to be run.
+    // This needs the new PM to work as there's no clean way to
+    // pass a set of passes to run in the legacy PM.
+    runNewCustomLtoPasses(M, TM);
+    if (HasError)
+      return;
+  } else {
+    // Run the 'default' set of LTO passes. This code still uses
+    // the legacy PM as the new one is not the default.
+    runOldLtoPasses(M, TM);
+  }
+
+  if (Config->SaveTemps)
+    saveBCFile(M, Config->OutputFile + ".lto.opt.bc");
+}
+
+static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
+                              Symbol *S, GlobalValue *GV) {
+  if (S->IsUsedInRegularObj || Used.count(GV))
+    return false;
+  return !S->includeInDynsym();
+}
+
+BitcodeCompiler::BitcodeCompiler()
+    : Combined(new Module("ld-temp.o", Driver->Context)) {}
+
+static void undefine(Symbol *S) {
+  replaceBody<Undefined>(S, S->body()->getName(), STV_DEFAULT, S->body()->Type,
+                         nullptr);
+}
+
+static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV,
+                                   StringSet<> &AsmUndefinedRefs) {
+  // GV associated => not an assembly symbol, bail out.
+  if (GV)
+    return;
+
+  // This is an undefined reference to a symbol in asm. We put that in
+  // compiler.used, so that we can preserve it from being dropped from
+  // the output, without necessarily preventing its internalization.
+  SmallString<64> Name;
+  raw_svector_ostream OS(Name);
+  Sym.printName(OS);
+  AsmUndefinedRefs.insert(Name.str());
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+  std::unique_ptr<IRObjectFile> Obj = std::move(F.Obj);
+  std::vector<GlobalValue *> Keep;
+  unsigned BodyIndex = 0;
+  ArrayRef<Symbol *> Syms = F.getSymbols();
+
+  Module &M = Obj->getModule();
+  if (M.getDataLayoutStr().empty())
+    fatal("invalid bitcode file: " + F.getName() + " has no datalayout");
+
+  // Discard non-compatible debug infos if necessary.
+  M.materializeMetadata();
+  UpgradeDebugInfo(M);
+
+  // If a symbol appears in @llvm.used, the linker is required
+  // to treat the symbol as there is a reference to the symbol
+  // that it cannot see. Therefore, we can't internalize.
+  SmallPtrSet<GlobalValue *, 8> Used;
+  collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false);
+
+  for (const BasicSymbolRef &Sym : Obj->symbols()) {
+    uint32_t Flags = Sym.getFlags();
+    GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
+    if (GV && GV->hasAppendingLinkage())
+      Keep.push_back(GV);
+    if (BitcodeFile::shouldSkip(Flags))
+      continue;
+    Symbol *S = Syms[BodyIndex++];
+    if (Flags & BasicSymbolRef::SF_Undefined) {
+      handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs);
+      continue;
+    }
+    auto *B = dyn_cast<DefinedBitcode>(S->body());
+    if (!B || B->file() != &F)
+      continue;
+
+    // We collect the set of symbols we want to internalize here
+    // and change the linkage after the IRMover executed, i.e. after
+    // we imported the symbols and satisfied undefined references
+    // to it. We can't just change linkage here because otherwise
+    // the IRMover will just rename the symbol.
+    if (GV && shouldInternalize(Used, S, GV))
+      InternalizedSyms.insert(GV->getName());
+
+    // At this point we know that either the combined LTO object will provide a
+    // definition of a symbol, or we will internalize it. In either case, we
+    // need to undefine the symbol. In the former case, the real definition
+    // needs to be able to replace the original definition without conflicting.
+    // In the latter case, we need to allow the combined LTO object to provide a
+    // definition with the same name, for example when doing parallel codegen.
+    undefine(S);
+
+    if (!GV)
+      // Module asm symbol.
+      continue;
+
+    switch (GV->getLinkage()) {
+    default:
+      break;
+    case GlobalValue::LinkOnceAnyLinkage:
+      GV->setLinkage(GlobalValue::WeakAnyLinkage);
+      break;
+    case GlobalValue::LinkOnceODRLinkage:
+      GV->setLinkage(GlobalValue::WeakODRLinkage);
+      break;
+    }
+
+    Keep.push_back(GV);
+  }
+
+  IRMover Mover(*Combined);
+  if (Error E = Mover.move(Obj->takeModule(), Keep,
+                           [](GlobalValue &, IRMover::ValueAdder) {})) {
+    handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) {
+      fatal("failed to link module " + F.getName() + ": " + EIB.message());
+    });
+  }
+}
+
+static void internalize(GlobalValue &GV) {
+  assert(!GV.hasLocalLinkage() &&
+         "Trying to internalize a symbol with local linkage!");
+  GV.setLinkage(GlobalValue::InternalLinkage);
+}
+
+std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::runSplitCodegen(
+    const std::function<std::unique_ptr<TargetMachine>()> &TMFactory) {
+  unsigned NumThreads = Config->LtoJobs;
+  OwningData.resize(NumThreads);
+
+  std::list<raw_svector_ostream> OSs;
+  std::vector<raw_pwrite_stream *> OSPtrs;
+  for (SmallString<0> &Obj : OwningData) {
+    OSs.emplace_back(Obj);
+    OSPtrs.push_back(&OSs.back());
+  }
+
+  splitCodeGen(std::move(Combined), OSPtrs, {}, TMFactory);
+
+  std::vector<std::unique_ptr<InputFile>> ObjFiles;
+  for (SmallString<0> &Obj : OwningData)
+    ObjFiles.push_back(createObjectFile(
+        MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object")));
+
+  // If -save-temps is given, we need to save temporary objects to files.
+  // This is for debugging.
+  if (Config->SaveTemps) {
+    if (NumThreads == 1) {
+      saveBuffer(OwningData[0], Config->OutputFile + ".lto.o");
+    } else {
+      for (unsigned I = 0; I < NumThreads; ++I)
+        saveBuffer(OwningData[I], Config->OutputFile + Twine(I) + ".lto.o");
+    }
+  }
+
+  return ObjFiles;
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting ObjectFile.
+std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::compile() {
+  for (const auto &Name : InternalizedSyms) {
+    GlobalValue *GV = Combined->getNamedValue(Name.first());
+    assert(GV);
+    internalize(*GV);
+  }
+
+  std::string TheTriple = Combined->getTargetTriple();
+  std::string Msg;
+  const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg);
+  if (!T)
+    fatal("target not found: " + Msg);
+
+  // LLD supports the new relocations.
+  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+  Options.RelaxELFRelocations = true;
+
+  auto CreateTargetMachine = [&]() {
+    return std::unique_ptr<TargetMachine>(T->createTargetMachine(
+        TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static));
+  };
+
+  std::unique_ptr<TargetMachine> TM = CreateTargetMachine();
+
+  // Update llvm.compiler.used so that optimizations won't strip
+  // off AsmUndefinedReferences.
+  updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs);
+
+  if (Config->SaveTemps)
+    saveBCFile(*Combined, Config->OutputFile + ".lto.bc");
+
+  runLTOPasses(*Combined, *TM);
+  if (HasError)
+    return {};
+
+  return runSplitCodegen(CreateTargetMachine);
+}
diff --git a/ELF/LTO.h b/ELF/LTO.h
new file mode 100644 (file)
index 0000000..81dffb6
--- /dev/null
+++ b/ELF/LTO.h
@@ -0,0 +1,54 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one ELF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular ELF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// an ELF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LTO_H
+#define LLD_ELF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Linker/IRMover.h"
+
+namespace lld {
+namespace elf {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+  BitcodeCompiler();
+  void add(BitcodeFile &F);
+  std::vector<std::unique_ptr<InputFile>> compile();
+
+private:
+  std::vector<std::unique_ptr<InputFile>> runSplitCodegen(
+      const std::function<std::unique_ptr<llvm::TargetMachine>()> &TMFactory);
+
+  std::unique_ptr<llvm::Module> Combined;
+  std::vector<SmallString<0>> OwningData;
+  llvm::StringSet<> InternalizedSyms;
+  llvm::StringSet<> AsmUndefinedRefs;
+};
+}
+}
+
+#endif
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
new file mode 100644 (file)
index 0000000..61abdc1
--- /dev/null
@@ -0,0 +1,606 @@
+//===- LinkerScript.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+// It does not construct an AST but consume linker script directives directly.
+// Results are written to Driver or Config object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinkerScript.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
+#include "Strings.h"
+#include "Symbols.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace lld;
+using namespace lld::elf;
+
+ScriptConfiguration *elf::ScriptConfig;
+
+// This is an operator-precedence parser to parse and evaluate
+// a linker script expression. For each linker script arithmetic
+// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
+// is created and ran.
+namespace {
+class ExprParser : public ScriptParserBase {
+public:
+  ExprParser(std::vector<StringRef> &Tokens, uint64_t Dot)
+      : ScriptParserBase(Tokens), Dot(Dot) {}
+
+  uint64_t run();
+
+private:
+  uint64_t parsePrimary();
+  uint64_t parseTernary(uint64_t Cond);
+  uint64_t apply(StringRef Op, uint64_t L, uint64_t R);
+  uint64_t parseExpr1(uint64_t Lhs, int MinPrec);
+  uint64_t parseExpr();
+
+  uint64_t Dot;
+};
+}
+
+static int precedence(StringRef Op) {
+  return StringSwitch<int>(Op)
+      .Case("*", 4)
+      .Case("/", 4)
+      .Case("+", 3)
+      .Case("-", 3)
+      .Case("<", 2)
+      .Case(">", 2)
+      .Case(">=", 2)
+      .Case("<=", 2)
+      .Case("==", 2)
+      .Case("!=", 2)
+      .Case("&", 1)
+      .Default(-1);
+}
+
+static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) {
+  return ExprParser(Tokens, Dot).run();
+}
+
+uint64_t ExprParser::run() {
+  uint64_t V = parseExpr();
+  if (!atEOF() && !Error)
+    setError("stray token: " + peek());
+  return V;
+}
+
+// This is a part of the operator-precedence parser to evaluate
+// arithmetic expressions in SECTIONS command. This function evaluates an
+// integer literal, a parenthesized expression, the ALIGN function,
+// or the special variable ".".
+uint64_t ExprParser::parsePrimary() {
+  StringRef Tok = next();
+  if (Tok == ".")
+    return Dot;
+  if (Tok == "(") {
+    uint64_t V = parseExpr();
+    expect(")");
+    return V;
+  }
+  if (Tok == "ALIGN") {
+    expect("(");
+    uint64_t V = parseExpr();
+    expect(")");
+    return alignTo(Dot, V);
+  }
+  uint64_t V = 0;
+  if (Tok.getAsInteger(0, V))
+    setError("malformed number: " + Tok);
+  return V;
+}
+
+uint64_t ExprParser::parseTernary(uint64_t Cond) {
+  next();
+  uint64_t V = parseExpr();
+  expect(":");
+  uint64_t W = parseExpr();
+  return Cond ? V : W;
+}
+
+uint64_t ExprParser::apply(StringRef Op, uint64_t L, uint64_t R) {
+  if (Op == "*")
+    return L * R;
+  if (Op == "/") {
+    if (R == 0) {
+      error("division by zero");
+      return 0;
+    }
+    return L / R;
+  }
+  if (Op == "+")
+    return L + R;
+  if (Op == "-")
+    return L - R;
+  if (Op == "<")
+    return L < R;
+  if (Op == ">")
+    return L > R;
+  if (Op == ">=")
+    return L >= R;
+  if (Op == "<=")
+    return L <= R;
+  if (Op == "==")
+    return L == R;
+  if (Op == "!=")
+    return L != R;
+  if (Op == "&")
+    return L & R;
+  llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser.
+// This function assumes that the remaining token stream starts
+// with an operator.
+uint64_t ExprParser::parseExpr1(uint64_t Lhs, int MinPrec) {
+  while (!atEOF()) {
+    // Read an operator and an expression.
+    StringRef Op1 = peek();
+    if (Op1 == "?")
+      return parseTernary(Lhs);
+    if (precedence(Op1) < MinPrec)
+      return Lhs;
+    next();
+    uint64_t Rhs = parsePrimary();
+
+    // Evaluate the remaining part of the expression first if the
+    // next operator has greater precedence than the previous one.
+    // For example, if we have read "+" and "3", and if the next
+    // operator is "*", then we'll evaluate 3 * ... part first.
+    while (!atEOF()) {
+      StringRef Op2 = peek();
+      if (precedence(Op2) <= precedence(Op1))
+        break;
+      Rhs = parseExpr1(Rhs, precedence(Op2));
+    }
+
+    Lhs = apply(Op1, Lhs, Rhs);
+  }
+  return Lhs;
+}
+
+// Reads and evaluates an arithmetic expression.
+uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); }
+
+template <class ELFT>
+StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
+  for (SectionRule &R : Opt.Sections)
+    if (globMatch(R.SectionPattern, S->getSectionName()))
+      return R.Dest;
+  return "";
+}
+
+template <class ELFT>
+bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) {
+  return getOutputSection(S) == "/DISCARD/";
+}
+
+template <class ELFT>
+bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
+  for (StringRef Pat : Opt.KeptSections)
+    if (globMatch(Pat, S->getSectionName()))
+      return true;
+  return false;
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::assignAddresses(
+    ArrayRef<OutputSectionBase<ELFT> *> Sections) {
+  // Orphan sections are sections present in the input files which
+  // are not explicitly placed into the output file by the linker script.
+  // We place orphan sections at end of file.
+  // Other linkers places them using some heuristics as described in
+  // https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections.
+  for (OutputSectionBase<ELFT> *Sec : Sections) {
+    StringRef Name = Sec->getName();
+    if (getSectionIndex(Name) == INT_MAX)
+      Opt.Commands.push_back({SectionKind, {}, Name});
+  }
+
+  // Assign addresses as instructed by linker script SECTIONS sub-commands.
+  Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize();
+  uintX_t MinVA = std::numeric_limits<uintX_t>::max();
+  uintX_t ThreadBssOffset = 0;
+
+  for (SectionsCommand &Cmd : Opt.Commands) {
+    if (Cmd.Kind == AssignmentKind) {
+      uint64_t Val = evalExpr(Cmd.Expr, Dot);
+
+      if (Cmd.Name == ".") {
+        Dot = Val;
+      } else {
+        auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
+        D->Value = Val;
+      }
+      continue;
+    }
+
+    // Find all the sections with required name. There can be more than
+    // ont section with such name, if the alignment, flags or type
+    // attribute differs.
+    assert(Cmd.Kind == SectionKind);
+    for (OutputSectionBase<ELFT> *Sec : Sections) {
+      if (Sec->getName() != Cmd.Name)
+        continue;
+
+      if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
+        uintX_t TVA = Dot + ThreadBssOffset;
+        TVA = alignTo(TVA, Sec->getAlignment());
+        Sec->setVA(TVA);
+        ThreadBssOffset = TVA - Dot + Sec->getSize();
+        continue;
+      }
+
+      if (Sec->getFlags() & SHF_ALLOC) {
+        Dot = alignTo(Dot, Sec->getAlignment());
+        Sec->setVA(Dot);
+        MinVA = std::min(MinVA, Dot);
+        Dot += Sec->getSize();
+        continue;
+      }
+    }
+  }
+
+  // ELF and Program headers need to be right before the first section in
+  // memory.
+  // Set their addresses accordingly.
+  MinVA = alignDown(MinVA - Out<ELFT>::ElfHeader->getSize() -
+                        Out<ELFT>::ProgramHeaders->getSize(),
+                    Target->PageSize);
+  Out<ELFT>::ElfHeader->setVA(MinVA);
+  Out<ELFT>::ProgramHeaders->setVA(Out<ELFT>::ElfHeader->getSize() + MinVA);
+}
+
+template <class ELFT>
+ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) {
+  auto I = Opt.Filler.find(Name);
+  if (I == Opt.Filler.end())
+    return {};
+  return I->second;
+}
+
+// Returns the index of the given section name in linker script
+// SECTIONS commands. Sections are laid out as the same order as they
+// were in the script. If a given name did not appear in the script,
+// it returns INT_MAX, so that it will be laid out at end of file.
+template <class ELFT>
+int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
+  auto Begin = Opt.Commands.begin();
+  auto End = Opt.Commands.end();
+  auto I = std::find_if(Begin, End, [&](SectionsCommand &N) {
+    return N.Kind == SectionKind && N.Name == Name;
+  });
+  return I == End ? INT_MAX : (I - Begin);
+}
+
+// A compartor to sort output sections. Returns -1 or 1 if
+// A or B are mentioned in linker script. Otherwise, returns 0.
+template <class ELFT>
+int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
+  int I = getSectionIndex(A);
+  int J = getSectionIndex(B);
+  if (I == INT_MAX && J == INT_MAX)
+    return 0;
+  return I < J ? -1 : 1;
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::addScriptedSymbols() {
+  for (SectionsCommand &Cmd : Opt.Commands)
+    if (Cmd.Kind == AssignmentKind)
+      if (Cmd.Name != "." && Symtab<ELFT>::X->find(Cmd.Name) == nullptr)
+        Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT);
+}
+
+class elf::ScriptParser : public ScriptParserBase {
+  typedef void (ScriptParser::*Handler)();
+
+public:
+  ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {}
+
+  void run();
+
+private:
+  void addFile(StringRef Path);
+
+  void readAsNeeded();
+  void readEntry();
+  void readExtern();
+  void readGroup();
+  void readInclude();
+  void readNothing() {}
+  void readOutput();
+  void readOutputArch();
+  void readOutputFormat();
+  void readSearchDir();
+  void readSections();
+
+  void readLocationCounterValue();
+  void readOutputSectionDescription(StringRef OutSec);
+  void readSymbolAssignment(StringRef Name);
+  std::vector<StringRef> readSectionsCommandExpr();
+
+  const static StringMap<Handler> Cmd;
+  ScriptConfiguration &Opt = *ScriptConfig;
+  StringSaver Saver = {ScriptConfig->Alloc};
+  bool IsUnderSysroot;
+};
+
+const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = {
+    {"ENTRY", &ScriptParser::readEntry},
+    {"EXTERN", &ScriptParser::readExtern},
+    {"GROUP", &ScriptParser::readGroup},
+    {"INCLUDE", &ScriptParser::readInclude},
+    {"INPUT", &ScriptParser::readGroup},
+    {"OUTPUT", &ScriptParser::readOutput},
+    {"OUTPUT_ARCH", &ScriptParser::readOutputArch},
+    {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat},
+    {"SEARCH_DIR", &ScriptParser::readSearchDir},
+    {"SECTIONS", &ScriptParser::readSections},
+    {";", &ScriptParser::readNothing}};
+
+void ScriptParser::run() {
+  while (!atEOF()) {
+    StringRef Tok = next();
+    if (Handler Fn = Cmd.lookup(Tok))
+      (this->*Fn)();
+    else
+      setError("unknown directive: " + Tok);
+  }
+}
+
+void ScriptParser::addFile(StringRef S) {
+  if (IsUnderSysroot && S.startswith("/")) {
+    SmallString<128> Path;
+    (Config->Sysroot + S).toStringRef(Path);
+    if (sys::fs::exists(Path)) {
+      Driver->addFile(Saver.save(Path.str()));
+      return;
+    }
+  }
+
+  if (sys::path::is_absolute(S)) {
+    Driver->addFile(S);
+  } else if (S.startswith("=")) {
+    if (Config->Sysroot.empty())
+      Driver->addFile(S.substr(1));
+    else
+      Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
+  } else if (S.startswith("-l")) {
+    Driver->addLibrary(S.substr(2));
+  } else if (sys::fs::exists(S)) {
+    Driver->addFile(S);
+  } else {
+    std::string Path = findFromSearchPaths(S);
+    if (Path.empty())
+      setError("unable to find " + S);
+    else
+      Driver->addFile(Saver.save(Path));
+  }
+}
+
+void ScriptParser::readAsNeeded() {
+  expect("(");
+  bool Orig = Config->AsNeeded;
+  Config->AsNeeded = true;
+  while (!Error) {
+    StringRef Tok = next();
+    if (Tok == ")")
+      break;
+    addFile(Tok);
+  }
+  Config->AsNeeded = Orig;
+}
+
+void ScriptParser::readEntry() {
+  // -e <symbol> takes predecence over ENTRY(<symbol>).
+  expect("(");
+  StringRef Tok = next();
+  if (Config->Entry.empty())
+    Config->Entry = Tok;
+  expect(")");
+}
+
+void ScriptParser::readExtern() {
+  expect("(");
+  while (!Error) {
+    StringRef Tok = next();
+    if (Tok == ")")
+      return;
+    Config->Undefined.push_back(Tok);
+  }
+}
+
+void ScriptParser::readGroup() {
+  expect("(");
+  while (!Error) {
+    StringRef Tok = next();
+    if (Tok == ")")
+      return;
+    if (Tok == "AS_NEEDED") {
+      readAsNeeded();
+      continue;
+    }
+    addFile(Tok);
+  }
+}
+
+void ScriptParser::readInclude() {
+  StringRef Tok = next();
+  auto MBOrErr = MemoryBuffer::getFile(Tok);
+  if (!MBOrErr) {
+    setError("cannot open " + Tok);
+    return;
+  }
+  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+  StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
+  std::vector<StringRef> V = tokenize(S);
+  Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
+}
+
+void ScriptParser::readOutput() {
+  // -o <file> takes predecence over OUTPUT(<file>).
+  expect("(");
+  StringRef Tok = next();
+  if (Config->OutputFile.empty())
+    Config->OutputFile = Tok;
+  expect(")");
+}
+
+void ScriptParser::readOutputArch() {
+  // Error checking only for now.
+  expect("(");
+  next();
+  expect(")");
+}
+
+void ScriptParser::readOutputFormat() {
+  // Error checking only for now.
+  expect("(");
+  next();
+  StringRef Tok = next();
+  if (Tok == ")")
+   return;
+  if (Tok != ",") {
+    setError("unexpected token: " + Tok);
+    return;
+  }
+  next();
+  expect(",");
+  next();
+  expect(")");
+}
+
+void ScriptParser::readSearchDir() {
+  expect("(");
+  Config->SearchPaths.push_back(next());
+  expect(")");
+}
+
+void ScriptParser::readSections() {
+  Opt.DoLayout = true;
+  expect("{");
+  while (!Error && !skip("}")) {
+    StringRef Tok = peek();
+    if (Tok == ".") {
+      readLocationCounterValue();
+      continue;
+    }
+    next();
+    if (peek() == "=")
+      readSymbolAssignment(Tok);
+    else
+      readOutputSectionDescription(Tok);
+  }
+}
+
+void ScriptParser::readLocationCounterValue() {
+  expect(".");
+  expect("=");
+  std::vector<StringRef> Expr = readSectionsCommandExpr();
+  if (Expr.empty())
+    error("error in location counter expression");
+  else
+    Opt.Commands.push_back({AssignmentKind, std::move(Expr), "."});
+}
+
+void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+  Opt.Commands.push_back({SectionKind, {}, OutSec});
+  expect(":");
+  expect("{");
+
+  while (!Error && !skip("}")) {
+    StringRef Tok = next();
+    if (Tok == "*") {
+      expect("(");
+      while (!Error && !skip(")"))
+        Opt.Sections.emplace_back(OutSec, next());
+    } else if (Tok == "KEEP") {
+      expect("(");
+      expect("*");
+      expect("(");
+      while (!Error && !skip(")")) {
+        StringRef Sec = next();
+        Opt.Sections.emplace_back(OutSec, Sec);
+        Opt.KeptSections.push_back(Sec);
+      }
+      expect(")");
+    } else {
+      setError("unknown command " + Tok);
+    }
+  }
+
+  StringRef Tok = peek();
+  if (Tok.startswith("=")) {
+    if (!Tok.startswith("=0x")) {
+      setError("filler should be a hexadecimal value");
+      return;
+    }
+    Tok = Tok.substr(3);
+    Opt.Filler[OutSec] = parseHex(Tok);
+    next();
+  }
+}
+
+void ScriptParser::readSymbolAssignment(StringRef Name) {
+  expect("=");
+  std::vector<StringRef> Expr = readSectionsCommandExpr();
+  if (Expr.empty())
+    error("error in symbol assignment expression");
+  else
+    Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name});
+}
+
+std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
+  std::vector<StringRef> Expr;
+  while (!Error) {
+    StringRef Tok = next();
+    if (Tok == ";")
+      break;
+    Expr.push_back(Tok);
+  }
+  return Expr;
+}
+
+static bool isUnderSysroot(StringRef Path) {
+  if (Config->Sysroot == "")
+    return false;
+  for (; !Path.empty(); Path = sys::path::parent_path(Path))
+    if (sys::fs::equivalent(Config->Sysroot, Path))
+      return true;
+  return false;
+}
+
+// Entry point.
+void elf::readLinkerScript(MemoryBufferRef MB) {
+  StringRef Path = MB.getBufferIdentifier();
+  ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run();
+}
+
+template class elf::LinkerScript<ELF32LE>;
+template class elf::LinkerScript<ELF32BE>;
+template class elf::LinkerScript<ELF64LE>;
+template class elf::LinkerScript<ELF64BE>;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
new file mode 100644 (file)
index 0000000..768f78a
--- /dev/null
@@ -0,0 +1,103 @@
+//===- LinkerScript.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LINKER_SCRIPT_H
+#define LLD_ELF_LINKER_SCRIPT_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+// Parses a linker script. Calling this function updates
+// Config and ScriptConfig.
+void readLinkerScript(MemoryBufferRef MB);
+
+class ScriptParser;
+template <class ELFT> class InputSectionBase;
+template <class ELFT> class OutputSectionBase;
+
+// This class represents each rule in SECTIONS command.
+struct SectionRule {
+  SectionRule(StringRef D, StringRef S)
+      : Dest(D), SectionPattern(S) {}
+
+  StringRef Dest;
+
+  StringRef SectionPattern;
+};
+
+// This enum represents what we can observe in SECTIONS tag of script:
+// ExprKind is a location counter change, like ". = . + 0x1000"
+// SectionKind is a description of output section, like ".data :..."
+enum SectionsCommandKind { SectionKind, AssignmentKind };
+
+struct SectionsCommand {
+  SectionsCommandKind Kind;
+  std::vector<StringRef> Expr;
+  StringRef Name;
+};
+
+// ScriptConfiguration holds linker script parse results.
+struct ScriptConfiguration {
+  // SECTIONS commands.
+  std::vector<SectionRule> Sections;
+
+  // Section fill attribute for each section.
+  llvm::StringMap<std::vector<uint8_t>> Filler;
+
+  // Used to assign addresses to sections.
+  std::vector<SectionsCommand> Commands;
+
+  bool DoLayout = false;
+
+  llvm::BumpPtrAllocator Alloc;
+
+  // List of section patterns specified with KEEP commands. They will
+  // be kept even if they are unused and --gc-sections is specified.
+  std::vector<StringRef> KeptSections;
+};
+
+extern ScriptConfiguration *ScriptConfig;
+
+// This is a runner of the linker script.
+template <class ELFT> class LinkerScript {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  StringRef getOutputSection(InputSectionBase<ELFT> *S);
+  ArrayRef<uint8_t> getFiller(StringRef Name);
+  bool isDiscarded(InputSectionBase<ELFT> *S);
+  bool shouldKeep(InputSectionBase<ELFT> *S);
+  void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S);
+  int compareSections(StringRef A, StringRef B);
+  void addScriptedSymbols();
+
+private:
+  // "ScriptConfig" is a bit too long, so define a short name for it.
+  ScriptConfiguration &Opt = *ScriptConfig;
+
+  int getSectionIndex(StringRef Name);
+
+  uintX_t Dot;
+};
+
+// Variable template is a C++14 feature, so we can't template
+// a global variable. Use a struct to workaround.
+template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
+template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
new file mode 100644 (file)
index 0000000..41e30ce
--- /dev/null
@@ -0,0 +1,201 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements --gc-sections, which is a feature to remove unused
+// sections from output. Unused sections are sections that are not reachable
+// from known GC-root symbols or sections. Naturally the feature is
+// implemented as a mark-sweep garbage collector.
+//
+// Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off
+// by default. Starting with GC-root symbols or sections, markLive function
+// defined in this file visits all reachable sections to set their Live
+// bits. Writer will then ignore sections whose Live bits are off, so that
+// such sections are not included into output.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ELF.h"
+#include <functional>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+// A resolved relocation. The Sec and Offset fields are set if the relocation
+// was resolved to an offset within a section.
+template <class ELFT>
+struct ResolvedReloc {
+  InputSectionBase<ELFT> *Sec;
+  typename ELFT::uint Offset;
+};
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+                                     const typename ELFT::Rel &Rel) {
+  return Target->getImplicitAddend(Sec.getSectionData().begin(),
+                                   Rel.getType(Config->Mips64EL));
+}
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+                                     const typename ELFT::Rela &Rel) {
+  return Rel.r_addend;
+}
+
+template <class ELFT, class RelT>
+static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
+                                        RelT &Rel) {
+  SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel);
+  auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
+  if (!D || !D->Section)
+    return {nullptr, 0};
+  typename ELFT::uint Offset = D->Value;
+  if (D->isSection())
+    Offset += getAddend(Sec, Rel);
+  return {D->Section->Repl, Offset};
+}
+
+template <class ELFT, class Elf_Shdr>
+static void run(ELFFile<ELFT> &Obj, InputSectionBase<ELFT> &Sec,
+                Elf_Shdr *RelSec, std::function<void(ResolvedReloc<ELFT>)> Fn) {
+  if (RelSec->sh_type == SHT_RELA) {
+    for (const typename ELFT::Rela &RI : Obj.relas(RelSec))
+      Fn(resolveReloc(Sec, RI));
+  } else {
+    for (const typename ELFT::Rel &RI : Obj.rels(RelSec))
+      Fn(resolveReloc(Sec, RI));
+  }
+}
+
+// Calls Fn for each section that Sec refers to via relocations.
+template <class ELFT>
+static void forEachSuccessor(InputSection<ELFT> &Sec,
+                             std::function<void(ResolvedReloc<ELFT>)> Fn) {
+  ELFFile<ELFT> &Obj = Sec.getFile()->getObj();
+  for (const typename ELFT::Shdr *RelSec : Sec.RelocSections)
+    run(Obj, Sec, RelSec, Fn);
+}
+
+template <class ELFT>
+static void scanEhFrameSection(EhInputSection<ELFT> &EH,
+                               std::function<void(ResolvedReloc<ELFT>)> Fn) {
+  if (!EH.RelocSection)
+    return;
+  ELFFile<ELFT> &EObj = EH.getFile()->getObj();
+  run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
+    if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+      return;
+    if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
+      return;
+    Fn({R.Sec, 0});
+  });
+}
+
+// Sections listed below are special because they are used by the loader
+// just by being in an ELF file. They should not be garbage-collected.
+template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
+  switch (Sec->getSectionHdr()->sh_type) {
+  case SHT_FINI_ARRAY:
+  case SHT_INIT_ARRAY:
+  case SHT_NOTE:
+  case SHT_PREINIT_ARRAY:
+    return true;
+  default:
+    StringRef S = Sec->getSectionName();
+
+    // We do not want to reclaim sections if they can be referred
+    // by __start_* and __stop_* symbols.
+    if (isValidCIdentifier(S))
+      return true;
+
+    return S.startswith(".ctors") || S.startswith(".dtors") ||
+           S.startswith(".init") || S.startswith(".fini") ||
+           S.startswith(".jcr");
+  }
+}
+
+// This is the main function of the garbage collector.
+// Starting from GC-root sections, this function visits all reachable
+// sections to set their "Live" bits.
+template <class ELFT> void elf::markLive() {
+  SmallVector<InputSection<ELFT> *, 256> Q;
+
+  auto Enqueue = [&](ResolvedReloc<ELFT> R) {
+    if (!R.Sec)
+      return;
+
+    // Usually, a whole section is marked as live or dead, but in mergeable
+    // (splittable) sections, each piece of data has independent liveness bit.
+    // So we explicitly tell it which offset is in use.
+    if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec))
+      MS->markLiveAt(R.Offset);
+
+    if (R.Sec->Live)
+      return;
+    R.Sec->Live = true;
+    if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
+      Q.push_back(S);
+  };
+
+  auto MarkSymbol = [&](const SymbolBody *Sym) {
+    if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
+      Enqueue({D->Section, D->Value});
+  };
+
+  // Add GC root symbols.
+  if (Config->EntrySym)
+    MarkSymbol(Config->EntrySym->body());
+  MarkSymbol(Symtab<ELFT>::X->find(Config->Init));
+  MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
+  for (StringRef S : Config->Undefined)
+    MarkSymbol(Symtab<ELFT>::X->find(S));
+
+  // Preserve externally-visible symbols if the symbols defined by this
+  // file can interrupt other ELF file's symbols at runtime.
+  for (const Symbol *S : Symtab<ELFT>::X->getSymbols())
+    if (S->includeInDynsym())
+      MarkSymbol(S->body());
+
+  // Preserve special sections and those which are specified in linker
+  // script KEEP command.
+  for (const std::unique_ptr<ObjectFile<ELFT>> &F :
+       Symtab<ELFT>::X->getObjectFiles())
+    for (InputSectionBase<ELFT> *Sec : F->getSections())
+      if (Sec && Sec != &InputSection<ELFT>::Discarded) {
+        // .eh_frame is always marked as live now, but also it can reference to
+        // sections that contain personality. We preserve all non-text sections
+        // referred by .eh_frame here.
+        if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
+          scanEhFrameSection<ELFT>(*EH, Enqueue);
+        if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
+          Enqueue({Sec, 0});
+      }
+
+  // Mark all reachable sections.
+  while (!Q.empty())
+    forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue);
+}
+
+template void elf::markLive<ELF32LE>();
+template void elf::markLive<ELF32BE>();
+template void elf::markLive<ELF64LE>();
+template void elf::markLive<ELF64BE>();
diff --git a/ELF/Options.td b/ELF/Options.td
new file mode 100644 (file)
index 0000000..010f376
--- /dev/null
@@ -0,0 +1,276 @@
+include "llvm/Option/OptParser.td"
+
+// For options whose names are multiple letters, either one dash or
+// two can precede the option name except those that start with 'o'.
+class F<string name>: Flag<["--", "-"], name>;
+class J<string name>: Joined<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+class JS<string name>: JoinedOrSeparate<["--", "-"], name>;
+
+def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
+
+def Bsymbolic_functions: F<"Bsymbolic-functions">,
+  HelpText<"Bind defined function symbols locally">;
+
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
+
+def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
+
+def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+
+def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+  HelpText<"Add a directory to the library search path">;
+
+def O: Joined<["-"], "O">, HelpText<"Optimize output file size">;
+
+def allow_multiple_definition: F<"allow-multiple-definition">,
+  HelpText<"Allow multiple definitions">;
+
+def as_needed: F<"as-needed">,
+  HelpText<"Only set DT_NEEDED for shared libraries if used">;
+
+def disable_new_dtags: F<"disable-new-dtags">,
+  HelpText<"Disable new dynamic tags">;
+
+def discard_all: F<"discard-all">, HelpText<"Delete all local symbols">;
+
+def discard_locals: F<"discard-locals">,
+  HelpText<"Delete temporary local symbols">;
+
+def discard_none: F<"discard-none">,
+  HelpText<"Keep all symbols in the symbol table">;
+
+def dynamic_linker: S<"dynamic-linker">,
+  HelpText<"Which dynamic linker to use">;
+
+def dynamic_list: S<"dynamic-list">,
+  HelpText<"Read a list of dynamic symbols">;
+
+def eh_frame_hdr: F<"eh-frame-hdr">,
+  HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+
+def enable_new_dtags: F<"enable-new-dtags">,
+  HelpText<"Enable new dynamic tags">;
+
+def end_lib: F<"end-lib">,
+  HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
+
+def entry: S<"entry">, MetaVarName<"<entry>">,
+  HelpText<"Name of entry point symbol">;
+
+def export_dynamic: F<"export-dynamic">,
+  HelpText<"Put symbols in the dynamic symbol table">;
+
+def export_dynamic_symbol: S<"export-dynamic-symbol">,
+  HelpText<"Put a symbol in the dynamic symbol table">;
+
+def fatal_warnings: F<"fatal-warnings">,
+  HelpText<"Treat warnings as errors">;
+
+def fini: S<"fini">, MetaVarName<"<symbol>">,
+  HelpText<"Specify a finalizer function">;
+
+def hash_style: S<"hash-style">,
+  HelpText<"Specify hash style (sysv, gnu or both)">;
+
+def help: F<"help">, HelpText<"Print option help">;
+
+def icf: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def image_base : J<"image-base=">, HelpText<"Set the base address">;
+
+def gc_sections: F<"gc-sections">,
+  HelpText<"Enable garbage collection of unused sections">;
+
+def init: S<"init">, MetaVarName<"<symbol>">,
+  HelpText<"Specify an initializer function">;
+
+def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
+  HelpText<"Root name of library to use">;
+
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+  HelpText<"Optimization level for LTO">;
+
+def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+
+def no_as_needed: F<"no-as-needed">,
+  HelpText<"Always DT_NEEDED for shared libraries">;
+
+def no_demangle: F<"no-demangle">,
+  HelpText<"Do not demangle symbol names">;
+
+def no_gnu_unique: F<"no-gnu-unique">,
+  HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
+
+def no_whole_archive: F<"no-whole-archive">,
+  HelpText<"Restores the default behavior of loading archive members">;
+
+def noinhibit_exec: F<"noinhibit-exec">,
+  HelpText<"Retain the executable output file whenever it is still usable">;
+
+def no_undefined: F<"no-undefined">,
+  HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
+
+def no_undefined_version: F<"no-undefined-version">,
+  HelpText<"Report version scripts that refer undefined symbols">;
+
+def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
+  HelpText<"Path to file to write output">;
+
+def pie: F<"pie">, HelpText<"Create a position independent executable">;
+
+def print_gc_sections: F<"print-gc-sections">,
+  HelpText<"List removed unused sections">;
+
+def reproduce: S<"reproduce">,
+  HelpText<"Dump linker invocation and input files for debugging">;
+
+def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+
+def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+
+def script: S<"script">, HelpText<"Read linker script">;
+
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
+def soname: J<"soname=">, HelpText<"Set DT_SONAME">;
+
+def start_lib: F<"start-lib">,
+  HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
+
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
+
+def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+
+def sysroot: J<"sysroot=">, HelpText<"Set the system root">;
+
+def threads: F<"threads">, HelpText<"Enable use of threads">;
+
+def trace: F<"trace">, HelpText<"Print the names of the input files">;
+
+def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+
+def undefined: J<"undefined=">,
+  HelpText<"Force undefined symbol during linking">;
+
+def unresolved_symbols: J<"unresolved-symbols=">,
+  HelpText<"Determine how to handle unresolved symbols">;
+
+def rsp_quoting: J<"rsp-quoting=">,
+  HelpText<"Quoting style for response files. Values supported: windows|posix">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def version: F<"version">, HelpText<"Display the version number">;
+
+def version_script: S<"version-script">,
+  HelpText<"Read a version script">;
+
+def warn_common: F<"warn-common">,
+  HelpText<"Warn about duplicate common symbols">;
+
+def whole_archive: F<"whole-archive">,
+  HelpText<"Force load of all members in a static library">;
+
+def wrap: S<"wrap">, MetaVarName<"<symbol>">,
+  HelpText<"Use wrapper functions for symbol">;
+
+def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
+  HelpText<"Linker option extensions">;
+
+// Aliases
+def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
+def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
+def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
+def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
+def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
+def alias_L__library_path: J<"library-path=">, Alias<L>;
+def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
+def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
+def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def alias_entry_entry: J<"entry=">, Alias<entry>;
+def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
+def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
+  Alias<export_dynamic_symbol>;
+def alias_fini_fini: J<"fini=">, Alias<fini>;
+def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
+def alias_init_init: J<"init=">, Alias<init>;
+def alias_l__library: J<"library=">, Alias<l>;
+def alias_o_output: Joined<["--"], "output=">, Alias<o>;
+def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
+def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_rpath_R: Joined<["-"], "R">, Alias<rpath>;
+def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
+def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
+def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
+def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
+def alias_soname_soname: S<"soname">, Alias<soname>;
+def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
+def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
+def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
+def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def alias_version_V: Flag<["-"], "V">, Alias<version>;
+def alias_version_v: Flag<["-"], "v">, Alias<version>;
+def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
+
+// Our symbol resolution algorithm handles symbols in archive files differently
+// than traditional linkers, so we don't need --start-group and --end-group.
+// These options are recongized for compatibility but ignored.
+def end_group: F<"end-group">;
+def end_group_paren: Flag<["-"], ")">;
+def start_group: F<"start-group">;
+def start_group_paren: Flag<["-"], "(">;
+
+// Ignore LTO plugin-related options.
+// clang -flto passes -plugin and -plugin-opt to the linker. This is required
+// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
+// rely on a plugin. Instead of detecting which linker is used on clang side we
+// just ignore the option on lld side as it's easier. In fact, the linker could
+// be called 'ld' and understanding which linker is used would require parsing of
+// --version output.
+def plugin: S<"plugin">;
+def plugin_eq: J<"plugin=">;
+def plugin_opt: S<"plugin-opt">;
+def plugin_opt_eq: J<"plugin-opt=">;
+
+// Options listed below are silently ignored for now for compatibility.
+def allow_shlib_undefined: F<"allow-shlib-undefined">;
+def define_common: F<"define-common">;
+def demangle: F<"demangle">;
+def detect_odr_violations: F<"detect-odr-violations">;
+def no_add_needed: F<"no-add-needed">;
+def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
+def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
+  Alias<no_add_needed>;
+def no_dynamic_linker: F<"no-dynamic-linker">;
+def no_fatal_warnings: F<"no-fatal-warnings">;
+def no_mmap_output_file: F<"no-mmap-output-file">;
+def no_warn_common: F<"no-warn-common">;
+def no_warn_mismatch: F<"no-warn-mismatch">;
+def rpath_link: S<"rpath-link">;
+def rpath_link_eq: J<"rpath-link=">;
+def sort_common: F<"sort-common">;
+def warn_execstack: F<"warn-execstack">;
+def warn_shared_textrel: F<"warn-shared-textrel">;
+def G: Separate<["-"], "G">;
+
+// Aliases for ignored options
+def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
+def alias_define_common_dc: F<"dc">, Alias<define_common>;
+def alias_define_common_dp: F<"dp">, Alias<define_common>;
+def alias_version_script_version_script: J<"version-script=">,
+  Alias<version_script>;
+
+// LTO-related options.
+def lto_jobs: J<"lto-jobs=">, HelpText<"Number of threads to run codegen">;
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+  HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+  HelpText<"Passes to run during LTO">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+def save_temps: F<"save-temps">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
new file mode 100644 (file)
index 0000000..50b9401
--- /dev/null
@@ -0,0 +1,1965 @@
+//===- OutputSections.cpp -------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "Config.h"
+#include "EhFrame.h"
+#include "LinkerScript.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SHA1.h"
+#include <map>
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT>
+OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
+                                           uintX_t Flags)
+    : Name(Name) {
+  memset(&Header, 0, sizeof(Elf_Shdr));
+  Header.sh_type = Type;
+  Header.sh_flags = Flags;
+  Header.sh_addralign = 1;
+}
+
+template <class ELFT>
+void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *Shdr) {
+  *Shdr = Header;
+}
+
+template <class ELFT>
+GotPltSection<ELFT>::GotPltSection()
+    : OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
+  this->Header.sh_addralign = Target->GotPltEntrySize;
+}
+
+template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+  Entries.push_back(&Sym);
+}
+
+template <class ELFT> bool GotPltSection<ELFT>::empty() const {
+  return Entries.empty();
+}
+
+template <class ELFT> void GotPltSection<ELFT>::finalize() {
+  this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) *
+                         Target->GotPltEntrySize;
+}
+
+template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+  Target->writeGotPltHeader(Buf);
+  Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
+  for (const SymbolBody *B : Entries) {
+    Target->writeGotPlt(Buf, *B);
+    Buf += sizeof(uintX_t);
+  }
+}
+
+template <class ELFT>
+GotSection<ELFT>::GotSection()
+    : OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
+  if (Config->EMachine == EM_MIPS)
+    this->Header.sh_flags |= SHF_MIPS_GPREL;
+  this->Header.sh_addralign = Target->GotEntrySize;
+}
+
+template <class ELFT>
+void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.GotIndex = Entries.size();
+  Entries.push_back(&Sym);
+}
+
+template <class ELFT>
+void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
+                                    RelExpr Expr) {
+  // For "true" local symbols which can be referenced from the same module
+  // only compiler creates two instructions for address loading:
+  //
+  // lw   $8, 0($gp) # R_MIPS_GOT16
+  // addi $8, $8, 0  # R_MIPS_LO16
+  //
+  // The first instruction loads high 16 bits of the symbol address while
+  // the second adds an offset. That allows to reduce number of required
+  // GOT entries because only one global offset table entry is necessary
+  // for every 64 KBytes of local data. So for local symbols we need to
+  // allocate number of GOT entries to hold all required "page" addresses.
+  //
+  // All global symbols (hidden and regular) considered by compiler uniformly.
+  // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
+  // to load address of the symbol. So for each such symbol we need to
+  // allocate dedicated GOT entry to store its address.
+  //
+  // If a symbol is preemptible we need help of dynamic linker to get its
+  // final address. The corresponding GOT entries are allocated in the
+  // "global" part of GOT. Entries for non preemptible global symbol allocated
+  // in the "local" part of GOT.
+  //
+  // See "Global Offset Table" in Chapter 5:
+  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
+    // At this point we do not know final symbol value so to reduce number
+    // of allocated GOT entries do the following trick. Save all output
+    // sections referenced by GOT relocations. Then later in the `finalize`
+    // method calculate number of "pages" required to cover all saved output
+    // section and allocate appropriate number of GOT entries.
+    auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
+    MipsOutSections.insert(OutSec);
+    return;
+  }
+  if (Sym.isTls()) {
+    // GOT entries created for MIPS TLS relocations behave like
+    // almost GOT entries from other ABIs. They go to the end
+    // of the global offset table.
+    Sym.GotIndex = Entries.size();
+    Entries.push_back(&Sym);
+    return;
+  }
+  auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
+    if (S.isInGot() && !A)
+      return;
+    size_t NewIndex = Items.size();
+    if (!MipsGotMap.insert({{&S, A}, NewIndex}).second)
+      return;
+    Items.emplace_back(&S, A);
+    if (!A)
+      S.GotIndex = NewIndex;
+  };
+  if (Sym.isPreemptible()) {
+    // Ignore addends for preemptible symbols. They got single GOT entry anyway.
+    AddEntry(Sym, 0, MipsGlobal);
+    Sym.IsInGlobalMipsGot = true;
+  } else
+    AddEntry(Sym, Addend, MipsLocal);
+}
+
+template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+  if (Sym.GlobalDynIndex != -1U)
+    return false;
+  Sym.GlobalDynIndex = Entries.size();
+  // Global Dynamic TLS entries take two GOT slots.
+  Entries.push_back(nullptr);
+  Entries.push_back(&Sym);
+  return true;
+}
+
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
+  if (TlsIndexOff != uint32_t(-1))
+    return false;
+  TlsIndexOff = Entries.size() * sizeof(uintX_t);
+  Entries.push_back(nullptr);
+  Entries.push_back(nullptr);
+  return true;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
+  // Initialize the entry by the %hi(EntryValue) expression
+  // but without right-shifting.
+  EntryValue = (EntryValue + 0x8000) & ~0xffff;
+  // Take into account MIPS GOT header.
+  // See comment in the GotSection::writeTo.
+  size_t NewIndex = MipsLocalGotPos.size() + 2;
+  auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
+  assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
+  return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
+  uintX_t Off = MipsPageEntries;
+  if (B.isTls())
+    Off += MipsLocal.size() + MipsGlobal.size() + B.GotIndex;
+  else if (B.IsInGlobalMipsGot)
+    Off += MipsLocal.size() + B.GotIndex;
+  else if (B.isInGot())
+    Off += B.GotIndex;
+  else {
+    auto It = MipsGotMap.find({&B, Addend});
+    assert(It != MipsGotMap.end());
+    Off += It->second;
+  }
+  return Off * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() {
+  return (MipsPageEntries + MipsLocal.size() + MipsGlobal.size()) *
+         sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
+  return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+  return B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
+  return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
+}
+
+template <class ELFT>
+unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
+  return MipsPageEntries + MipsLocal.size();
+}
+
+template <class ELFT> void GotSection<ELFT>::finalize() {
+  size_t EntriesNum = Entries.size();
+  if (Config->EMachine == EM_MIPS) {
+    // Take into account MIPS GOT header.
+    // See comment in the GotSection::writeTo.
+    MipsPageEntries += 2;
+    for (const OutputSectionBase<ELFT> *OutSec : MipsOutSections) {
+      // Calculate an upper bound of MIPS GOT entries required to store page
+      // addresses of local symbols. We assume the worst case - each 64kb
+      // page of the output section has at least one GOT relocation against it.
+      // Add 0x8000 to the section's size because the page address stored
+      // in the GOT entry is calculated as (value + 0x8000) & ~0xffff.
+      MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff;
+    }
+    EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size();
+  }
+  this->Header.sh_size = EntriesNum * sizeof(uintX_t);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
+  // Set the MSB of the second GOT slot. This is not required by any
+  // MIPS ABI documentation, though.
+  //
+  // There is a comment in glibc saying that "The MSB of got[1] of a
+  // gnu object is set to identify gnu objects," and in GNU gold it
+  // says "the second entry will be used by some runtime loaders".
+  // But how this field is being used is unclear.
+  //
+  // We are not really willing to mimic other linkers behaviors
+  // without understanding why they do that, but because all files
+  // generated by GNU tools have this special GOT value, and because
+  // we've been doing this for years, it is probably a safe bet to
+  // keep doing this for now. We really need to revisit this to see
+  // if we had to do this.
+  auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
+  P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+  // Write 'page address' entries to the local part of the GOT.
+  for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
+    uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
+  }
+  Buf += MipsPageEntries * sizeof(uintX_t);
+  auto AddEntry = [&](const MipsGotEntry &SA) {
+    uint8_t *Entry = Buf;
+    Buf += sizeof(uintX_t);
+    const SymbolBody* Body = SA.first;
+    uintX_t VA = Body->template getVA<ELFT>(SA.second);
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+  };
+  std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
+  std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+  if (Config->EMachine == EM_MIPS)
+    writeMipsGot(Buf);
+  for (const SymbolBody *B : Entries) {
+    uint8_t *Entry = Buf;
+    Buf += sizeof(uintX_t);
+    if (!B)
+      continue;
+    if (B->isPreemptible())
+      continue; // The dynamic linker will take care of it.
+    uintX_t VA = B->getVA<ELFT>();
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+  }
+}
+
+template <class ELFT>
+PltSection<ELFT>::PltSection()
+    : OutputSectionBase<ELFT>(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
+  this->Header.sh_addralign = 16;
+}
+
+template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
+  // At beginning of PLT, we have code to call the dynamic linker
+  // to resolve dynsyms at runtime. Write such code.
+  Target->writePltHeader(Buf);
+  size_t Off = Target->PltHeaderSize;
+
+  for (auto &I : Entries) {
+    const SymbolBody *B = I.first;
+    unsigned RelOff = I.second;
+    uint64_t Got = B->getGotPltVA<ELFT>();
+    uint64_t Plt = this->getVA() + Off;
+    Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+    Off += Target->PltEntrySize;
+  }
+}
+
+template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.PltIndex = Entries.size();
+  unsigned RelOff = Out<ELFT>::RelaPlt->getRelocOffset();
+  Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+template <class ELFT> void PltSection<ELFT>::finalize() {
+  this->Header.sh_size =
+      Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
+}
+
+template <class ELFT>
+RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
+    : OutputSectionBase<ELFT>(Name, Config->Rela ? SHT_RELA : SHT_REL,
+                              SHF_ALLOC),
+      Sort(Sort) {
+  this->Header.sh_entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+  this->Header.sh_addralign = sizeof(uintX_t);
+}
+
+template <class ELFT>
+void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
+  Relocs.push_back(Reloc);
+}
+
+template <class ELFT, class RelTy>
+static bool compRelocations(const RelTy &A, const RelTy &B) {
+  return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL);
+}
+
+template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
+  uint8_t *BufBegin = Buf;
+  for (const DynamicReloc<ELFT> &Rel : Relocs) {
+    auto *P = reinterpret_cast<Elf_Rela *>(Buf);
+    Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+
+    if (Config->Rela)
+      P->r_addend = Rel.getAddend();
+    P->r_offset = Rel.getOffset();
+    if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
+      // Dynamic relocation against MIPS GOT section make deal TLS entries
+      // allocated in the end of the GOT. We need to adjust the offset to take
+      // in account 'local' and 'global' GOT entries.
+      P->r_offset += Out<ELFT>::Got->getMipsTlsOffset();
+    P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
+  }
+
+  if (Sort) {
+    if (Config->Rela)
+      std::stable_sort((Elf_Rela *)BufBegin,
+                       (Elf_Rela *)BufBegin + Relocs.size(),
+                       compRelocations<ELFT, Elf_Rela>);
+    else
+      std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
+                       compRelocations<ELFT, Elf_Rel>);
+  }
+}
+
+template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
+  return this->Header.sh_entsize * Relocs.size();
+}
+
+template <class ELFT> void RelocationSection<ELFT>::finalize() {
+  this->Header.sh_link = Static ? Out<ELFT>::SymTab->SectionIndex
+                                : Out<ELFT>::DynSymTab->SectionIndex;
+  this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
+}
+
+template <class ELFT>
+InterpSection<ELFT>::InterpSection()
+    : OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) {
+  this->Header.sh_size = Config->DynamicLinker.size() + 1;
+}
+
+template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
+  StringRef S = Config->DynamicLinker;
+  memcpy(Buf, S.data(), S.size());
+}
+
+template <class ELFT>
+HashTableSection<ELFT>::HashTableSection()
+    : OutputSectionBase<ELFT>(".hash", SHT_HASH, SHF_ALLOC) {
+  this->Header.sh_entsize = sizeof(Elf_Word);
+  this->Header.sh_addralign = sizeof(Elf_Word);
+}
+
+static uint32_t hashSysv(StringRef Name) {
+  uint32_t H = 0;
+  for (char C : Name) {
+    H = (H << 4) + C;
+    uint32_t G = H & 0xf0000000;
+    if (G)
+      H ^= G >> 24;
+    H &= ~G;
+  }
+  return H;
+}
+
+template <class ELFT> void HashTableSection<ELFT>::finalize() {
+  this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
+
+  unsigned NumEntries = 2;                             // nbucket and nchain.
+  NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
+
+  // Create as many buckets as there are symbols.
+  // FIXME: This is simplistic. We can try to optimize it, but implementing
+  // support for SHT_GNU_HASH is probably even more profitable.
+  NumEntries += Out<ELFT>::DynSymTab->getNumSymbols();
+  this->Header.sh_size = NumEntries * sizeof(Elf_Word);
+}
+
+template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  unsigned NumSymbols = Out<ELFT>::DynSymTab->getNumSymbols();
+  auto *P = reinterpret_cast<Elf_Word *>(Buf);
+  *P++ = NumSymbols; // nbucket
+  *P++ = NumSymbols; // nchain
+
+  Elf_Word *Buckets = P;
+  Elf_Word *Chains = P + NumSymbols;
+
+  for (const std::pair<SymbolBody *, unsigned> &P :
+       Out<ELFT>::DynSymTab->getSymbols()) {
+    SymbolBody *Body = P.first;
+    StringRef Name = Body->getName();
+    unsigned I = Body->DynsymIndex;
+    uint32_t Hash = hashSysv(Name) % NumSymbols;
+    Chains[I] = Buckets[Hash];
+    Buckets[Hash] = I;
+  }
+}
+
+static uint32_t hashGnu(StringRef Name) {
+  uint32_t H = 5381;
+  for (uint8_t C : Name)
+    H = (H << 5) + H + C;
+  return H;
+}
+
+template <class ELFT>
+GnuHashTableSection<ELFT>::GnuHashTableSection()
+    : OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) {
+  this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4;
+  this->Header.sh_addralign = sizeof(uintX_t);
+}
+
+template <class ELFT>
+unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
+  if (!NumHashed)
+    return 0;
+
+  // These values are prime numbers which are not greater than 2^(N-1) + 1.
+  // In result, for any particular NumHashed we return a prime number
+  // which is not greater than NumHashed.
+  static const unsigned Primes[] = {
+      1,   1,    3,    3,    7,    13,    31,    61,    127,   251,
+      509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
+
+  return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
+                                   array_lengthof(Primes) - 1)];
+}
+
+// Bloom filter estimation: at least 8 bits for each hashed symbol.
+// GNU Hash table requirement: it should be a power of 2,
+//   the minimum value is 1, even for an empty table.
+// Expected results for a 32-bit target:
+//   calcMaskWords(0..4)   = 1
+//   calcMaskWords(5..8)   = 2
+//   calcMaskWords(9..16)  = 4
+// For a 64-bit target:
+//   calcMaskWords(0..8)   = 1
+//   calcMaskWords(9..16)  = 2
+//   calcMaskWords(17..32) = 4
+template <class ELFT>
+unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
+  if (!NumHashed)
+    return 1;
+  return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
+}
+
+template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
+  unsigned NumHashed = Symbols.size();
+  NBuckets = calcNBuckets(NumHashed);
+  MaskWords = calcMaskWords(NumHashed);
+  // Second hash shift estimation: just predefined values.
+  Shift2 = ELFT::Is64Bits ? 6 : 5;
+
+  this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
+  this->Header.sh_size = sizeof(Elf_Word) * 4            // Header
+                         + sizeof(Elf_Off) * MaskWords   // Bloom Filter
+                         + sizeof(Elf_Word) * NBuckets   // Hash Buckets
+                         + sizeof(Elf_Word) * NumHashed; // Hash Values
+}
+
+template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  writeHeader(Buf);
+  if (Symbols.empty())
+    return;
+  writeBloomFilter(Buf);
+  writeHashTable(Buf);
+}
+
+template <class ELFT>
+void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
+  auto *P = reinterpret_cast<Elf_Word *>(Buf);
+  *P++ = NBuckets;
+  *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
+  *P++ = MaskWords;
+  *P++ = Shift2;
+  Buf = reinterpret_cast<uint8_t *>(P);
+}
+
+template <class ELFT>
+void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
+  unsigned C = sizeof(Elf_Off) * 8;
+
+  auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
+  for (const SymbolData &Sym : Symbols) {
+    size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
+    uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
+                (uintX_t(1) << ((Sym.Hash >> Shift2) % C));
+    Masks[Pos] |= V;
+  }
+  Buf += sizeof(Elf_Off) * MaskWords;
+}
+
+template <class ELFT>
+void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
+  Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
+  Elf_Word *Values = Buckets + NBuckets;
+
+  int PrevBucket = -1;
+  int I = 0;
+  for (const SymbolData &Sym : Symbols) {
+    int Bucket = Sym.Hash % NBuckets;
+    assert(PrevBucket <= Bucket);
+    if (Bucket != PrevBucket) {
+      Buckets[Bucket] = Sym.Body->DynsymIndex;
+      PrevBucket = Bucket;
+      if (I > 0)
+        Values[I - 1] |= 1;
+    }
+    Values[I] = Sym.Hash & ~1;
+    ++I;
+  }
+  if (I > 0)
+    Values[I - 1] |= 1;
+}
+
+// Add symbols to this symbol hash table. Note that this function
+// destructively sort a given vector -- which is needed because
+// GNU-style hash table places some sorting requirements.
+template <class ELFT>
+void GnuHashTableSection<ELFT>::addSymbols(
+    std::vector<std::pair<SymbolBody *, size_t>> &V) {
+  // Ideally this will just be 'auto' but GCC 6.1 is not able
+  // to deduce it correctly.
+  std::vector<std::pair<SymbolBody *, size_t>>::iterator Mid =
+      std::stable_partition(V.begin(), V.end(),
+                            [](std::pair<SymbolBody *, size_t> &P) {
+                              return P.first->isUndefined();
+                            });
+  if (Mid == V.end())
+    return;
+  for (auto I = Mid, E = V.end(); I != E; ++I) {
+    SymbolBody *B = I->first;
+    size_t StrOff = I->second;
+    Symbols.push_back({B, StrOff, hashGnu(B->getName())});
+  }
+
+  unsigned NBuckets = calcNBuckets(Symbols.size());
+  std::stable_sort(Symbols.begin(), Symbols.end(),
+                   [&](const SymbolData &L, const SymbolData &R) {
+                     return L.Hash % NBuckets < R.Hash % NBuckets;
+                   });
+
+  V.erase(Mid, V.end());
+  for (const SymbolData &Sym : Symbols)
+    V.push_back({Sym.Body, Sym.STName});
+}
+
+// Returns the number of version definition entries. Because the first entry
+// is for the version definition itself, it is the number of versioned symbols
+// plus one. Note that we don't support multiple versions yet.
+static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
+
+template <class ELFT>
+DynamicSection<ELFT>::DynamicSection()
+    : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) {
+  Elf_Shdr &Header = this->Header;
+  Header.sh_addralign = sizeof(uintX_t);
+  Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
+
+  // .dynamic section is not writable on MIPS.
+  // See "Special Section" in Chapter 4 in the following document:
+  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Config->EMachine == EM_MIPS)
+    Header.sh_flags = SHF_ALLOC;
+}
+
+template <class ELFT> void DynamicSection<ELFT>::finalize() {
+  if (this->Header.sh_size)
+    return; // Already finalized.
+
+  Elf_Shdr &Header = this->Header;
+  Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+
+  auto Add = [=](Entry E) { Entries.push_back(E); };
+
+  // Add strings. We know that these are the last strings to be added to
+  // DynStrTab and doing this here allows this function to set DT_STRSZ.
+  if (!Config->RPath.empty())
+    Add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
+         Out<ELFT>::DynStrTab->addString(Config->RPath)});
+  for (const std::unique_ptr<SharedFile<ELFT>> &F :
+       Symtab<ELFT>::X->getSharedFiles())
+    if (F->isNeeded())
+      Add({DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())});
+  if (!Config->SoName.empty())
+    Add({DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)});
+
+  Out<ELFT>::DynStrTab->finalize();
+
+  if (Out<ELFT>::RelaDyn->hasRelocs()) {
+    bool IsRela = Config->Rela;
+    Add({IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn});
+    Add({IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()});
+    Add({IsRela ? DT_RELAENT : DT_RELENT,
+         uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
+  }
+  if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
+    Add({DT_JMPREL, Out<ELFT>::RelaPlt});
+    Add({DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()});
+    Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
+         Out<ELFT>::GotPlt});
+    Add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
+  }
+
+  Add({DT_SYMTAB, Out<ELFT>::DynSymTab});
+  Add({DT_SYMENT, sizeof(Elf_Sym)});
+  Add({DT_STRTAB, Out<ELFT>::DynStrTab});
+  Add({DT_STRSZ, Out<ELFT>::DynStrTab->getSize()});
+  if (Out<ELFT>::GnuHashTab)
+    Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab});
+  if (Out<ELFT>::HashTab)
+    Add({DT_HASH, Out<ELFT>::HashTab});
+
+  if (PreInitArraySec) {
+    Add({DT_PREINIT_ARRAY, PreInitArraySec});
+    Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()});
+  }
+  if (InitArraySec) {
+    Add({DT_INIT_ARRAY, InitArraySec});
+    Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()});
+  }
+  if (FiniArraySec) {
+    Add({DT_FINI_ARRAY, FiniArraySec});
+    Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()});
+  }
+
+  if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Init))
+    Add({DT_INIT, B});
+  if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Fini))
+    Add({DT_FINI, B});
+
+  uint32_t DtFlags = 0;
+  uint32_t DtFlags1 = 0;
+  if (Config->Bsymbolic)
+    DtFlags |= DF_SYMBOLIC;
+  if (Config->ZNodelete)
+    DtFlags1 |= DF_1_NODELETE;
+  if (Config->ZNow) {
+    DtFlags |= DF_BIND_NOW;
+    DtFlags1 |= DF_1_NOW;
+  }
+  if (Config->ZOrigin) {
+    DtFlags |= DF_ORIGIN;
+    DtFlags1 |= DF_1_ORIGIN;
+  }
+
+  if (DtFlags)
+    Add({DT_FLAGS, DtFlags});
+  if (DtFlags1)
+    Add({DT_FLAGS_1, DtFlags1});
+
+  if (!Config->Entry.empty())
+    Add({DT_DEBUG, (uint64_t)0});
+
+  bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
+  if (HasVerNeed || Out<ELFT>::VerDef)
+    Add({DT_VERSYM, Out<ELFT>::VerSym});
+  if (Out<ELFT>::VerDef) {
+    Add({DT_VERDEF, Out<ELFT>::VerDef});
+    Add({DT_VERDEFNUM, getVerDefNum()});
+  }
+  if (HasVerNeed) {
+    Add({DT_VERNEED, Out<ELFT>::VerNeed});
+    Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()});
+  }
+
+  if (Config->EMachine == EM_MIPS) {
+    Add({DT_MIPS_RLD_VERSION, 1});
+    Add({DT_MIPS_FLAGS, RHF_NOTPOT});
+    Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
+    Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
+    Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
+    if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
+      Add({DT_MIPS_GOTSYM, B->DynsymIndex});
+    else
+      Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
+    Add({DT_PLTGOT, Out<ELFT>::Got});
+    if (Out<ELFT>::MipsRldMap)
+      Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
+  }
+
+  // +1 for DT_NULL
+  Header.sh_size = (Entries.size() + 1) * Header.sh_entsize;
+}
+
+template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
+
+  for (const Entry &E : Entries) {
+    P->d_tag = E.Tag;
+    switch (E.Kind) {
+    case Entry::SecAddr:
+      P->d_un.d_ptr = E.OutSec->getVA();
+      break;
+    case Entry::SymAddr:
+      P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+      break;
+    case Entry::PlainInt:
+      P->d_un.d_val = E.Val;
+      break;
+    }
+    ++P;
+  }
+}
+
+template <class ELFT>
+EhFrameHeader<ELFT>::EhFrameHeader()
+    : OutputSectionBase<ELFT>(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC) {}
+
+// .eh_frame_hdr contains a binary search table of pointers to FDEs.
+// Each entry of the search table consists of two values,
+// the starting PC from where FDEs covers, and the FDE's address.
+// It is sorted by PC.
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+
+  // Sort the FDE list by their PC and uniqueify. Usually there is only
+  // one FDE for a PC (i.e. function), but if ICF merges two functions
+  // into one, there can be more than one FDEs pointing to the address.
+  auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
+  std::stable_sort(Fdes.begin(), Fdes.end(), Less);
+  auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
+  Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
+
+  Buf[0] = 1;
+  Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+  Buf[2] = DW_EH_PE_udata4;
+  Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
+  write32<E>(Buf + 4, Out<ELFT>::EhFrame->getVA() - this->getVA() - 4);
+  write32<E>(Buf + 8, Fdes.size());
+  Buf += 12;
+
+  uintX_t VA = this->getVA();
+  for (FdeData &Fde : Fdes) {
+    write32<E>(Buf, Fde.Pc - VA);
+    write32<E>(Buf + 4, Fde.FdeVA - VA);
+    Buf += 8;
+  }
+}
+
+template <class ELFT> void EhFrameHeader<ELFT>::finalize() {
+  // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
+  this->Header.sh_size = 12 + Out<ELFT>::EhFrame->NumFdes * 8;
+}
+
+template <class ELFT>
+void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
+  Fdes.push_back({Pc, FdeVA});
+}
+
+template <class ELFT>
+OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
+    : OutputSectionBase<ELFT>(Name, Type, Flags) {
+  if (Type == SHT_RELA)
+    this->Header.sh_entsize = sizeof(Elf_Rela);
+  else if (Type == SHT_REL)
+    this->Header.sh_entsize = sizeof(Elf_Rel);
+}
+
+template <class ELFT> void OutputSection<ELFT>::finalize() {
+  uint32_t Type = this->Header.sh_type;
+  if (Type != SHT_RELA && Type != SHT_REL)
+    return;
+  this->Header.sh_link = Out<ELFT>::SymTab->SectionIndex;
+  // sh_info for SHT_REL[A] sections should contain the section header index of
+  // the section to which the relocation applies.
+  InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
+  this->Header.sh_info = S->OutSec->SectionIndex;
+}
+
+template <class ELFT>
+void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  assert(C->Live);
+  auto *S = cast<InputSection<ELFT>>(C);
+  Sections.push_back(S);
+  S->OutSec = this;
+  this->updateAlignment(S->Alignment);
+}
+
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+static int getPriority(StringRef S) {
+  size_t Pos = S.rfind('.');
+  if (Pos == StringRef::npos)
+    return 65536;
+  int V;
+  if (S.substr(Pos + 1).getAsInteger(10, V))
+    return 65536;
+  return V;
+}
+
+// This function is called after we sort input sections
+// and scan relocations to setup sections' offsets.
+template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
+  uintX_t Off = this->Header.sh_size;
+  for (InputSection<ELFT> *S : Sections) {
+    Off = alignTo(Off, S->Alignment);
+    S->OutSecOff = Off;
+    Off += S->getSize();
+  }
+  this->Header.sh_size = Off;
+}
+
+// Sorts input sections by section name suffixes, so that .foo.N comes
+// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
+// We want to keep the original order if the priorities are the same
+// because the compiler keeps the original initialization order in a
+// translation unit and we need to respect that.
+// For more detail, read the section of the GCC's manual about init_priority.
+template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
+  // Sort sections by priority.
+  typedef std::pair<int, InputSection<ELFT> *> Pair;
+  auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
+
+  std::vector<Pair> V;
+  for (InputSection<ELFT> *S : Sections)
+    V.push_back({getPriority(S->getSectionName()), S});
+  std::stable_sort(V.begin(), V.end(), Comp);
+  Sections.clear();
+  for (Pair &P : V)
+    Sections.push_back(P.second);
+}
+
+// Returns true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+  if (!S.endswith(".o"))
+    return false;
+  S = S.drop_back(2);
+  if (S.endswith(Filename))
+    return true;
+  return !S.empty() && S.drop_back().endswith(Filename);
+}
+
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
+
+// .ctors and .dtors are sorted by this priority from highest to lowest.
+//
+//  1. The section was contained in crtbegin (crtbegin contains
+//     some sentinel value in its .ctors and .dtors so that the runtime
+//     can find the beginning of the sections.)
+//
+//  2. The section has an optional priority value in the form of ".ctors.N"
+//     or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+//     they are compared as string rather than number.
+//
+//  3. The section is just ".ctors" or ".dtors".
+//
+//  4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .ctors are duplicate features (and .init_array is newer.) However, there
+// are too many real-world use cases of .ctors, so we had no choice to
+// support that with this rather ad-hoc semantics.
+template <class ELFT>
+static bool compCtors(const InputSection<ELFT> *A,
+                      const InputSection<ELFT> *B) {
+  bool BeginA = isCrtbegin(A->getFile()->getName());
+  bool BeginB = isCrtbegin(B->getFile()->getName());
+  if (BeginA != BeginB)
+    return BeginA;
+  bool EndA = isCrtend(A->getFile()->getName());
+  bool EndB = isCrtend(B->getFile()->getName());
+  if (EndA != EndB)
+    return EndB;
+  StringRef X = A->getSectionName();
+  StringRef Y = B->getSectionName();
+  assert(X.startswith(".ctors") || X.startswith(".dtors"));
+  assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+  X = X.substr(6);
+  Y = Y.substr(6);
+  if (X.empty() && Y.empty())
+    return false;
+  return X < Y;
+}
+
+// Sorts input sections by the special rules for .ctors and .dtors.
+// Unfortunately, the rules are different from the one for .{init,fini}_array.
+// Read the comment above.
+template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
+  std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
+}
+
+static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
+  size_t I = 0;
+  for (; I + A.size() < Size; I += A.size())
+    memcpy(Buf + I, A.data(), A.size());
+  memcpy(Buf + I, A.data(), Size - I);
+}
+
+template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  ArrayRef<uint8_t> Filler = Script<ELFT>::X->getFiller(this->Name);
+  if (!Filler.empty())
+    fill(Buf, this->getSize(), Filler);
+  if (Config->Threads) {
+    parallel_for_each(Sections.begin(), Sections.end(),
+                      [=](InputSection<ELFT> *C) { C->writeTo(Buf); });
+  } else {
+    for (InputSection<ELFT> *C : Sections)
+      C->writeTo(Buf);
+  }
+}
+
+template <class ELFT>
+EhOutputSection<ELFT>::EhOutputSection()
+    : OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
+
+// Returns the first relocation that points to a region
+// between Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef<RelTy> &Rels) {
+  for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
+    if (I->r_offset < Begin)
+      continue;
+
+    // Truncate Rels for fast access. That means we expect that the
+    // relocations are sorted and we are looking up symbols in
+    // sequential order. It is naturally satisfied for .eh_frame.
+    Rels = Rels.slice(I - Rels.begin());
+    if (I->r_offset < Begin + Size)
+      return I;
+    return nullptr;
+  }
+  Rels = ArrayRef<RelTy>();
+  return nullptr;
+}
+
+// Search for an existing CIE record or create a new one.
+// CIE records from input object files are uniquified by their contents
+// and where their relocations point to.
+template <class ELFT>
+template <class RelTy>
+CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
+                                         EhInputSection<ELFT> *Sec,
+                                         ArrayRef<RelTy> &Rels) {
+  const endianness E = ELFT::TargetEndianness;
+  if (read32<E>(Piece.data().data() + 4) != 0)
+    fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
+
+  SymbolBody *Personality = nullptr;
+  if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels))
+    Personality = &Sec->getFile()->getRelocTargetSym(*Rel);
+
+  // Search for an existing CIE by CIE contents/relocation target pair.
+  CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
+
+  // If not found, create a new one.
+  if (Cie->Piece == nullptr) {
+    Cie->Piece = &Piece;
+    Cies.push_back(Cie);
+  }
+  return Cie;
+}
+
+// There is one FDE per function. Returns true if a given FDE
+// points to a live function.
+template <class ELFT>
+template <class RelTy>
+bool EhOutputSection<ELFT>::isFdeLive(SectionPiece &Piece,
+                                      EhInputSection<ELFT> *Sec,
+                                      ArrayRef<RelTy> &Rels) {
+  const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels);
+  if (!Rel)
+    fatal("FDE doesn't reference another section");
+  SymbolBody &B = Sec->getFile()->getRelocTargetSym(*Rel);
+  auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
+  if (!D || !D->Section)
+    return false;
+  InputSectionBase<ELFT> *Target = D->Section->Repl;
+  return Target && Target->Live;
+}
+
+// .eh_frame is a sequence of CIE or FDE records. In general, there
+// is one CIE record per input object file which is followed by
+// a list of FDEs. This function searches an existing CIE or create a new
+// one and associates FDEs to the CIE.
+template <class ELFT>
+template <class RelTy>
+void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
+                                          ArrayRef<RelTy> Rels) {
+  const endianness E = ELFT::TargetEndianness;
+
+  DenseMap<size_t, CieRecord *> OffsetToCie;
+  for (SectionPiece &Piece : Sec->Pieces) {
+    // The empty record is the end marker.
+    if (Piece.size() == 4)
+      return;
+
+    size_t Offset = Piece.InputOff;
+    uint32_t ID = read32<E>(Piece.data().data() + 4);
+    if (ID == 0) {
+      OffsetToCie[Offset] = addCie(Piece, Sec, Rels);
+      continue;
+    }
+
+    uint32_t CieOffset = Offset + 4 - ID;
+    CieRecord *Cie = OffsetToCie[CieOffset];
+    if (!Cie)
+      fatal("invalid CIE reference");
+
+    if (!isFdeLive(Piece, Sec, Rels))
+      continue;
+    Cie->FdePieces.push_back(&Piece);
+    NumFdes++;
+  }
+}
+
+template <class ELFT>
+void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  auto *Sec = cast<EhInputSection<ELFT>>(C);
+  Sec->OutSec = this;
+  this->updateAlignment(Sec->Alignment);
+  Sections.push_back(Sec);
+
+  // .eh_frame is a sequence of CIE or FDE records. This function
+  // splits it into pieces so that we can call
+  // SplitInputSection::getSectionPiece on the section.
+  Sec->split();
+  if (Sec->Pieces.empty())
+    return;
+
+  if (const Elf_Shdr *RelSec = Sec->RelocSection) {
+    ELFFile<ELFT> &Obj = Sec->getFile()->getObj();
+    if (RelSec->sh_type == SHT_RELA)
+      addSectionAux(Sec, Obj.relas(RelSec));
+    else
+      addSectionAux(Sec, Obj.rels(RelSec));
+    return;
+  }
+  addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
+  memcpy(Buf, D.data(), D.size());
+
+  // Fix the size field. -4 since size does not include the size field itself.
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
+}
+
+template <class ELFT> void EhOutputSection<ELFT>::finalize() {
+  if (this->Header.sh_size)
+    return; // Already finalized.
+
+  size_t Off = 0;
+  for (CieRecord *Cie : Cies) {
+    Cie->Piece->OutputOff = Off;
+    Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
+
+    for (SectionPiece *Fde : Cie->FdePieces) {
+      Fde->OutputOff = Off;
+      Off += alignTo(Fde->size(), sizeof(uintX_t));
+    }
+  }
+  this->Header.sh_size = Off;
+}
+
+template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
+  const endianness E = ELFT::TargetEndianness;
+  switch (Size) {
+  case DW_EH_PE_udata2:
+    return read16<E>(Buf);
+  case DW_EH_PE_udata4:
+    return read32<E>(Buf);
+  case DW_EH_PE_udata8:
+    return read64<E>(Buf);
+  case DW_EH_PE_absptr:
+    if (ELFT::Is64Bits)
+      return read64<E>(Buf);
+    return read32<E>(Buf);
+  }
+  fatal("unknown FDE size encoding");
+}
+
+// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
+// We need it to create .eh_frame_hdr section.
+template <class ELFT>
+typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
+                                                    uint8_t Enc) {
+  // The starting address to which this FDE applies is
+  // stored at FDE + 8 byte.
+  size_t Off = FdeOff + 8;
+  uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
+  if ((Enc & 0x70) == DW_EH_PE_absptr)
+    return Addr;
+  if ((Enc & 0x70) == DW_EH_PE_pcrel)
+    return Addr + this->getVA() + Off;
+  fatal("unknown FDE size relative encoding");
+}
+
+template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+  for (CieRecord *Cie : Cies) {
+    size_t CieOffset = Cie->Piece->OutputOff;
+    writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
+
+    for (SectionPiece *Fde : Cie->FdePieces) {
+      size_t Off = Fde->OutputOff;
+      writeCieFde<ELFT>(Buf + Off, Fde->data());
+
+      // FDE's second word should have the offset to an associated CIE.
+      // Write it.
+      write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
+    }
+  }
+
+  for (EhInputSection<ELFT> *S : Sections)
+    S->relocate(Buf, nullptr);
+
+  // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
+  // to get a FDE from an address to which FDE is applied. So here
+  // we obtain two addresses and pass them to EhFrameHdr object.
+  if (Out<ELFT>::EhFrameHdr) {
+    for (CieRecord *Cie : Cies) {
+      uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data());
+      for (SectionPiece *Fde : Cie->FdePieces) {
+        uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+        uintX_t FdeVA = this->getVA() + Fde->OutputOff;
+        Out<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
+      }
+    }
+  }
+}
+
+template <class ELFT>
+MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
+                                             uintX_t Flags, uintX_t Alignment)
+    : OutputSectionBase<ELFT>(Name, Type, Flags),
+      Builder(StringTableBuilder::RAW, Alignment) {}
+
+template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  if (shouldTailMerge()) {
+    StringRef Data = Builder.data();
+    memcpy(Buf, Data.data(), Data.size());
+    return;
+  }
+  for (const std::pair<CachedHash<StringRef>, size_t> &P : Builder.getMap()) {
+    StringRef Data = P.first.Val;
+    memcpy(Buf + P.second, Data.data(), Data.size());
+  }
+}
+
+static StringRef toStringRef(ArrayRef<uint8_t> A) {
+  return {(const char *)A.data(), A.size()};
+}
+
+template <class ELFT>
+void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  auto *Sec = cast<MergeInputSection<ELFT>>(C);
+  Sec->OutSec = this;
+  this->updateAlignment(Sec->Alignment);
+  this->Header.sh_entsize = Sec->getSectionHdr()->sh_entsize;
+  Sections.push_back(Sec);
+
+  bool IsString = this->Header.sh_flags & SHF_STRINGS;
+
+  for (SectionPiece &Piece : Sec->Pieces) {
+    if (!Piece.Live)
+      continue;
+    uintX_t OutputOffset = Builder.add(toStringRef(Piece.data()));
+    if (!IsString || !shouldTailMerge())
+      Piece.OutputOff = OutputOffset;
+  }
+}
+
+template <class ELFT>
+unsigned MergeOutputSection<ELFT>::getOffset(StringRef Val) {
+  return Builder.getOffset(Val);
+}
+
+template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
+  return Config->Optimize >= 2 && this->Header.sh_flags & SHF_STRINGS;
+}
+
+template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
+  if (shouldTailMerge())
+    Builder.finalize();
+  this->Header.sh_size = Builder.getSize();
+}
+
+template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
+  for (MergeInputSection<ELFT> *Sec : Sections)
+    Sec->finalizePieces();
+}
+
+template <class ELFT>
+StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
+    : OutputSectionBase<ELFT>(Name, SHT_STRTAB,
+                              Dynamic ? (uintX_t)SHF_ALLOC : 0),
+      Dynamic(Dynamic) {}
+
+// Adds a string to the string table. If HashIt is true we hash and check for
+// duplicates. It is optional because the name of global symbols are already
+// uniqued and hashing them again has a big cost for a small value: uniquing
+// them with some other string that happens to be the same.
+template <class ELFT>
+unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
+  if (HashIt) {
+    auto R = StringMap.insert(std::make_pair(S, Size));
+    if (!R.second)
+      return R.first->second;
+  }
+  unsigned Ret = Size;
+  Size += S.size() + 1;
+  Strings.push_back(S);
+  return Ret;
+}
+
+template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  // ELF string tables start with NUL byte, so advance the pointer by one.
+  ++Buf;
+  for (StringRef S : Strings) {
+    memcpy(Buf, S.data(), S.size());
+    Buf += S.size() + 1;
+  }
+}
+
+template <class ELFT>
+typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
+  if (OutputSec)
+    return OutputSec->getVA() + OffsetInSec;
+  return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec);
+}
+
+template <class ELFT>
+typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+  if (UseSymVA)
+    return Sym->getVA<ELFT>(Addend);
+  return Addend;
+}
+
+template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
+  if (Sym && !UseSymVA)
+    return Sym->DynsymIndex;
+  return 0;
+}
+
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(
+    StringTableSection<ELFT> &StrTabSec)
+    : OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
+                              StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+                              StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
+      StrTabSec(StrTabSec) {
+  this->Header.sh_entsize = sizeof(Elf_Sym);
+  this->Header.sh_addralign = sizeof(uintX_t);
+}
+
+// Orders symbols according to their positions in the GOT,
+// in compliance with MIPS ABI rules.
+// See "Global Offset Table" in Chapter 5 in the following document
+// for detailed description:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,
+                            const std::pair<SymbolBody *, unsigned> &R) {
+  // Sort entries related to non-local preemptible symbols by GOT indexes.
+  // All other entries go to the first part of GOT in arbitrary order.
+  bool LIsInLocalGot = !L.first->IsInGlobalMipsGot;
+  bool RIsInLocalGot = !R.first->IsInGlobalMipsGot;
+  if (LIsInLocalGot || RIsInLocalGot)
+    return !RIsInLocalGot;
+  return L.first->GotIndex < R.first->GotIndex;
+}
+
+static uint8_t getSymbolBinding(SymbolBody *Body) {
+  Symbol *S = Body->symbol();
+  uint8_t Visibility = S->Visibility;
+  if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+    return STB_LOCAL;
+  if (Config->NoGnuUnique && S->Binding == STB_GNU_UNIQUE)
+    return STB_GLOBAL;
+  return S->Binding;
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
+  if (this->Header.sh_size)
+    return; // Already finalized.
+
+  this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
+  this->Header.sh_link = StrTabSec.SectionIndex;
+  this->Header.sh_info = NumLocals + 1;
+
+  if (Config->Relocatable) {
+    size_t I = NumLocals;
+    for (const std::pair<SymbolBody *, size_t> &P : Symbols)
+      P.first->DynsymIndex = ++I;
+    return;
+  }
+
+  if (!StrTabSec.isDynamic()) {
+    std::stable_sort(Symbols.begin(), Symbols.end(),
+                     [](const std::pair<SymbolBody *, unsigned> &L,
+                        const std::pair<SymbolBody *, unsigned> &R) {
+                       return getSymbolBinding(L.first) == STB_LOCAL &&
+                              getSymbolBinding(R.first) != STB_LOCAL;
+                     });
+    return;
+  }
+  if (Out<ELFT>::GnuHashTab)
+    // NB: It also sorts Symbols to meet the GNU hash table requirements.
+    Out<ELFT>::GnuHashTab->addSymbols(Symbols);
+  else if (Config->EMachine == EM_MIPS)
+    std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
+  size_t I = 0;
+  for (const std::pair<SymbolBody *, size_t> &P : Symbols)
+    P.first->DynsymIndex = ++I;
+}
+
+template <class ELFT>
+void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
+  Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  Buf += sizeof(Elf_Sym);
+
+  // All symbols with STB_LOCAL binding precede the weak and global symbols.
+  // .dynsym only contains global symbols.
+  if (!Config->DiscardAll && !StrTabSec.isDynamic())
+    writeLocalSymbols(Buf);
+
+  writeGlobalSymbols(Buf);
+}
+
+template <class ELFT>
+void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
+  // Iterate over all input object files to copy their local symbols
+  // to the output symbol table pointed by Buf.
+  for (const std::unique_ptr<ObjectFile<ELFT>> &File :
+       Symtab<ELFT>::X->getObjectFiles()) {
+    for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
+         File->KeptLocalSyms) {
+      const DefinedRegular<ELFT> &Body = *P.first;
+      InputSectionBase<ELFT> *Section = Body.Section;
+      auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+
+      if (!Section) {
+        ESym->st_shndx = SHN_ABS;
+        ESym->st_value = Body.Value;
+      } else {
+        const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
+        ESym->st_shndx = OutSec->SectionIndex;
+        ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
+      }
+      ESym->st_name = P.second;
+      ESym->st_size = Body.template getSize<ELFT>();
+      ESym->setBindingAndType(STB_LOCAL, Body.Type);
+      Buf += sizeof(*ESym);
+    }
+  }
+}
+
+template <class ELFT>
+void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
+  // Write the internal symbol table contents to the output symbol table
+  // pointed by Buf.
+  auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+  for (const std::pair<SymbolBody *, size_t> &P : Symbols) {
+    SymbolBody *Body = P.first;
+    size_t StrOff = P.second;
+
+    uint8_t Type = Body->Type;
+    uintX_t Size = Body->getSize<ELFT>();
+
+    ESym->setBindingAndType(getSymbolBinding(Body), Type);
+    ESym->st_size = Size;
+    ESym->st_name = StrOff;
+    ESym->setVisibility(Body->symbol()->Visibility);
+    ESym->st_value = Body->getVA<ELFT>();
+
+    if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
+      ESym->st_shndx = OutSec->SectionIndex;
+    else if (isa<DefinedRegular<ELFT>>(Body))
+      ESym->st_shndx = SHN_ABS;
+
+    // On MIPS we need to mark symbol which has a PLT entry and requires pointer
+    // equality by STO_MIPS_PLT flag. That is necessary to help dynamic linker
+    // distinguish such symbols and MIPS lazy-binding stubs.
+    // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+    if (Config->EMachine == EM_MIPS && Body->isInPlt() &&
+        Body->NeedsCopyOrPltAddr)
+      ESym->st_other |= STO_MIPS_PLT;
+    ++ESym;
+  }
+}
+
+template <class ELFT>
+const OutputSectionBase<ELFT> *
+SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
+  switch (Sym->kind()) {
+  case SymbolBody::DefinedSyntheticKind:
+    return cast<DefinedSynthetic<ELFT>>(Sym)->Section;
+  case SymbolBody::DefinedRegularKind: {
+    auto &D = cast<DefinedRegular<ELFT>>(*Sym);
+    if (D.Section)
+      return D.Section->OutSec;
+    break;
+  }
+  case SymbolBody::DefinedCommonKind:
+    return Out<ELFT>::Bss;
+  case SymbolBody::SharedKind:
+    if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
+      return Out<ELFT>::Bss;
+    break;
+  case SymbolBody::UndefinedKind:
+  case SymbolBody::LazyArchiveKind:
+  case SymbolBody::LazyObjectKind:
+    break;
+  case SymbolBody::DefinedBitcodeKind:
+    llvm_unreachable("should have been replaced");
+  }
+  return nullptr;
+}
+
+template <class ELFT>
+VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+    : OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) {
+  this->Header.sh_addralign = sizeof(uint32_t);
+}
+
+static StringRef getFileDefName() {
+  if (!Config->SoName.empty())
+    return Config->SoName;
+  return Config->OutputFile;
+}
+
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
+  FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName());
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name);
+
+  this->Header.sh_size =
+      (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+  this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+
+  // sh_info should be set to the number of definitions. This fact is missed in
+  // documentation, but confirmed by binutils community:
+  // https://sourceware.org/ml/binutils/2014-11/msg00355.html
+  this->Header.sh_info = getVerDefNum();
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
+                                              StringRef Name, size_t NameOff) {
+  auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+  Verdef->vd_version = 1;
+  Verdef->vd_cnt = 1;
+  Verdef->vd_aux = sizeof(Elf_Verdef);
+  Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+  Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
+  Verdef->vd_ndx = Index;
+  Verdef->vd_hash = hashSysv(Name);
+
+  auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
+  Verdaux->vda_name = NameOff;
+  Verdaux->vda_next = 0;
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+  writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
+
+  for (VersionDefinition &V : Config->VersionDefinitions) {
+    Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+    writeOne(Buf, V.Id, V.Name, V.NameOff);
+  }
+
+  // Need to terminate the last version definition.
+  Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+  Verdef->vd_next = 0;
+}
+
+template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+    : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {
+  this->Header.sh_addralign = sizeof(uint16_t);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalize() {
+  this->Header.sh_size =
+      sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1);
+  this->Header.sh_entsize = sizeof(Elf_Versym);
+  // At the moment of june 2016 GNU docs does not mention that sh_link field
+  // should be set, but Sun docs do. Also readelf relies on this field.
+  this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
+  for (const std::pair<SymbolBody *, size_t> &P :
+       Out<ELFT>::DynSymTab->getSymbols()) {
+    OutVersym->vs_index = P.first->symbol()->VersionId;
+    ++OutVersym;
+  }
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+    : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {
+  this->Header.sh_addralign = sizeof(uint32_t);
+
+  // Identifiers in verneed section start at 2 because 0 and 1 are reserved
+  // for VER_NDX_LOCAL and VER_NDX_GLOBAL.
+  // First identifiers are reserved by verdef section if it exist.
+  NextIndex = getVerDefNum() + 1;
+}
+
+template <class ELFT>
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
+  if (!SS->Verdef) {
+    SS->symbol()->VersionId = VER_NDX_GLOBAL;
+    return;
+  }
+  SharedFile<ELFT> *F = SS->file();
+  // If we don't already know that we need an Elf_Verneed for this DSO, prepare
+  // to create one by adding it to our needed list and creating a dynstr entry
+  // for the soname.
+  if (F->VerdefMap.empty())
+    Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())});
+  typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
+  // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
+  // prepare to create one by allocating a version identifier and creating a
+  // dynstr entry for the version name.
+  if (NV.Index == 0) {
+    NV.StrTab = Out<ELFT>::DynStrTab->addString(
+        SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name);
+    NV.Index = NextIndex++;
+  }
+  SS->symbol()->VersionId = NV.Index;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
+  // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
+  auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
+  auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
+
+  for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
+    // Create an Elf_Verneed for this DSO.
+    Verneed->vn_version = 1;
+    Verneed->vn_cnt = P.first->VerdefMap.size();
+    Verneed->vn_file = P.second;
+    Verneed->vn_aux =
+        reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
+    Verneed->vn_next = sizeof(Elf_Verneed);
+    ++Verneed;
+
+    // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
+    // VerdefMap, which will only contain references to needed version
+    // definitions. Each Elf_Vernaux is based on the information contained in
+    // the Elf_Verdef in the source DSO. This loop iterates over a std::map of
+    // pointers, but is deterministic because the pointers refer to Elf_Verdef
+    // data structures within a single input file.
+    for (auto &NV : P.first->VerdefMap) {
+      Vernaux->vna_hash = NV.first->vd_hash;
+      Vernaux->vna_flags = 0;
+      Vernaux->vna_other = NV.second.Index;
+      Vernaux->vna_name = NV.second.StrTab;
+      Vernaux->vna_next = sizeof(Elf_Vernaux);
+      ++Vernaux;
+    }
+
+    Vernaux[-1].vna_next = 0;
+  }
+  Verneed[-1].vn_next = 0;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
+  this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+  this->Header.sh_info = Needed.size();
+  unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+  for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+    Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+  this->Header.sh_size = Size;
+}
+
+template <class ELFT>
+BuildIdSection<ELFT>::BuildIdSection(size_t HashSize)
+    : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC),
+      HashSize(HashSize) {
+  // 16 bytes for the note section header.
+  this->Header.sh_size = 16 + HashSize;
+}
+
+template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, 4);                   // Name size
+  write32<E>(Buf + 4, HashSize);        // Content size
+  write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
+  memcpy(Buf + 12, "GNU", 4);           // Name string
+  HashBuf = Buf + 16;
+}
+
+template <class ELFT>
+void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+  const endianness E = ELFT::TargetEndianness;
+
+  // 64-bit FNV-1 hash
+  uint64_t Hash = 0xcbf29ce484222325;
+  for (ArrayRef<uint8_t> Buf : Bufs) {
+    for (uint8_t B : Buf) {
+      Hash *= 0x100000001b3;
+      Hash ^= B;
+    }
+  }
+  write64<E>(this->HashBuf, Hash);
+}
+
+template <class ELFT>
+void BuildIdMd5<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+  MD5 Hash;
+  for (ArrayRef<uint8_t> Buf : Bufs)
+    Hash.update(Buf);
+  MD5::MD5Result Res;
+  Hash.final(Res);
+  memcpy(this->HashBuf, Res, 16);
+}
+
+template <class ELFT>
+void BuildIdSha1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+  SHA1 Hash;
+  for (ArrayRef<uint8_t> Buf : Bufs)
+    Hash.update(Buf);
+  memcpy(this->HashBuf, Hash.final().data(), 20);
+}
+
+template <class ELFT>
+BuildIdHexstring<ELFT>::BuildIdHexstring()
+    : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
+
+template <class ELFT>
+void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+  memcpy(this->HashBuf, Config->BuildIdVector.data(),
+         Config->BuildIdVector.size());
+}
+
+template <class ELFT>
+MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
+    : OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
+  this->Header.sh_addralign = 4;
+  this->Header.sh_entsize = sizeof(Elf_Mips_RegInfo);
+  this->Header.sh_size = sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT>
+void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
+  R->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
+  R->ri_gprmask = GprMask;
+}
+
+template <class ELFT>
+void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  // Copy input object file's .reginfo gprmask to output.
+  auto *S = cast<MipsReginfoInputSection<ELFT>>(C);
+  GprMask |= S->Reginfo->ri_gprmask;
+  S->OutSec = this;
+}
+
+template <class ELFT>
+MipsOptionsOutputSection<ELFT>::MipsOptionsOutputSection()
+    : OutputSectionBase<ELFT>(".MIPS.options", SHT_MIPS_OPTIONS,
+                              SHF_ALLOC | SHF_MIPS_NOSTRIP) {
+  this->Header.sh_addralign = 8;
+  this->Header.sh_entsize = 1;
+  this->Header.sh_size = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf);
+  Opt->kind = ODK_REGINFO;
+  Opt->size = this->Header.sh_size;
+  Opt->section = 0;
+  Opt->info = 0;
+  auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt));
+  Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
+  Reg->ri_gprmask = GprMask;
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  auto *S = cast<MipsOptionsInputSection<ELFT>>(C);
+  if (S->Reginfo)
+    GprMask |= S->Reginfo->ri_gprmask;
+  S->OutSec = this;
+}
+
+template <class ELFT>
+std::pair<OutputSectionBase<ELFT> *, bool>
+OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
+                                   StringRef OutsecName) {
+  SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
+  OutputSectionBase<ELFT> *&Sec = Map[Key];
+  if (Sec)
+    return {Sec, false};
+
+  switch (C->SectionKind) {
+  case InputSectionBase<ELFT>::Regular:
+    Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+    break;
+  case InputSectionBase<ELFT>::EHFrame:
+    return {Out<ELFT>::EhFrame, false};
+  case InputSectionBase<ELFT>::Merge:
+    Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags,
+                                       Key.Alignment);
+    break;
+  case InputSectionBase<ELFT>::MipsReginfo:
+    Sec = new MipsReginfoOutputSection<ELFT>();
+    break;
+  case InputSectionBase<ELFT>::MipsOptions:
+    Sec = new MipsOptionsOutputSection<ELFT>();
+    break;
+  }
+  return {Sec, true};
+}
+
+template <class ELFT>
+OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name,
+                                                            uint32_t Type,
+                                                            uintX_t Flags) {
+  return Map.lookup({Name, Type, Flags, 0});
+}
+
+template <class ELFT>
+SectionKey<ELFT::Is64Bits>
+OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
+                                      StringRef OutsecName) {
+  const Elf_Shdr *H = C->getSectionHdr();
+  uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
+
+  // For SHF_MERGE we create different output sections for each alignment.
+  // This makes each output section simple and keeps a single level mapping from
+  // input to output.
+  uintX_t Alignment = 0;
+  if (isa<MergeInputSection<ELFT>>(C))
+    Alignment = std::max(H->sh_addralign, H->sh_entsize);
+
+  uint32_t Type = H->sh_type;
+  return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment};
+}
+
+template <bool Is64Bits>
+typename lld::elf::SectionKey<Is64Bits>
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() {
+  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0};
+}
+
+template <bool Is64Bits>
+typename lld::elf::SectionKey<Is64Bits>
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() {
+  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0,
+                              0};
+}
+
+template <bool Is64Bits>
+unsigned
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) {
+  return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
+}
+
+template <bool Is64Bits>
+bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS,
+                                                           const Key &RHS) {
+  return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
+         LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
+         LHS.Alignment == RHS.Alignment;
+}
+
+namespace llvm {
+template struct DenseMapInfo<SectionKey<true>>;
+template struct DenseMapInfo<SectionKey<false>>;
+}
+
+namespace lld {
+namespace elf {
+template class OutputSectionBase<ELF32LE>;
+template class OutputSectionBase<ELF32BE>;
+template class OutputSectionBase<ELF64LE>;
+template class OutputSectionBase<ELF64BE>;
+
+template class EhFrameHeader<ELF32LE>;
+template class EhFrameHeader<ELF32BE>;
+template class EhFrameHeader<ELF64LE>;
+template class EhFrameHeader<ELF64BE>;
+
+template class GotPltSection<ELF32LE>;
+template class GotPltSection<ELF32BE>;
+template class GotPltSection<ELF64LE>;
+template class GotPltSection<ELF64BE>;
+
+template class GotSection<ELF32LE>;
+template class GotSection<ELF32BE>;
+template class GotSection<ELF64LE>;
+template class GotSection<ELF64BE>;
+
+template class PltSection<ELF32LE>;
+template class PltSection<ELF32BE>;
+template class PltSection<ELF64LE>;
+template class PltSection<ELF64BE>;
+
+template class RelocationSection<ELF32LE>;
+template class RelocationSection<ELF32BE>;
+template class RelocationSection<ELF64LE>;
+template class RelocationSection<ELF64BE>;
+
+template class InterpSection<ELF32LE>;
+template class InterpSection<ELF32BE>;
+template class InterpSection<ELF64LE>;
+template class InterpSection<ELF64BE>;
+
+template class GnuHashTableSection<ELF32LE>;
+template class GnuHashTableSection<ELF32BE>;
+template class GnuHashTableSection<ELF64LE>;
+template class GnuHashTableSection<ELF64BE>;
+
+template class HashTableSection<ELF32LE>;
+template class HashTableSection<ELF32BE>;
+template class HashTableSection<ELF64LE>;
+template class HashTableSection<ELF64BE>;
+
+template class DynamicSection<ELF32LE>;
+template class DynamicSection<ELF32BE>;
+template class DynamicSection<ELF64LE>;
+template class DynamicSection<ELF64BE>;
+
+template class OutputSection<ELF32LE>;
+template class OutputSection<ELF32BE>;
+template class OutputSection<ELF64LE>;
+template class OutputSection<ELF64BE>;
+
+template class EhOutputSection<ELF32LE>;
+template class EhOutputSection<ELF32BE>;
+template class EhOutputSection<ELF64LE>;
+template class EhOutputSection<ELF64BE>;
+
+template class MipsReginfoOutputSection<ELF32LE>;
+template class MipsReginfoOutputSection<ELF32BE>;
+template class MipsReginfoOutputSection<ELF64LE>;
+template class MipsReginfoOutputSection<ELF64BE>;
+
+template class MipsOptionsOutputSection<ELF32LE>;
+template class MipsOptionsOutputSection<ELF32BE>;
+template class MipsOptionsOutputSection<ELF64LE>;
+template class MipsOptionsOutputSection<ELF64BE>;
+
+template class MergeOutputSection<ELF32LE>;
+template class MergeOutputSection<ELF32BE>;
+template class MergeOutputSection<ELF64LE>;
+template class MergeOutputSection<ELF64BE>;
+
+template class StringTableSection<ELF32LE>;
+template class StringTableSection<ELF32BE>;
+template class StringTableSection<ELF64LE>;
+template class StringTableSection<ELF64BE>;
+
+template class SymbolTableSection<ELF32LE>;
+template class SymbolTableSection<ELF32BE>;
+template class SymbolTableSection<ELF64LE>;
+template class SymbolTableSection<ELF64BE>;
+
+template class VersionTableSection<ELF32LE>;
+template class VersionTableSection<ELF32BE>;
+template class VersionTableSection<ELF64LE>;
+template class VersionTableSection<ELF64BE>;
+
+template class VersionNeedSection<ELF32LE>;
+template class VersionNeedSection<ELF32BE>;
+template class VersionNeedSection<ELF64LE>;
+template class VersionNeedSection<ELF64BE>;
+
+template class VersionDefinitionSection<ELF32LE>;
+template class VersionDefinitionSection<ELF32BE>;
+template class VersionDefinitionSection<ELF64LE>;
+template class VersionDefinitionSection<ELF64BE>;
+
+template class BuildIdSection<ELF32LE>;
+template class BuildIdSection<ELF32BE>;
+template class BuildIdSection<ELF64LE>;
+template class BuildIdSection<ELF64BE>;
+
+template class BuildIdFnv1<ELF32LE>;
+template class BuildIdFnv1<ELF32BE>;
+template class BuildIdFnv1<ELF64LE>;
+template class BuildIdFnv1<ELF64BE>;
+
+template class BuildIdMd5<ELF32LE>;
+template class BuildIdMd5<ELF32BE>;
+template class BuildIdMd5<ELF64LE>;
+template class BuildIdMd5<ELF64BE>;
+
+template class BuildIdSha1<ELF32LE>;
+template class BuildIdSha1<ELF32BE>;
+template class BuildIdSha1<ELF64LE>;
+template class BuildIdSha1<ELF64BE>;
+
+template class BuildIdHexstring<ELF32LE>;
+template class BuildIdHexstring<ELF32BE>;
+template class BuildIdHexstring<ELF64LE>;
+template class BuildIdHexstring<ELF64BE>;
+
+template class OutputSectionFactory<ELF32LE>;
+template class OutputSectionFactory<ELF32BE>;
+template class OutputSectionFactory<ELF64LE>;
+template class OutputSectionFactory<ELF64BE>;
+}
+}
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
new file mode 100644 (file)
index 0000000..5fdf8de
--- /dev/null
@@ -0,0 +1,732 @@
+//===- OutputSections.h -----------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_OUTPUT_SECTIONS_H
+#define LLD_ELF_OUTPUT_SECTIONS_H
+
+#include "Config.h"
+#include "Relocations.h"
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/SHA1.h"
+
+namespace lld {
+namespace elf {
+
+class SymbolBody;
+struct SectionPiece;
+template <class ELFT> class SymbolTable;
+template <class ELFT> class SymbolTableSection;
+template <class ELFT> class StringTableSection;
+template <class ELFT> class EhInputSection;
+template <class ELFT> class InputSection;
+template <class ELFT> class InputSectionBase;
+template <class ELFT> class MergeInputSection;
+template <class ELFT> class MipsReginfoInputSection;
+template <class ELFT> class OutputSection;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class SharedFile;
+template <class ELFT> class SharedSymbol;
+template <class ELFT> class DefinedRegular;
+
+// This represents a section in an output file.
+// Different sub classes represent different types of sections. Some contain
+// input sections, others are created by the linker.
+// The writer creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and VAs.
+template <class ELFT> class OutputSectionBase {
+public:
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+  OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
+  void setVA(uintX_t VA) { Header.sh_addr = VA; }
+  uintX_t getVA() const { return Header.sh_addr; }
+  void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
+  void setSHName(unsigned Val) { Header.sh_name = Val; }
+  void writeHeaderTo(Elf_Shdr *SHdr);
+  StringRef getName() { return Name; }
+
+  virtual void addSection(InputSectionBase<ELFT> *C) {}
+
+  unsigned SectionIndex;
+
+  // Returns the size of the section in the output file.
+  uintX_t getSize() const { return Header.sh_size; }
+  void setSize(uintX_t Val) { Header.sh_size = Val; }
+  uintX_t getFlags() const { return Header.sh_flags; }
+  uintX_t getFileOff() const { return Header.sh_offset; }
+  uintX_t getAlignment() const { return Header.sh_addralign; }
+  uint32_t getType() const { return Header.sh_type; }
+
+  void updateAlignment(uintX_t Alignment) {
+    if (Alignment > Header.sh_addralign)
+      Header.sh_addralign = Alignment;
+  }
+
+  // If true, this section will be page aligned on disk.
+  // Typically the first section of each PT_LOAD segment has this flag.
+  bool PageAlign = false;
+
+  virtual void finalize() {}
+  virtual void finalizePieces() {}
+  virtual void assignOffsets() {}
+  virtual void writeTo(uint8_t *Buf) {}
+  virtual ~OutputSectionBase() = default;
+
+protected:
+  StringRef Name;
+  Elf_Shdr Header;
+};
+
+template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
+  typedef OutputSectionBase<ELFT> Base;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  GotSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  void addEntry(SymbolBody &Sym);
+  void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+  bool addDynTlsEntry(SymbolBody &Sym);
+  bool addTlsIndex();
+  bool empty() const { return MipsPageEntries == 0 && Entries.empty(); }
+  uintX_t getMipsLocalPageOffset(uintX_t Addr);
+  uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const;
+  uintX_t getGlobalDynAddr(const SymbolBody &B) const;
+  uintX_t getGlobalDynOffset(const SymbolBody &B) const;
+  uintX_t getNumEntries() const { return Entries.size(); }
+
+  // Returns the symbol which corresponds to the first entry of the global part
+  // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
+  // table properties.
+  // Returns nullptr if the global part is empty.
+  const SymbolBody *getMipsFirstGlobalEntry() const;
+
+  // Returns the number of entries in the local part of GOT including
+  // the number of reserved entries. This method is MIPS-specific.
+  unsigned getMipsLocalEntriesNum() const;
+
+  // Returns offset of TLS part of the MIPS GOT table. This part goes
+  // after 'local' and 'global' entries.
+  uintX_t getMipsTlsOffset();
+
+  uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; }
+  uint32_t getTlsIndexOff() { return TlsIndexOff; }
+
+  // Flag to force GOT to be in output if we have relocations
+  // that relies on its address.
+  bool HasGotOffRel = false;
+
+private:
+  std::vector<const SymbolBody *> Entries;
+  uint32_t TlsIndexOff = -1;
+  uint32_t MipsPageEntries = 0;
+  // Output sections referenced by MIPS GOT relocations.
+  llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
+  llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
+
+  // MIPS ABI requires to create unique GOT entry for each Symbol/Addend
+  // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal`
+  // or `MipsGlobal` vectors. In general it does not have a sence to take in
+  // account addend for preemptible symbols because the corresponding
+  // GOT entries should have one-to-one mapping with dynamic symbols table.
+  // But we use the same container's types for both kind of GOT entries
+  // to handle them uniformly.
+  typedef std::pair<const SymbolBody*, uintX_t> MipsGotEntry;
+  typedef std::vector<MipsGotEntry> MipsGotEntries;
+  llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
+  MipsGotEntries MipsLocal;
+  MipsGotEntries MipsGlobal;
+
+  // Write MIPS-specific parts of the GOT.
+  void writeMipsGot(uint8_t *&Buf);
+};
+
+template <class ELFT>
+class GotPltSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  GotPltSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  void addEntry(SymbolBody &Sym);
+  bool empty() const;
+
+private:
+  std::vector<const SymbolBody *> Entries;
+};
+
+template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
+  typedef OutputSectionBase<ELFT> Base;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  PltSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  void addEntry(SymbolBody &Sym);
+  bool empty() const { return Entries.empty(); }
+
+private:
+  std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+};
+
+template <class ELFT> class DynamicReloc {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
+               uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+               uintX_t Addend)
+      : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
+        UseSymVA(UseSymVA), Addend(Addend) {}
+
+  DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OutputSec,
+               uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+               uintX_t Addend)
+      : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec),
+        UseSymVA(UseSymVA), Addend(Addend) {}
+
+  uintX_t getOffset() const;
+  uintX_t getAddend() const;
+  uint32_t getSymIndex() const;
+  const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; }
+
+  uint32_t Type;
+
+private:
+  SymbolBody *Sym;
+  const InputSectionBase<ELFT> *InputSec = nullptr;
+  const OutputSectionBase<ELFT> *OutputSec = nullptr;
+  uintX_t OffsetInSec;
+  bool UseSymVA;
+  uintX_t Addend;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public OutputSectionBase<ELFT> {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::uint uintX_t;
+  SymbolTableSection(StringTableSection<ELFT> &StrTabSec);
+
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  void addSymbol(SymbolBody *Body);
+  StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
+  unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
+
+  ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const {
+    return Symbols;
+  }
+
+  unsigned NumLocals = 0;
+  StringTableSection<ELFT> &StrTabSec;
+
+private:
+  void writeLocalSymbols(uint8_t *&Buf);
+  void writeGlobalSymbols(uint8_t *Buf);
+
+  const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym);
+
+  // A vector of symbols and their string table offsets.
+  std::vector<std::pair<SymbolBody *, size_t>> Symbols;
+};
+
+// For more information about .gnu.version and .gnu.version_r see:
+// https://www.akkadia.org/drepper/symbol-versioning
+
+// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall
+// contain symbol version definitions. The number of entries in this section
+// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
+// The section shall contain an array of Elf_Verdef structures, optionally
+// followed by an array of Elf_Verdaux structures.
+template <class ELFT>
+class VersionDefinitionSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::Verdaux Elf_Verdaux;
+
+public:
+  VersionDefinitionSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+
+private:
+  void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
+
+  unsigned FileDefNameOff;
+};
+
+// The .gnu.version section specifies the required version of each symbol in the
+// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
+// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
+// identifier defined in the either .gnu.version_r or .gnu.version_d section.
+// The values 0 and 1 are reserved. All other values are used for versions in
+// the own object or in any of the dependencies.
+template <class ELFT>
+class VersionTableSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Versym Elf_Versym;
+
+public:
+  VersionTableSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+};
+
+// The .gnu.version_r section defines the version identifiers used by
+// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
+// Elf_Verneed specifies the version requirements for a single DSO, and contains
+// a reference to a linked list of Elf_Vernaux data structures which define the
+// mapping from version identifiers to version names.
+template <class ELFT>
+class VersionNeedSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Verneed Elf_Verneed;
+  typedef typename ELFT::Vernaux Elf_Vernaux;
+
+  // A vector of shared files that need Elf_Verneed data structures and the
+  // string table offsets of their sonames.
+  std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
+
+  // The next available version identifier.
+  unsigned NextIndex;
+
+public:
+  VersionNeedSection();
+  void addSymbol(SharedSymbol<ELFT> *SS);
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getNeedNum() const { return Needed.size(); }
+};
+
+template <class ELFT>
+class RelocationSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  RelocationSection(StringRef Name, bool Sort);
+  void addReloc(const DynamicReloc<ELFT> &Reloc);
+  unsigned getRelocOffset();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  bool hasRelocs() const { return !Relocs.empty(); }
+
+  bool Static = false;
+
+private:
+  bool Sort;
+  std::vector<DynamicReloc<ELFT>> Relocs;
+};
+
+template <class ELFT>
+class OutputSection final : public OutputSectionBase<ELFT> {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::uint uintX_t;
+  OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
+  void addSection(InputSectionBase<ELFT> *C) override;
+  void sortInitFini();
+  void sortCtorsDtors();
+  void writeTo(uint8_t *Buf) override;
+  void finalize() override;
+  void assignOffsets() override;
+  std::vector<InputSection<ELFT> *> Sections;
+};
+
+template <class ELFT>
+class MergeOutputSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
+                     uintX_t Alignment);
+  void addSection(InputSectionBase<ELFT> *S) override;
+  void writeTo(uint8_t *Buf) override;
+  unsigned getOffset(StringRef Val);
+  void finalize() override;
+  void finalizePieces() override;
+  bool shouldTailMerge() const;
+
+private:
+  llvm::StringTableBuilder Builder;
+  std::vector<MergeInputSection<ELFT> *> Sections;
+};
+
+struct CieRecord {
+  SectionPiece *Piece = nullptr;
+  std::vector<SectionPiece *> FdePieces;
+};
+
+// Output section for .eh_frame.
+template <class ELFT>
+class EhOutputSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+
+public:
+  EhOutputSection();
+  void writeTo(uint8_t *Buf) override;
+  void finalize() override;
+  bool empty() const { return Sections.empty(); }
+
+  void addSection(InputSectionBase<ELFT> *S) override;
+
+  size_t NumFdes = 0;
+
+private:
+  template <class RelTy>
+  void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
+
+  template <class RelTy>
+  CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
+                    ArrayRef<RelTy> &Rels);
+
+  template <class RelTy>
+  bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
+                 ArrayRef<RelTy> &Rels);
+
+  uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
+
+  std::vector<EhInputSection<ELFT> *> Sections;
+  std::vector<CieRecord *> Cies;
+
+  // CIE records are uniquified by their contents and personality functions.
+  llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
+};
+
+template <class ELFT>
+class InterpSection final : public OutputSectionBase<ELFT> {
+public:
+  InterpSection();
+  void writeTo(uint8_t *Buf) override;
+};
+
+template <class ELFT>
+class StringTableSection final : public OutputSectionBase<ELFT> {
+public:
+  typedef typename ELFT::uint uintX_t;
+  StringTableSection(StringRef Name, bool Dynamic);
+  unsigned addString(StringRef S, bool HashIt = true);
+  void writeTo(uint8_t *Buf) override;
+  unsigned getSize() const { return Size; }
+  void finalize() override { this->Header.sh_size = getSize(); }
+  bool isDynamic() const { return Dynamic; }
+
+private:
+  const bool Dynamic;
+  llvm::DenseMap<StringRef, unsigned> StringMap;
+  std::vector<StringRef> Strings;
+  unsigned Size = 1; // ELF string tables start with a NUL byte, so 1.
+};
+
+template <class ELFT>
+class HashTableSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Word Elf_Word;
+
+public:
+  HashTableSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+};
+
+// Outputs GNU Hash section. For detailed explanation see:
+// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
+template <class ELFT>
+class GnuHashTableSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Off Elf_Off;
+  typedef typename ELFT::Word Elf_Word;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  GnuHashTableSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+
+  // Adds symbols to the hash table.
+  // Sorts the input to satisfy GNU hash section requirements.
+  void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols);
+
+private:
+  static unsigned calcNBuckets(unsigned NumHashed);
+  static unsigned calcMaskWords(unsigned NumHashed);
+
+  void writeHeader(uint8_t *&Buf);
+  void writeBloomFilter(uint8_t *&Buf);
+  void writeHashTable(uint8_t *Buf);
+
+  struct SymbolData {
+    SymbolBody *Body;
+    size_t STName;
+    uint32_t Hash;
+  };
+
+  std::vector<SymbolData> Symbols;
+
+  unsigned MaskWords;
+  unsigned NBuckets;
+  unsigned Shift2;
+};
+
+template <class ELFT>
+class DynamicSection final : public OutputSectionBase<ELFT> {
+  typedef OutputSectionBase<ELFT> Base;
+  typedef typename ELFT::Dyn Elf_Dyn;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+
+  // The .dynamic section contains information for the dynamic linker.
+  // The section consists of fixed size entries, which consist of
+  // type and value fields. Value are one of plain integers, symbol
+  // addresses, or section addresses. This struct represents the entry.
+  struct Entry {
+    int32_t Tag;
+    union {
+      OutputSectionBase<ELFT> *OutSec;
+      uint64_t Val;
+      const SymbolBody *Sym;
+    };
+    enum KindT { SecAddr, SymAddr, PlainInt } Kind;
+    Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec)
+        : Tag(Tag), OutSec(OutSec), Kind(SecAddr) {}
+    Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
+    Entry(int32_t Tag, const SymbolBody *Sym)
+        : Tag(Tag), Sym(Sym), Kind(SymAddr) {}
+  };
+
+  // finalize() fills this vector with the section contents. finalize()
+  // cannot directly create final section contents because when the
+  // function is called, symbol or section addresses are not fixed yet.
+  std::vector<Entry> Entries;
+
+public:
+  explicit DynamicSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+
+  OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
+  OutputSectionBase<ELFT> *InitArraySec = nullptr;
+  OutputSectionBase<ELFT> *FiniArraySec = nullptr;
+};
+
+template <class ELFT>
+class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
+  typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+  MipsReginfoOutputSection();
+  void writeTo(uint8_t *Buf) override;
+  void addSection(InputSectionBase<ELFT> *S) override;
+
+private:
+  uint32_t GprMask = 0;
+};
+
+template <class ELFT>
+class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> {
+  typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+  typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+  MipsOptionsOutputSection();
+  void writeTo(uint8_t *Buf) override;
+  void addSection(InputSectionBase<ELFT> *S) override;
+
+private:
+  uint32_t GprMask = 0;
+};
+
+// --eh-frame-hdr option tells linker to construct a header for all the
+// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
+// and also to a PT_GNU_EH_FRAME segment.
+// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
+// calling dl_iterate_phdr.
+// This section contains a lookup table for quick binary search of FDEs.
+// Detailed info about internals can be found in Ian Lance Taylor's blog:
+// http://www.airs.com/blog/archives/460 (".eh_frame")
+// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
+template <class ELFT>
+class EhFrameHeader final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  EhFrameHeader();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  void addFde(uint32_t Pc, uint32_t FdeVA);
+
+private:
+  struct FdeData {
+    uint32_t Pc;
+    uint32_t FdeVA;
+  };
+
+  std::vector<FdeData> Fdes;
+};
+
+template <class ELFT> class BuildIdSection : public OutputSectionBase<ELFT> {
+public:
+  void writeTo(uint8_t *Buf) override;
+  virtual void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) = 0;
+
+protected:
+  BuildIdSection(size_t HashSize);
+  size_t HashSize;
+  uint8_t *HashBuf = nullptr;
+};
+
+template <class ELFT> class BuildIdFnv1 final : public BuildIdSection<ELFT> {
+public:
+  BuildIdFnv1() : BuildIdSection<ELFT>(8) {}
+  void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT> class BuildIdMd5 final : public BuildIdSection<ELFT> {
+public:
+  BuildIdMd5() : BuildIdSection<ELFT>(16) {}
+  void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT> class BuildIdSha1 final : public BuildIdSection<ELFT> {
+public:
+  BuildIdSha1() : BuildIdSection<ELFT>(20) {}
+  void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT>
+class BuildIdHexstring final : public BuildIdSection<ELFT> {
+public:
+  BuildIdHexstring();
+  void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+// All output sections that are hadnled by the linker specially are
+// globally accessible. Writer initializes them, so don't use them
+// until Writer is initialized.
+template <class ELFT> struct Out {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Phdr Elf_Phdr;
+  static BuildIdSection<ELFT> *BuildId;
+  static DynamicSection<ELFT> *Dynamic;
+  static EhFrameHeader<ELFT> *EhFrameHdr;
+  static EhOutputSection<ELFT> *EhFrame;
+  static GnuHashTableSection<ELFT> *GnuHashTab;
+  static GotPltSection<ELFT> *GotPlt;
+  static GotSection<ELFT> *Got;
+  static HashTableSection<ELFT> *HashTab;
+  static InterpSection<ELFT> *Interp;
+  static OutputSection<ELFT> *Bss;
+  static OutputSection<ELFT> *MipsRldMap;
+  static OutputSectionBase<ELFT> *Opd;
+  static uint8_t *OpdBuf;
+  static PltSection<ELFT> *Plt;
+  static RelocationSection<ELFT> *RelaDyn;
+  static RelocationSection<ELFT> *RelaPlt;
+  static StringTableSection<ELFT> *DynStrTab;
+  static StringTableSection<ELFT> *ShStrTab;
+  static StringTableSection<ELFT> *StrTab;
+  static SymbolTableSection<ELFT> *DynSymTab;
+  static SymbolTableSection<ELFT> *SymTab;
+  static VersionDefinitionSection<ELFT> *VerDef;
+  static VersionTableSection<ELFT> *VerSym;
+  static VersionNeedSection<ELFT> *VerNeed;
+  static Elf_Phdr *TlsPhdr;
+  static OutputSectionBase<ELFT> *ElfHeader;
+  static OutputSectionBase<ELFT> *ProgramHeaders;
+};
+
+template <bool Is64Bits> struct SectionKey {
+  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+  StringRef Name;
+  uint32_t Type;
+  uintX_t Flags;
+  uintX_t Alignment;
+};
+
+// This class knows how to create an output section for a given
+// input section. Output section type is determined by various
+// factors, including input section's sh_flags, sh_type and
+// linker scripts.
+template <class ELFT> class OutputSectionFactory {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::uint uintX_t;
+  typedef typename elf::SectionKey<ELFT::Is64Bits> Key;
+
+public:
+  std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
+                                                    StringRef OutsecName);
+
+  OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
+
+private:
+  Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName);
+
+  llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;
+};
+
+template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId;
+template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
+template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
+template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
+template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
+template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
+template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
+template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
+template <class ELFT> InterpSection<ELFT> *Out<ELFT>::Interp;
+template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
+template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
+template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::Opd;
+template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
+template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt;
+template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaDyn;
+template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaPlt;
+template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::DynStrTab;
+template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab;
+template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
+template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
+template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
+template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef;
+template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed;
+template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr;
+template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader;
+template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders;
+
+} // namespace elf
+} // namespace lld
+
+namespace llvm {
+template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> {
+  typedef typename lld::elf::SectionKey<Is64Bits> Key;
+
+  static Key getEmptyKey();
+  static Key getTombstoneKey();
+  static unsigned getHashValue(const Key &Val);
+  static bool isEqual(const Key &LHS, const Key &RHS);
+};
+}
+
+#endif
diff --git a/ELF/README.md b/ELF/README.md
new file mode 100644 (file)
index 0000000..f1bfc9c
--- /dev/null
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
new file mode 100644 (file)
index 0000000..c09cf6b
--- /dev/null
@@ -0,0 +1,704 @@
+//===- Relocations.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains platform-independent functions to process relocations.
+// I'll describe the overview of this file here.
+//
+// Simple relocations are easy to handle for the linker. For example,
+// for R_X86_64_PC64 relocs, the linker just has to fix up locations
+// with the relative offsets to the target symbols. It would just be
+// reading records from relocation sections and applying them to output.
+//
+// But not all relocations are that easy to handle. For example, for
+// R_386_GOTOFF relocs, the linker has to create new GOT entries for
+// symbols if they don't exist, and fix up locations with GOT entry
+// offsets from the beginning of GOT section. So there is more than
+// fixing addresses in relocation processing.
+//
+// ELF defines a large number of complex relocations.
+//
+// The functions in this file analyze relocations and do whatever needs
+// to be done. It includes, but not limited to, the following.
+//
+//  - create GOT/PLT entries
+//  - create new relocations in .dynsym to let the dynamic linker resolve
+//    them at runtime (since ELF supports dynamic linking, not all
+//    relocations can be resolved at link-time)
+//  - create COPY relocs and reserve space in .bss
+//  - replace expensive relocs (in terms of runtime cost) with cheap ones
+//  - error out infeasible combinations such as PIC and non-relative relocs
+//
+// Note that the functions in this file don't actually apply relocations
+// because it doesn't know about the output file nor the output file buffer.
+// It instead stores Relocation objects to InputSection's Relocations
+// vector to let it apply later in InputSection::writeTo.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Relocations.h"
+#include "Config.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "Thunks.h"
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+static bool refersToGotEntry(RelExpr Expr) {
+  return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
+         Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD ||
+         Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
+         Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
+         Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
+}
+
+static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
+  // In case of MIPS GP-relative relocations always resolve to a definition
+  // in a regular input file, ignoring the one-definition rule. So we,
+  // for example, should not attempt to create a dynamic relocation even
+  // if the target symbol is preemptible. There are two two MIPS GP-relative
+  // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
+  // can be against a preemptible symbol.
+  // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
+  // relocation types occupy eight bit. In case of N64 ABI we extract first
+  // relocation from 3-in-1 packet because only the first relocation can
+  // be against a real symbol.
+  if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
+    return false;
+  return Body.isPreemptible();
+}
+
+// This function is similar to the `handleTlsRelocation`. MIPS does not support
+// any relaxations for TLS relocations so by factoring out MIPS handling into
+// the separate function we can simplify the code and does not pollute
+// `handleTlsRelocation` by MIPS `ifs` statements.
+template <class ELFT>
+static unsigned
+handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+                        InputSectionBase<ELFT> &C, typename ELFT::uint Offset,
+                        typename ELFT::uint Addend, RelExpr Expr) {
+  if (Expr == R_MIPS_TLSLD) {
+    if (Out<ELFT>::Got->addTlsIndex())
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+                                    Out<ELFT>::Got->getTlsIndexOff(), false,
+                                    nullptr, 0});
+    C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+  if (Target->isTlsGlobalDynamicRel(Type)) {
+    if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+      typedef typename ELFT::uint uintX_t;
+      uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+                                    Off + (uintX_t)sizeof(uintX_t), false,
+                                    &Body, 0});
+    }
+    C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+  return 0;
+}
+
+// Returns the number of relocations processed.
+template <class ELFT>
+static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
+                                    InputSectionBase<ELFT> &C,
+                                    typename ELFT::uint Offset,
+                                    typename ELFT::uint Addend, RelExpr Expr) {
+  if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
+    return 0;
+
+  if (!Body.isTls())
+    return 0;
+
+  typedef typename ELFT::uint uintX_t;
+
+  if (Config->EMachine == EM_MIPS)
+    return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+
+  if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
+      Config->Shared) {
+    if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+      uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
+    }
+    if (Expr != R_HINT)
+      C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (Expr == R_TLSLD_PC || Expr == R_TLSLD) {
+    // Local-Dynamic relocs can be relaxed to Local-Exec.
+    if (!Config->Shared) {
+      C.Relocations.push_back(
+          {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
+      return 2;
+    }
+    if (Out<ELFT>::Got->addTlsIndex())
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+                                    Out<ELFT>::Got->getTlsIndexOff(), false,
+                                    nullptr, 0});
+    C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+
+  // Local-Dynamic relocs can be relaxed to Local-Exec.
+  if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT ||
+      Target->isTlsGlobalDynamicRel(Type)) {
+    if (Config->Shared) {
+      if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+        uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+        Out<ELFT>::RelaDyn->addReloc(
+            {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+
+        // If the symbol is preemptible we need the dynamic linker to write
+        // the offset too.
+        if (isPreemptible(Body, Type))
+          Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+                                        Off + (uintX_t)sizeof(uintX_t), false,
+                                        &Body, 0});
+      }
+      C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+      return 1;
+    }
+
+    // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+    // depending on the symbol being locally defined or not.
+    if (isPreemptible(Body, Type)) {
+      C.Relocations.push_back(
+          {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
+           &C, Offset, Addend, &Body});
+      if (!Body.isInGot()) {
+        Out<ELFT>::Got->addEntry(Body);
+        Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
+                                      Body.getGotOffset<ELFT>(), false, &Body,
+                                      0});
+      }
+      return Target->TlsGdRelaxSkip;
+    }
+    C.Relocations.push_back(
+        {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, &C,
+         Offset, Addend, &Body});
+    return Target->TlsGdRelaxSkip;
+  }
+
+  // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+  // defined.
+  if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
+      !isPreemptible(Body, Type)) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+  return 0;
+}
+
+template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
+  return read32<E>(Loc) & 0xffff;
+}
+
+template <class RelTy>
+static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
+  switch (Rel->getType(Config->Mips64EL)) {
+  case R_MIPS_HI16:
+    return R_MIPS_LO16;
+  case R_MIPS_GOT16:
+    return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
+  case R_MIPS_PCHI16:
+    return R_MIPS_PCLO16;
+  case R_MICROMIPS_HI16:
+    return R_MICROMIPS_LO16;
+  default:
+    return R_MIPS_NONE;
+  }
+}
+
+template <class ELFT, class RelTy>
+static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
+                                    SymbolBody &Sym, const RelTy *Rel,
+                                    const RelTy *End) {
+  uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
+  uint32_t Type = getMipsPairType(Rel, Sym);
+
+  // Some MIPS relocations use addend calculated from addend of the relocation
+  // itself and addend of paired relocation. ABI requires to compute such
+  // combined addend in case of REL relocation record format only.
+  // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (RelTy::IsRela || Type == R_MIPS_NONE)
+    return 0;
+
+  for (const RelTy *RI = Rel; RI != End; ++RI) {
+    if (RI->getType(Config->Mips64EL) != Type)
+      continue;
+    if (RI->getSymbol(Config->Mips64EL) != SymIndex)
+      continue;
+    const endianness E = ELFT::TargetEndianness;
+    return ((read32<E>(BufLoc) & 0xffff) << 16) +
+           readSignedLo16<E>(Buf + RI->r_offset);
+  }
+  warning("can't find matching " + getRelName(Type) + " relocation for " +
+          getRelName(Rel->getType(Config->Mips64EL)));
+  return 0;
+}
+
+// True if non-preemptable symbol always has the same value regardless of where
+// the DSO is loaded.
+template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
+  if (Body.isUndefined())
+    return !Body.isLocal() && Body.symbol()->isWeak();
+  if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body))
+    return DR->Section == nullptr; // Absolute symbol.
+  return false;
+}
+
+static bool needsPlt(RelExpr Expr) {
+  return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT ||
+         Expr == R_PLT_PAGE_PC || Expr == R_THUNK_PLT_PC;
+}
+
+// True if this expression is of the form Sym - X, where X is a position in the
+// file (PC, or GOT for example).
+static bool isRelExpr(RelExpr Expr) {
+  return Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC ||
+         Expr == R_RELAX_GOT_PC || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC;
+}
+
+template <class ELFT>
+static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
+                                     const SymbolBody &Body) {
+  // These expressions always compute a constant
+  if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
+      E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD ||
+      E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
+      E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE ||
+      E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC)
+    return true;
+
+  // These never do, except if the entire file is position dependent or if
+  // only the low bits are used.
+  if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+    return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
+
+  if (isPreemptible(Body, Type))
+    return false;
+
+  if (!Config->Pic)
+    return true;
+
+  bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls();
+  bool RelE = isRelExpr(E);
+  if (AbsVal && !RelE)
+    return true;
+  if (!AbsVal && RelE)
+    return true;
+
+  // Relative relocation to an absolute value. This is normally unrepresentable,
+  // but if the relocation refers to a weak undefined symbol, we allow it to
+  // resolve to the image base. This is a little strange, but it allows us to
+  // link function calls to such symbols. Normally such a call will be guarded
+  // with a comparison, which will load a zero from the GOT.
+  if (AbsVal && RelE) {
+    if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+      return true;
+    error("relocation " + getRelName(Type) +
+          " cannot refer to absolute symbol " + Body.getName());
+    return true;
+  }
+
+  return Target->usesOnlyLowPageBits(Type);
+}
+
+static RelExpr toPlt(RelExpr Expr) {
+  if (Expr == R_PPC_OPD)
+    return R_PPC_PLT_OPD;
+  if (Expr == R_PC)
+    return R_PLT_PC;
+  if (Expr == R_PAGE_PC)
+    return R_PLT_PAGE_PC;
+  if (Expr == R_ABS)
+    return R_PLT;
+  return Expr;
+}
+
+static RelExpr fromPlt(RelExpr Expr) {
+  // We decided not to use a plt. Optimize a reference to the plt to a
+  // reference to the symbol itself.
+  if (Expr == R_PLT_PC)
+    return R_PC;
+  if (Expr == R_PPC_PLT_OPD)
+    return R_PPC_OPD;
+  if (Expr == R_PLT)
+    return R_ABS;
+  return Expr;
+}
+
+template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) {
+  typedef typename ELFT::uint uintX_t;
+
+  uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign;
+  uintX_t SymValue = SS->Sym.st_value;
+  int TrailingZeros =
+      std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue));
+  return 1 << TrailingZeros;
+}
+
+// Reserve space in .bss for copy relocation.
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Sym Elf_Sym;
+
+  // Copy relocation against zero-sized symbol doesn't make sense.
+  uintX_t SymSize = SS->template getSize<ELFT>();
+  if (SymSize == 0)
+    fatal("cannot create a copy relocation for " + SS->getName());
+
+  uintX_t Alignment = getAlignment(SS);
+  uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment);
+  Out<ELFT>::Bss->setSize(Off + SymSize);
+  Out<ELFT>::Bss->updateAlignment(Alignment);
+  uintX_t Shndx = SS->Sym.st_shndx;
+  uintX_t Value = SS->Sym.st_value;
+  // Look through the DSO's dynamic symbol table for aliases and create a
+  // dynamic symbol for each one. This causes the copy relocation to correctly
+  // interpose any aliases.
+  for (const Elf_Sym &S : SS->file()->getElfSymbols(true)) {
+    if (S.st_shndx != Shndx || S.st_value != Value)
+      continue;
+    auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
+        Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
+    if (!Alias)
+      continue;
+    Alias->OffsetInBss = Off;
+    Alias->NeedsCopyOrPltAddr = true;
+    Alias->symbol()->IsUsedInRegularObj = true;
+  }
+  Out<ELFT>::RelaDyn->addReloc(
+      {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
+}
+
+template <class ELFT>
+static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
+                          bool IsWrite, RelExpr Expr, uint32_t Type,
+                          const uint8_t *Data) {
+  bool Preemptible = isPreemptible(Body, Type);
+  if (Body.isGnuIFunc()) {
+    Expr = toPlt(Expr);
+  } else if (!Preemptible) {
+    if (needsPlt(Expr))
+      Expr = fromPlt(Expr);
+    if (Expr == R_GOT_PC)
+      Expr = Target->adjustRelaxExpr(Type, Data, Expr);
+  }
+  Expr = Target->getThunkExpr(Expr, Type, File, Body);
+
+  if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))
+    return Expr;
+
+  // This relocation would require the dynamic linker to write a value to read
+  // only memory. We can hack around it if we are producing an executable and
+  // the refered symbol can be preemepted to refer to the executable.
+  if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
+    error("can't create dynamic relocation " + getRelName(Type) +
+          " against readonly segment");
+    return Expr;
+  }
+  if (Body.getVisibility() != STV_DEFAULT) {
+    error("cannot preempt symbol");
+    return Expr;
+  }
+  if (Body.isObject()) {
+    // Produce a copy relocation.
+    auto *B = cast<SharedSymbol<ELFT>>(&Body);
+    if (!B->needsCopy())
+      addCopyRelSymbol(B);
+    return Expr;
+  }
+  if (Body.isFunc()) {
+    // This handles a non PIC program call to function in a shared library. In
+    // an ideal world, we could just report an error saying the relocation can
+    // overflow at runtime. In the real world with glibc, crt1.o has a
+    // R_X86_64_PC32 pointing to libc.so.
+    //
+    // The general idea on how to handle such cases is to create a PLT entry and
+    // use that as the function value.
+    //
+    // For the static linking part, we just return a plt expr and everything
+    // else will use the the PLT entry as the address.
+    //
+    // The remaining problem is making sure pointer equality still works. We
+    // need the help of the dynamic linker for that. We let it know that we have
+    // a direct reference to a so symbol by creating an undefined symbol with a
+    // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+    // the value of the symbol we created. This is true even for got entries, so
+    // pointer equality is maintained. To avoid an infinite loop, the only entry
+    // that points to the real function is a dedicated got entry used by the
+    // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+    // R_386_JMP_SLOT, etc).
+    Body.NeedsCopyOrPltAddr = true;
+    return toPlt(Expr);
+  }
+  error("symbol is missing type");
+
+  return Expr;
+}
+
+template <class ELFT, class RelTy>
+static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
+                                         const uint8_t *SectionData,
+                                         const RelTy *End, const RelTy &RI,
+                                         RelExpr Expr, SymbolBody &Body) {
+  typedef typename ELFT::uint uintX_t;
+
+  uint32_t Type = RI.getType(Config->Mips64EL);
+  uintX_t Addend = getAddend<ELFT>(RI);
+  const uint8_t *BufLoc = SectionData + RI.r_offset;
+  if (!RelTy::IsRela)
+    Addend += Target->getImplicitAddend(BufLoc, Type);
+  if (Config->EMachine == EM_MIPS) {
+    Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End);
+    if (Type == R_MIPS_LO16 && Expr == R_PC)
+      // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp
+      // symbol. In that case we should use the following formula for
+      // calculation "AHL + GP - P + 4". Let's add 4 right here.
+      // For details see p. 4-19 at
+      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+      Addend += 4;
+    if (Expr == R_GOTREL) {
+      Addend -= MipsGPOffset;
+      if (Body.isLocal())
+        Addend += File.getMipsGp0();
+    }
+  }
+  if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
+    Addend += getPPC64TocBase();
+  return Addend;
+}
+
+// The reason we have to do this early scan is as follows
+// * To mmap the output file, we need to know the size
+// * For that, we need to know how many dynamic relocs we will have.
+// It might be possible to avoid this by outputting the file with write:
+// * Write the allocated output sections, computing addresses.
+// * Apply relocations, recording which ones require a dynamic reloc.
+// * Write the dynamic relocations.
+// * Write the rest of the file.
+// This would have some drawbacks. For example, we would only know if .rela.dyn
+// is needed after applying relocations. If it is, it will go after rw and rx
+// sections. Given that it is ro, we will need an extra PT_LOAD. This
+// complicates things for the dynamic linker and means we would have to reserve
+// space for the extra PT_LOAD even if we end up not using it.
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
+  typedef typename ELFT::uint uintX_t;
+
+  bool IsWrite = C.getSectionHdr()->sh_flags & SHF_WRITE;
+
+  auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
+    Out<ELFT>::RelaDyn->addReloc(Reloc);
+  };
+
+  const elf::ObjectFile<ELFT> &File = *C.getFile();
+  ArrayRef<uint8_t> SectionData = C.getSectionData();
+  const uint8_t *Buf = SectionData.begin();
+  for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
+    const RelTy &RI = *I;
+    SymbolBody &Body = File.getRelocTargetSym(RI);
+    uint32_t Type = RI.getType(Config->Mips64EL);
+
+    RelExpr Expr = Target->getRelExpr(Type, Body);
+    bool Preemptible = isPreemptible(Body, Type);
+    Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf + RI.r_offset);
+    if (HasError)
+      continue;
+
+    // Skip a relocation that points to a dead piece
+    // in a mergeable section.
+    if (C.getOffset(RI.r_offset) == (uintX_t)-1)
+      continue;
+
+    // This relocation does not require got entry, but it is relative to got and
+    // needs it to be created. Here we request for that.
+    if (Expr == R_GOTONLY_PC || Expr == R_GOTREL || Expr == R_PPC_TOC)
+      Out<ELFT>::Got->HasGotOffRel = true;
+
+    uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
+
+    if (unsigned Processed = handleTlsRelocation<ELFT>(
+            Type, Body, C, RI.r_offset, Addend, Expr)) {
+      I += (Processed - 1);
+      continue;
+    }
+
+    // Ignore "hint" relocation because it is for optional code optimization.
+    if (Expr == R_HINT)
+      continue;
+
+    if (needsPlt(Expr) || Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
+        Expr == R_THUNK_PLT_PC || refersToGotEntry(Expr) ||
+        !isPreemptible(Body, Type)) {
+      // If the relocation points to something in the file, we can process it.
+      bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body);
+
+      // If the output being produced is position independent, the final value
+      // is still not known. In that case we still need some help from the
+      // dynamic linker. We can however do better than just copying the incoming
+      // relocation. We can process some of it and and just ask the dynamic
+      // linker to add the load address.
+      if (!Constant)
+        AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend});
+
+      // If the produced value is a constant, we just remember to write it
+      // when outputting this section. We also have to do it if the format
+      // uses Elf_Rel, since in that case the written value is the addend.
+      if (Constant || !RelTy::IsRela)
+        C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body});
+    } else {
+      // We don't know anything about the finaly symbol. Just ask the dynamic
+      // linker to handle the relocation for us.
+      AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend});
+      // MIPS ABI turns using of GOT and dynamic relocations inside out.
+      // While regular ABI uses dynamic relocations to fill up GOT entries
+      // MIPS ABI requires dynamic linker to fills up GOT entries using
+      // specially sorted dynamic symbol table. This affects even dynamic
+      // relocations against symbols which do not require GOT entries
+      // creation explicitly, i.e. do not have any GOT-relocations. So if
+      // a preemptible symbol has a dynamic relocation we anyway have
+      // to create a GOT entry for it.
+      // If a non-preemptible symbol has a dynamic relocation against it,
+      // dynamic linker takes it st_value, adds offset and writes down
+      // result of the dynamic relocation. In case of preemptible symbol
+      // dynamic linker performs symbol resolution, writes the symbol value
+      // to the GOT entry and reads the GOT entry when it needs to perform
+      // a dynamic relocation.
+      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
+      if (Config->EMachine == EM_MIPS)
+        Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+      continue;
+    }
+
+    // Some targets might require creation of thunks for relocations.
+    // Now we support only MIPS which requires LA25 thunk to call PIC
+    // code from non-PIC one, and ARM which requires interworking.
+    if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
+      auto *Sec = cast<InputSection<ELFT>>(&C);
+      addThunk<ELFT>(Type, Body, *Sec);
+    }
+
+    // At this point we are done with the relocated position. Some relocations
+    // also require us to create a got or plt entry.
+
+    // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol.
+    if (needsPlt(Expr)) {
+      if (Body.isInPlt())
+        continue;
+      Out<ELFT>::Plt->addEntry(Body);
+
+      uint32_t Rel;
+      if (Body.isGnuIFunc() && !Preemptible)
+        Rel = Target->IRelativeRel;
+      else
+        Rel = Target->PltRel;
+
+      Out<ELFT>::GotPlt->addEntry(Body);
+      Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
+                                    Body.getGotPltOffset<ELFT>(), !Preemptible,
+                                    &Body, 0});
+      continue;
+    }
+
+    if (refersToGotEntry(Expr)) {
+      if (Config->EMachine == EM_MIPS) {
+        // MIPS ABI has special rules to process GOT entries
+        // and doesn't require relocation entries for them.
+        // See "Global Offset Table" in Chapter 5 in the following document
+        // for detailed description:
+        // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+        Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        if (Body.isTls())
+          AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+                  !Preemptible, &Body, 0});
+        continue;
+      }
+
+      if (Body.isInGot())
+        continue;
+
+      Out<ELFT>::Got->addEntry(Body);
+      if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
+        uint32_t DynType;
+        if (Body.isTls())
+          DynType = Target->TlsGotRel;
+        else if (Preemptible)
+          DynType = Target->GotRel;
+        else
+          DynType = Target->RelativeRel;
+        AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+                !Preemptible, &Body, 0});
+      }
+      continue;
+    }
+  }
+}
+
+template <class ELFT> void scanRelocations(InputSection<ELFT> &C) {
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+  // Scan all relocations. Each relocation goes through a series
+  // of tests to determine if it needs special treatment, such as
+  // creating GOT, PLT, copy relocations, etc.
+  // Note that relocations for non-alloc sections are directly
+  // processed by InputSection::relocateNonAlloc.
+  if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
+    for (const Elf_Shdr *RelSec : C.RelocSections)
+      scanRelocations(C, *RelSec);
+}
+
+template <class ELFT>
+void scanRelocations(InputSectionBase<ELFT> &S,
+                     const typename ELFT::Shdr &RelSec) {
+  ELFFile<ELFT> &EObj = S.getFile()->getObj();
+  if (RelSec.sh_type == SHT_RELA)
+    scanRelocs(S, EObj.relas(&RelSec));
+  else
+    scanRelocs(S, EObj.rels(&RelSec));
+}
+
+template void scanRelocations<ELF32LE>(InputSection<ELF32LE> &);
+template void scanRelocations<ELF32BE>(InputSection<ELF32BE> &);
+template void scanRelocations<ELF64LE>(InputSection<ELF64LE> &);
+template void scanRelocations<ELF64BE>(InputSection<ELF64BE> &);
+
+template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &,
+                                       const ELF32LE::Shdr &);
+template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &,
+                                       const ELF32BE::Shdr &);
+template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &,
+                                       const ELF64LE::Shdr &);
+template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &,
+                                       const ELF64BE::Shdr &);
+}
+}
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
new file mode 100644 (file)
index 0000000..4c1c74e
--- /dev/null
@@ -0,0 +1,93 @@
+//===- Relocations.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_RELOCATIONS_H
+#define LLD_ELF_RELOCATIONS_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+class SymbolBody;
+template <class ELFT> class InputSection;
+template <class ELFT> class InputSectionBase;
+
+enum RelExpr {
+  R_ABS,
+  R_GOT,
+  R_GOTONLY_PC,
+  R_GOTREL,
+  R_GOT_FROM_END,
+  R_GOT_OFF,
+  R_GOT_PAGE_PC,
+  R_GOT_PC,
+  R_HINT,
+  R_MIPS_GOT_LOCAL_PAGE,
+  R_MIPS_GOT_OFF,
+  R_MIPS_TLSGD,
+  R_MIPS_TLSLD,
+  R_NEG_TLS,
+  R_PAGE_PC,
+  R_PC,
+  R_PLT,
+  R_PLT_PC,
+  R_PLT_PAGE_PC,
+  R_PPC_OPD,
+  R_PPC_PLT_OPD,
+  R_PPC_TOC,
+  R_RELAX_GOT_PC,
+  R_RELAX_GOT_PC_NOPIC,
+  R_RELAX_TLS_GD_TO_IE,
+  R_RELAX_TLS_GD_TO_IE_END,
+  R_RELAX_TLS_GD_TO_IE_ABS,
+  R_RELAX_TLS_GD_TO_IE_PAGE_PC,
+  R_RELAX_TLS_GD_TO_LE,
+  R_RELAX_TLS_GD_TO_LE_NEG,
+  R_RELAX_TLS_IE_TO_LE,
+  R_RELAX_TLS_LD_TO_LE,
+  R_SIZE,
+  R_THUNK_ABS,
+  R_THUNK_PC,
+  R_THUNK_PLT_PC,
+  R_TLS,
+  R_TLSDESC,
+  R_TLSDESC_PAGE,
+  R_TLSGD,
+  R_TLSGD_PC,
+  R_TLSLD,
+  R_TLSLD_PC
+};
+
+template <class ELFT> struct Relocation {
+  RelExpr Expr;
+  uint32_t Type;
+  InputSectionBase<ELFT> *InputSec;
+  uint64_t Offset;
+  uint64_t Addend;
+  SymbolBody *Sym;
+};
+
+template <class ELFT> void scanRelocations(InputSection<ELFT> &);
+
+template <class ELFT>
+void scanRelocations(InputSectionBase<ELFT> &, const typename ELFT::Shdr &);
+
+template <class ELFT>
+static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
+  return 0;
+}
+
+template <class ELFT>
+static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
+  return Rel.r_addend;
+}
+}
+}
+
+#endif
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
new file mode 100644 (file)
index 0000000..559ec1b
--- /dev/null
@@ -0,0 +1,163 @@
+//===- ScriptParser.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the base parser class for linker script and dynamic
+// list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptParser.h"
+#include "Error.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns the line that the character S[Pos] is in.
+static StringRef getLine(StringRef S, size_t Pos) {
+  size_t Begin = S.rfind('\n', Pos);
+  size_t End = S.find('\n', Pos);
+  Begin = (Begin == StringRef::npos) ? 0 : Begin + 1;
+  if (End == StringRef::npos)
+    End = S.size();
+  // rtrim for DOS-style newlines.
+  return S.substr(Begin, End - Begin).rtrim();
+}
+
+void ScriptParserBase::printErrorPos() {
+  StringRef Tok = Tokens[Pos == 0 ? 0 : Pos - 1];
+  StringRef Line = getLine(Input, Tok.data() - Input.data());
+  size_t Col = Tok.data() - Line.data();
+  error(Line);
+  error(std::string(Col, ' ') + "^");
+}
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptParserBase::setError(const Twine &Msg) {
+  if (Error)
+    return;
+  if (Input.empty() || Tokens.empty()) {
+    error(Msg);
+  } else {
+    error("line " + Twine(getPos()) + ": " + Msg);
+    printErrorPos();
+  }
+  Error = true;
+}
+
+// Split S into linker script tokens.
+std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) {
+  std::vector<StringRef> Ret;
+  for (;;) {
+    S = skipSpace(S);
+    if (S.empty())
+      return Ret;
+
+    // Quoted token
+    if (S.startswith("\"")) {
+      size_t E = S.find("\"", 1);
+      if (E == StringRef::npos) {
+        error("unclosed quote");
+        return {};
+      }
+      Ret.push_back(S.substr(1, E - 1));
+      S = S.substr(E + 1);
+      continue;
+    }
+
+    // Unquoted token
+    size_t Pos = S.find_first_not_of(
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+        "0123456789_.$/\\~=+[]*?-:!<>");
+    // A character that cannot start a word (which is usually a
+    // punctuation) forms a single character token.
+    if (Pos == 0)
+      Pos = 1;
+    Ret.push_back(S.substr(0, Pos));
+    S = S.substr(Pos);
+  }
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptParserBase::skipSpace(StringRef S) {
+  for (;;) {
+    if (S.startswith("/*")) {
+      size_t E = S.find("*/", 2);
+      if (E == StringRef::npos) {
+        error("unclosed comment in a linker script");
+        return "";
+      }
+      S = S.substr(E + 2);
+      continue;
+    }
+    if (S.startswith("#")) {
+      size_t E = S.find('\n', 1);
+      if (E == StringRef::npos)
+        E = S.size() - 1;
+      S = S.substr(E + 1);
+      continue;
+    }
+    size_t Size = S.size();
+    S = S.ltrim();
+    if (S.size() == Size)
+      return S;
+  }
+}
+
+// An erroneous token is handled as if it were the last token before EOF.
+bool ScriptParserBase::atEOF() { return Error || Tokens.size() == Pos; }
+
+StringRef ScriptParserBase::next() {
+  if (Error)
+    return "";
+  if (atEOF()) {
+    setError("unexpected EOF");
+    return "";
+  }
+  return Tokens[Pos++];
+}
+
+StringRef ScriptParserBase::peek() {
+  StringRef Tok = next();
+  if (Error)
+    return "";
+  --Pos;
+  return Tok;
+}
+
+bool ScriptParserBase::skip(StringRef Tok) {
+  if (Error)
+    return false;
+  if (atEOF()) {
+    setError("unexpected EOF");
+    return false;
+  }
+  if (Tokens[Pos] != Tok)
+    return false;
+  ++Pos;
+  return true;
+}
+
+void ScriptParserBase::expect(StringRef Expect) {
+  if (Error)
+    return;
+  StringRef Tok = next();
+  if (Tok != Expect)
+    setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns the current line number.
+size_t ScriptParserBase::getPos() {
+  if (Pos == 0)
+    return 1;
+  const char *Begin = Input.data();
+  const char *Tok = Tokens[Pos - 1].data();
+  return StringRef(Begin, Tok - Begin).count('\n') + 1;
+}
diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h
new file mode 100644 (file)
index 0000000..20735f7
--- /dev/null
@@ -0,0 +1,49 @@
+//===- ScriptParser.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_PARSER_H
+#define LLD_ELF_SCRIPT_PARSER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptParserBase {
+public:
+  explicit ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {}
+  explicit ScriptParserBase(std::vector<StringRef> Tokens)
+      : Input(""), Tokens(std::move(Tokens)) {}
+
+protected:
+  void setError(const Twine &Msg);
+  static std::vector<StringRef> tokenize(StringRef S);
+  static StringRef skipSpace(StringRef S);
+  bool atEOF();
+  StringRef next();
+  StringRef peek();
+  bool skip(StringRef Tok);
+  void expect(StringRef Expect);
+
+  size_t getPos();
+  void printErrorPos();
+
+  StringRef Input;
+  std::vector<StringRef> Tokens;
+  size_t Pos = 0;
+  bool Error = false;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
new file mode 100644 (file)
index 0000000..0c21e88
--- /dev/null
@@ -0,0 +1,98 @@
+//===- 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 "Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/config.h"
+#include <algorithm>
+
+#ifdef HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns true if S matches T. S can contain glob meta-characters.
+// The asterisk ('*') matches zero or more characters, and the question
+// mark ('?') matches one character.
+bool elf::globMatch(StringRef S, StringRef T) {
+  for (;;) {
+    if (S.empty())
+      return T.empty();
+    if (S[0] == '*') {
+      S = S.substr(1);
+      if (S.empty())
+        // Fast path. If a pattern is '*', it matches anything.
+        return true;
+      for (size_t I = 0, E = T.size(); I < E; ++I)
+        if (globMatch(S, T.substr(I)))
+          return true;
+      return false;
+    }
+    if (T.empty() || (S[0] != T[0] && S[0] != '?'))
+      return false;
+    S = S.substr(1);
+    T = T.substr(1);
+  }
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> elf::parseHex(StringRef S) {
+  std::vector<uint8_t> Hex;
+  while (!S.empty()) {
+    StringRef B = S.substr(0, 2);
+    S = S.substr(2);
+    uint8_t H;
+    if (B.getAsInteger(16, H)) {
+      error("not a hexadecimal value: " + B);
+      return {};
+    }
+    Hex.push_back(H);
+  }
+  return Hex;
+}
+
+static bool isAlpha(char C) {
+  return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
+}
+
+static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
+
+// Returns true if S is valid as a C language identifier.
+bool elf::isValidCIdentifier(StringRef S) {
+  return !S.empty() && isAlpha(S[0]) &&
+         std::all_of(S.begin() + 1, S.end(), isAlnum);
+}
+
+// Returns the demangled C++ symbol name for Name.
+std::string elf::demangle(StringRef Name) {
+#if !defined(HAVE_CXXABI_H)
+  return Name;
+#else
+  // __cxa_demangle can be used to demangle strings other than symbol
+  // names which do not necessarily start with "_Z". Name can be
+  // either a C or C++ symbol. Don't call __cxa_demangle if the name
+  // does not look like a C++ symbol name to avoid getting unexpected
+  // result for a C symbol that happens to match a mangled type name.
+  if (!Name.startswith("_Z"))
+    return Name;
+
+  char *Buf =
+      abi::__cxa_demangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+  if (!Buf)
+    return Name;
+  std::string S(Buf);
+  free(Buf);
+  return S;
+#endif
+}
diff --git a/ELF/Strings.h b/ELF/Strings.h
new file mode 100644 (file)
index 0000000..4948e9d
--- /dev/null
@@ -0,0 +1,29 @@
+//===- 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 "lld/Core/LLVM.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+bool globMatch(StringRef S, StringRef T);
+std::vector<uint8_t> parseHex(StringRef S);
+bool isValidCIdentifier(StringRef S);
+
+// Returns a demangled C++ symbol name. If Name is not a mangled
+// name or the system does not provide __cxa_demangle function,
+// it returns an unmodified string.
+std::string demangle(StringRef Name);
+}
+}
+
+#endif
diff --git a/ELF/SymbolListFile.cpp b/ELF/SymbolListFile.cpp
new file mode 100644 (file)
index 0000000..9e08802
--- /dev/null
@@ -0,0 +1,168 @@
+//===- SymbolListFile.cpp -------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+// It does not construct an AST but consume linker script directives directly.
+// Results are written to Driver or Config object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolListFile.h"
+#include "Config.h"
+#include "ScriptParser.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Parse the --dynamic-list argument.  A dynamic list is in the form
+//
+//  { symbol1; symbol2; [...]; symbolN };
+//
+// Multiple groups can be defined in the same file, and they are merged
+// into a single group.
+
+class DynamicListParser final : public ScriptParserBase {
+public:
+  DynamicListParser(StringRef S) : ScriptParserBase(S) {}
+  void run();
+};
+
+void DynamicListParser::run() {
+  while (!atEOF()) {
+    expect("{");
+    while (!Error) {
+      Config->DynamicList.push_back(next());
+      expect(";");
+      if (skip("}"))
+        break;
+    }
+    expect(";");
+  }
+}
+
+void elf::parseDynamicList(MemoryBufferRef MB) {
+  DynamicListParser(MB.getBuffer()).run();
+}
+
+// Parse the --version-script argument. We currently only accept the following
+// version script syntax:
+//
+//  { [ global: symbol1; symbol2; [...]; symbolN; ] local: *; };
+//
+// No wildcards are supported, other than for the local entry. Symbol versioning
+// is also not supported.
+
+class VersionScriptParser final : public ScriptParserBase {
+public:
+  VersionScriptParser(StringRef S) : ScriptParserBase(S) {}
+
+  void run();
+
+private:
+  void parseExtern(std::vector<SymbolVersion> *Globals);
+  void parseVersion(StringRef VerStr);
+  void parseGlobal(StringRef VerStr);
+  void parseLocal();
+};
+
+size_t elf::defineSymbolVersion(StringRef VerStr) {
+  // Identifiers start at 2 because 0 and 1 are reserved
+  // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
+  size_t VersionId = Config->VersionDefinitions.size() + 2;
+  Config->VersionDefinitions.push_back({VerStr, VersionId});
+  return VersionId;
+}
+
+void VersionScriptParser::parseVersion(StringRef VerStr) {
+  defineSymbolVersion(VerStr);
+
+  if (skip("global:") || peek() != "local:")
+    parseGlobal(VerStr);
+  if (skip("local:"))
+    parseLocal();
+  expect("}");
+
+  // Each version may have a parent version. For example, "Ver2" defined as
+  // "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This
+  // version hierarchy is, probably against your instinct, purely for human; the
+  // runtime doesn't care about them at all. In LLD, we simply skip the token.
+  if (!VerStr.empty() && peek() != ";")
+    next();
+  expect(";");
+}
+
+void VersionScriptParser::parseLocal() {
+  Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+  expect("*");
+  expect(";");
+}
+
+void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) {
+  expect("C++");
+  expect("{");
+
+  for (;;) {
+    if (peek() == "}" || Error)
+      break;
+    Globals->push_back({next(), true});
+    expect(";");
+  }
+
+  expect("}");
+  expect(";");
+}
+
+void VersionScriptParser::parseGlobal(StringRef VerStr) {
+  std::vector<SymbolVersion> *Globals;
+  if (VerStr.empty())
+    Globals = &Config->VersionScriptGlobals;
+  else
+    Globals = &Config->VersionDefinitions.back().Globals;
+
+  for (;;) {
+    if (skip("extern"))
+      parseExtern(Globals);
+
+    StringRef Cur = peek();
+    if (Cur == "}" || Cur == "local:" || Error)
+      return;
+    next();
+    Globals->push_back({Cur, false});
+    expect(";");
+  }
+}
+
+void VersionScriptParser::run() {
+  StringRef Msg = "anonymous version definition is used in "
+                  "combination with other version definitions";
+  if (skip("{")) {
+    parseVersion("");
+    if (!atEOF())
+      setError(Msg);
+    return;
+  }
+
+  while (!atEOF() && !Error) {
+    StringRef VerStr = next();
+    if (VerStr == "{") {
+      setError(Msg);
+      return;
+    }
+    expect("{");
+    parseVersion(VerStr);
+  }
+}
+
+void elf::parseVersionScript(MemoryBufferRef MB) {
+  VersionScriptParser(MB.getBuffer()).run();
+}
diff --git a/ELF/SymbolListFile.h b/ELF/SymbolListFile.h
new file mode 100644 (file)
index 0000000..cf3c4c6
--- /dev/null
@@ -0,0 +1,27 @@
+//===- SymbolListFile.h -----------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOL_LIST_FILE_H
+#define LLD_ELF_SYMBOL_LIST_FILE_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+size_t defineSymbolVersion(StringRef Version);
+
+void parseDynamicList(MemoryBufferRef MB);
+void parseVersionScript(MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..78c1298
--- /dev/null
@@ -0,0 +1,713 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbol table is a bag of all known symbols. We put all symbols of
+// all input files to the symbol table. The symbol table is basically
+// a hash table with the logic to resolve symbol name conflicts using
+// the symbol types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+#include "Config.h"
+#include "Error.h"
+#include "LinkerScript.h"
+#include "Strings.h"
+#include "SymbolListFile.h"
+#include "Symbols.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Support/StringSaver.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// All input object files must be for the same architecture
+// (e.g. it does not make sense to link x86 object files with
+// MIPS object files.) This function checks for that error.
+template <class ELFT> static bool isCompatible(InputFile *F) {
+  if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F))
+    return true;
+  if (F->EKind == Config->EKind && F->EMachine == Config->EMachine)
+    return true;
+  StringRef A = F->getName();
+  StringRef B = Config->Emulation;
+  if (B.empty())
+    B = Config->FirstElf->getName();
+  error(A + " is incompatible with " + B);
+  return false;
+}
+
+// Add symbols in File to the symbol table.
+template <class ELFT>
+void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
+  InputFile *FileP = File.get();
+  if (!isCompatible<ELFT>(FileP))
+    return;
+
+  // .a file
+  if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
+    ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
+    F->parse<ELFT>();
+    return;
+  }
+
+  // Lazy object file
+  if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
+    LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
+    F->parse<ELFT>();
+    return;
+  }
+
+  if (Config->Trace)
+    outs() << getFilename(FileP) << "\n";
+
+  // .so file
+  if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) {
+    // DSOs are uniquified not by filename but by soname.
+    F->parseSoName();
+    if (!SoNames.insert(F->getSoName()).second)
+      return;
+
+    SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
+    F->parseRest();
+    return;
+  }
+
+  // LLVM bitcode file
+  if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
+    BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
+    F->parse<ELFT>(ComdatGroups);
+    return;
+  }
+
+  // Regular object file
+  auto *F = cast<ObjectFile<ELFT>>(FileP);
+  ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
+  F->parse(ComdatGroups);
+}
+
+// This function is where all the optimizations of link-time
+// optimization happens. When LTO is in use, some input files are
+// not in native object file format but in the LLVM bitcode format.
+// This function compiles bitcode files into a few big native files
+// using LLVM functions and replaces bitcode symbols with the results.
+// Because all bitcode files that consist of a program are passed
+// to the compiler at once, it can do whole-program optimization.
+template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() {
+  if (BitcodeFiles.empty())
+    return;
+
+  // Compile bitcode files.
+  Lto.reset(new BitcodeCompiler);
+  for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles)
+    Lto->add(*F);
+  std::vector<std::unique_ptr<InputFile>> IFs = Lto->compile();
+
+  // Replace bitcode symbols.
+  for (auto &IF : IFs) {
+    ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());
+
+    DenseSet<StringRef> DummyGroups;
+    Obj->parse(DummyGroups);
+    ObjectFiles.emplace_back(Obj);
+  }
+}
+
+template <class ELFT>
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+                                                     uint8_t Visibility) {
+  return cast<DefinedRegular<ELFT>>(
+      addRegular(Name, STB_GLOBAL, Visibility)->body());
+}
+
+// Add Name as an "ignored" symbol. An ignored symbol is a regular
+// linker-synthesized defined symbol, but is only defined if needed.
+template <class ELFT>
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
+                                                    uint8_t Visibility) {
+  if (!find(Name))
+    return nullptr;
+  return addAbsolute(Name, Visibility);
+}
+
+// Set a flag for --trace-symbol so that we can print out a log message
+// if a new symbol with the same name is inserted into the symbol table.
+template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
+  Symtab.insert({Name, {-1, true}});
+}
+
+// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
+// Used to implement --wrap.
+template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
+  SymbolBody *B = find(Name);
+  if (!B)
+    return;
+  StringSaver Saver(Alloc);
+  Symbol *Sym = B->symbol();
+  Symbol *Real = addUndefined(Saver.save("__real_" + Name));
+  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+  // We rename symbols by replacing the old symbol's SymbolBody with the new
+  // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
+  // old symbol to instead refer to the new symbol.
+  memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
+  memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+}
+
+static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
+  if (VA == STV_DEFAULT)
+    return VB;
+  if (VB == STV_DEFAULT)
+    return VA;
+  return std::min(VA, VB);
+}
+
+// Find an existing symbol or create and insert a new one.
+template <class ELFT>
+std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+  auto P = Symtab.insert({Name, {(int)SymVector.size(), false}});
+  SymIndex &V = P.first->second;
+  bool IsNew = P.second;
+
+  if (V.Idx == -1) {
+    IsNew = true;
+    V = {(int)SymVector.size(), true};
+  }
+
+  Symbol *Sym;
+  if (IsNew) {
+    Sym = new (Alloc) Symbol;
+    Sym->Binding = STB_WEAK;
+    Sym->Visibility = STV_DEFAULT;
+    Sym->IsUsedInRegularObj = false;
+    Sym->ExportDynamic = false;
+    Sym->VersionId = Config->DefaultSymbolVersion;
+    Sym->Traced = V.Traced;
+    SymVector.push_back(Sym);
+  } else {
+    Sym = SymVector[V.Idx];
+  }
+  return {Sym, IsNew};
+}
+
+// Find an existing symbol or create and insert a new one, then apply the given
+// attributes.
+template <class ELFT>
+std::pair<Symbol *, bool>
+SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
+                          bool CanOmitFromDynSym, bool IsUsedInRegularObj,
+                          InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+
+  // Merge in the new symbol's visibility.
+  S->Visibility = getMinVisibility(S->Visibility, Visibility);
+  if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
+    S->ExportDynamic = true;
+  if (IsUsedInRegularObj)
+    S->IsUsedInRegularObj = true;
+  if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
+      ((Type == STT_TLS) != S->body()->isTls()))
+    error("TLS attribute mismatch for symbol: " +
+          conflictMsg(S->body(), File));
+
+  return {S, WasInserted};
+}
+
+// Construct a string in the form of "Sym in File1 and File2".
+// Used to construct an error message.
+template <typename ELFT>
+std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Existing,
+                                           InputFile *NewFile) {
+  std::string Sym = Existing->getName();
+  if (Config->Demangle)
+    Sym = demangle(Sym);
+  return Sym + " in " + getFilename(Existing->File) + " and " +
+         getFilename(NewFile);
+}
+
+template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
+  return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
+                      /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
+                                        uint8_t StOther, uint8_t Type,
+                                        bool CanOmitFromDynSym,
+                                        InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(Name, Type, StOther & 3, CanOmitFromDynSym,
+             /*IsUsedInRegularObj*/ !File || !isa<BitcodeFile>(File), File);
+  if (WasInserted) {
+    S->Binding = Binding;
+    replaceBody<Undefined>(S, Name, StOther, Type, File);
+    return S;
+  }
+  if (Binding != STB_WEAK) {
+    if (S->body()->isShared() || S->body()->isLazy())
+      S->Binding = Binding;
+    if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body()))
+      SS->file()->IsUsed = true;
+  }
+  if (auto *L = dyn_cast<Lazy>(S->body())) {
+    // An undefined weak will not fetch archive members, but we have to remember
+    // its type. See also comment in addLazyArchive.
+    if (S->isWeak())
+      L->Type = Type;
+    else if (auto F = L->fetch())
+      addFile(std::move(F));
+  }
+  return S;
+}
+
+// We have a new defined symbol with the specified binding. Return 1 if the new
+// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
+// strong defined symbols.
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
+  if (WasInserted)
+    return 1;
+  SymbolBody *Body = S->body();
+  if (Body->isLazy() || Body->isUndefined() || Body->isShared())
+    return 1;
+  if (Binding == STB_WEAK)
+    return -1;
+  if (S->isWeak())
+    return 1;
+  return 0;
+}
+
+// We have a new non-common defined symbol with the specified binding. Return 1
+// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
+// is a conflict. If the new symbol wins, also update the binding.
+static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding) {
+  if (int Cmp = compareDefined(S, WasInserted, Binding)) {
+    if (Cmp > 0)
+      S->Binding = Binding;
+    return Cmp;
+  }
+  if (isa<DefinedCommon>(S->body())) {
+    // Non-common symbols take precedence over common symbols.
+    if (Config->WarnCommon)
+      warning("common " + S->body()->getName() + " is overridden");
+    return 1;
+  }
+  return 0;
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
+                                     uint64_t Alignment, uint8_t Binding,
+                                     uint8_t StOther, uint8_t Type,
+                                     InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false,
+             /*IsUsedInRegularObj*/ true, File);
+  int Cmp = compareDefined(S, WasInserted, Binding);
+  if (Cmp > 0) {
+    S->Binding = Binding;
+    replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+  } else if (Cmp == 0) {
+    auto *C = dyn_cast<DefinedCommon>(S->body());
+    if (!C) {
+      // Non-common symbols take precedence over common symbols.
+      if (Config->WarnCommon)
+        warning("common " + S->body()->getName() + " is overridden");
+      return S;
+    }
+
+    if (Config->WarnCommon)
+      warning("multiple common of " + S->body()->getName());
+
+    C->Size = std::max(C->Size, Size);
+    C->Alignment = std::max(C->Alignment, Alignment);
+  }
+  return S;
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::reportDuplicate(SymbolBody *Existing,
+                                        InputFile *NewFile) {
+  std::string Msg = "duplicate symbol: " + conflictMsg(Existing, NewFile);
+  if (Config->AllowMultipleDefinition)
+    warning(Msg);
+  else
+    error(Msg);
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym,
+                                      InputSectionBase<ELFT> *Section) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(Name, Sym.getType(), Sym.getVisibility(),
+             /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true,
+             Section ? Section->getFile() : nullptr);
+  int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding());
+  if (Cmp > 0)
+    replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section);
+  else if (Cmp == 0)
+    reportDuplicate(S->body(), Section->getFile());
+  return S;
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding,
+                                      uint8_t StOther) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false,
+             /*IsUsedInRegularObj*/ true, nullptr);
+  int Cmp = compareDefinedNonCommon(S, WasInserted, Binding);
+  if (Cmp > 0)
+    replaceBody<DefinedRegular<ELFT>>(S, Name, StOther);
+  else if (Cmp == 0)
+    reportDuplicate(S->body(), nullptr);
+  return S;
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
+                                        OutputSectionBase<ELFT> *Section,
+                                        uintX_t Value) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(N, STT_NOTYPE, STV_HIDDEN, /*CanOmitFromDynSym*/ false,
+             /*IsUsedInRegularObj*/ true, nullptr);
+  int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL);
+  if (Cmp > 0)
+    replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section);
+  else if (Cmp == 0)
+    reportDuplicate(S->body(), nullptr);
+  return S;
+}
+
+template <typename ELFT>
+void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
+                                  const Elf_Sym &Sym,
+                                  const typename ELFT::Verdef *Verdef) {
+  // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
+  // as the visibility, which will leave the visibility in the symbol table
+  // unchanged.
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true,
+             /*IsUsedInRegularObj*/ false, F);
+  // Make sure we preempt DSO symbols with default visibility.
+  if (Sym.getVisibility() == STV_DEFAULT)
+    S->ExportDynamic = true;
+  if (WasInserted || isa<Undefined>(S->body())) {
+    replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
+    if (!S->isWeak())
+      F->IsUsed = true;
+  }
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak,
+                                      uint8_t StOther, uint8_t Type,
+                                      bool CanOmitFromDynSym, BitcodeFile *F) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym,
+                                    /*IsUsedInRegularObj*/ false, F);
+  int Cmp =
+      compareDefinedNonCommon(S, WasInserted, IsWeak ? STB_WEAK : STB_GLOBAL);
+  if (Cmp > 0)
+    replaceBody<DefinedBitcode>(S, Name, StOther, Type, F);
+  else if (Cmp == 0)
+    reportDuplicate(S->body(), F);
+  return S;
+}
+
+template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
+  auto It = Symtab.find(Name);
+  if (It == Symtab.end())
+    return nullptr;
+  SymIndex V = It->second;
+  if (V.Idx == -1)
+    return nullptr;
+  return SymVector[V.Idx]->body();
+}
+
+// Returns a list of defined symbols that match with a given glob pattern.
+template <class ELFT>
+std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) {
+  std::vector<SymbolBody *> Res;
+  for (Symbol *Sym : SymVector) {
+    SymbolBody *B = Sym->body();
+    if (!B->isUndefined() && globMatch(Pattern, B->getName()))
+      Res.push_back(B);
+  }
+  return Res;
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+                                       const object::Archive::Symbol Sym) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Sym.getName());
+  if (WasInserted) {
+    replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
+    return;
+  }
+  if (!S->body()->isUndefined())
+    return;
+
+  // Weak undefined symbols should not fetch members from archives. If we were
+  // to keep old symbol we would not know that an archive member was available
+  // if a strong undefined symbol shows up afterwards in the link. If a strong
+  // undefined symbol never shows up, this lazy symbol will get to the end of
+  // the link and must be treated as the weak undefined one. We already marked
+  // this symbol as used when we added it to the symbol table, but we also need
+  // to preserve its type. FIXME: Move the Type field to Symbol.
+  if (S->isWeak()) {
+    replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
+    return;
+  }
+  MemoryBufferRef MBRef = F->getMember(&Sym);
+  if (!MBRef.getBuffer().empty())
+    addFile(createObjectFile(MBRef, F->getName()));
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted) {
+    replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType);
+    return;
+  }
+  if (!S->body()->isUndefined())
+    return;
+
+  // See comment for addLazyArchive above.
+  if (S->isWeak()) {
+    replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
+  } else {
+    MemoryBufferRef MBRef = Obj.getBuffer();
+    if (!MBRef.getBuffer().empty())
+      addFile(createObjectFile(MBRef));
+  }
+}
+
+// Process undefined (-u) flags by loading lazy symbols named by those flags.
+template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
+  for (StringRef S : Config->Undefined)
+    if (auto *L = dyn_cast_or_null<Lazy>(find(S)))
+      if (std::unique_ptr<InputFile> File = L->fetch())
+        addFile(std::move(File));
+}
+
+// This function takes care of the case in which shared libraries depend on
+// the user program (not the other way, which is usual). Shared libraries
+// may have undefined symbols, expecting that the user program provides
+// the definitions for them. An example is BSD's __progname symbol.
+// We need to put such symbols to the main program's .dynsym so that
+// shared libraries can find them.
+// Except this, we ignore undefined symbols in DSOs.
+template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
+  for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
+    for (StringRef U : File->getUndefinedSymbols())
+      if (SymbolBody *Sym = find(U))
+        if (Sym->isDefined())
+          Sym->symbol()->ExportDynamic = true;
+}
+
+// This function process the dynamic list option by marking all the symbols
+// to be exported in the dynamic table.
+template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
+  for (StringRef S : Config->DynamicList)
+    if (SymbolBody *B = find(S))
+      B->symbol()->ExportDynamic = true;
+}
+
+static bool hasWildcard(StringRef S) {
+  return S.find_first_of("?*") != StringRef::npos;
+}
+
+static void setVersionId(SymbolBody *Body, StringRef VersionName,
+                         StringRef Name, uint16_t Version) {
+  if (!Body || Body->isUndefined()) {
+    if (Config->NoUndefinedVersion)
+      error("version script assignment of " + VersionName + " to symbol " +
+            Name + " failed: symbol not defined");
+    return;
+  }
+
+  Symbol *Sym = Body->symbol();
+  if (Sym->VersionId != Config->DefaultSymbolVersion)
+    warning("duplicate symbol " + Name + " in version script");
+  Sym->VersionId = Version;
+}
+
+template <class ELFT>
+std::map<std::string, SymbolBody *> SymbolTable<ELFT>::getDemangledSyms() {
+  std::map<std::string, SymbolBody *> Result;
+  for (Symbol *Sym : SymVector) {
+    SymbolBody *B = Sym->body();
+    Result[demangle(B->getName())] = B;
+  }
+  return Result;
+}
+
+static bool hasExternCpp() {
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    for (SymbolVersion Sym : V.Globals)
+      if (Sym.IsExternCpp)
+        return true;
+  return false;
+}
+
+// This function processes the --version-script option by marking all global
+// symbols with the VersionScriptGlobal flag, which acts as a filter on the
+// dynamic symbol table.
+template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
+  // If version script does not contain versions declarations,
+  // we just should mark global symbols.
+  if (!Config->VersionScriptGlobals.empty()) {
+    for (SymbolVersion &Sym : Config->VersionScriptGlobals)
+      if (SymbolBody *B = find(Sym.Name))
+        B->symbol()->VersionId = VER_NDX_GLOBAL;
+    return;
+  }
+
+  if (Config->VersionDefinitions.empty())
+    return;
+
+  // If we have symbols version declarations, we should
+  // assign version references for each symbol.
+  // Current rules are:
+  // * If there is an exact match for the mangled name or we have extern C++
+  //   exact match, then we use it.
+  // * Otherwise, we look through the wildcard patterns. We look through the
+  //   version tags in reverse order. We use the first match we find (the last
+  //   matching version tag in the file).
+  // Handle exact matches and build a map of demangled externs for
+  // quick search during next step.
+  std::map<std::string, SymbolBody *> Demangled;
+  if (hasExternCpp())
+    Demangled = getDemangledSyms();
+
+  for (VersionDefinition &V : Config->VersionDefinitions) {
+    for (SymbolVersion Sym : V.Globals) {
+      if (hasWildcard(Sym.Name))
+        continue;
+      SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
+      setVersionId(B, V.Name, Sym.Name, V.Id);
+    }
+  }
+
+  // Handle wildcards.
+  for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
+    VersionDefinition &V = Config->VersionDefinitions[I];
+    for (SymbolVersion &Sym : V.Globals)
+      if (hasWildcard(Sym.Name))
+        for (SymbolBody *B : findAll(Sym.Name))
+          if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+            B->symbol()->VersionId = V.Id;
+  }
+}
+
+// Returns the size of the longest version name.
+static int getMaxVersionLen() {
+  size_t Len = 0;
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    Len = std::max(Len, V.Name.size());
+  return Len;
+}
+
+// Parses a symbol name in the form of <name>@<version> or <name>@@<version>.
+static std::pair<StringRef, uint16_t>
+getSymbolVersion(SymbolBody *B, int MaxVersionLen) {
+  StringRef S = B->getName();
+
+  // MaxVersionLen was passed so that we don't need to scan
+  // all characters in a symbol name. It is effective because
+  // versions are usually short and symbol names can be very long.
+  size_t Pos = S.find('@', std::max(0, int(S.size()) - MaxVersionLen - 2));
+  if (Pos == 0 || Pos == StringRef::npos)
+    return {"", 0};
+
+  StringRef Name = S.substr(0, Pos);
+  StringRef Verstr = S.substr(Pos + 1);
+  if (Verstr.empty())
+    return {"", 0};
+
+  // '@@' in a symbol name means the default version.
+  // It is usually the most recent one.
+  bool IsDefault = (Verstr[0] == '@');
+  if (IsDefault)
+    Verstr = Verstr.substr(1);
+
+  for (VersionDefinition &V : Config->VersionDefinitions) {
+    if (V.Name == Verstr)
+      return {Name, IsDefault ? V.Id : (V.Id | VERSYM_HIDDEN)};
+  }
+
+  // It is an error if the specified version was not defined.
+  error("symbol " + S + " has undefined version " + Verstr);
+  return {"", 0};
+}
+
+// Versions are usually assigned to symbols using version scripts,
+// but there's another way to assign versions to symbols.
+// If a symbol name contains '@', the string after it is not
+// actually a part of the symbol name but specifies a version.
+// This function takes care of it.
+template <class ELFT> void SymbolTable<ELFT>::scanSymbolVersions() {
+  if (Config->VersionDefinitions.empty())
+    return;
+
+  int MaxVersionLen = getMaxVersionLen();
+
+  // Unfortunately there's no way other than iterating over all
+  // symbols to look for '@' characters in symbol names.
+  // So this is inherently slow. A good news is that we do this
+  // only when versions have been defined.
+  for (Symbol *Sym : SymVector) {
+    // Symbol versions for exported symbols are by nature
+    // only for defined global symbols.
+    SymbolBody *B = Sym->body();
+    if (!B->isDefined())
+      continue;
+    uint8_t Visibility = B->getVisibility();
+    if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+      continue;
+
+    // Look for '@' in the symbol name.
+    StringRef Name;
+    uint16_t Version;
+    std::tie(Name, Version) = getSymbolVersion(B, MaxVersionLen);
+    if (Name.empty())
+      continue;
+
+    B->setName(Name);
+    Sym->VersionId = Version;
+  }
+}
+
+template class elf::SymbolTable<ELF32LE>;
+template class elf::SymbolTable<ELF32BE>;
+template class elf::SymbolTable<ELF64LE>;
+template class elf::SymbolTable<ELF64BE>;
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
new file mode 100644 (file)
index 0000000..40415b6
--- /dev/null
@@ -0,0 +1,144 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOL_TABLE_H
+#define LLD_ELF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "LTO.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class Lazy;
+template <class ELFT> class OutputSectionBase;
+struct Symbol;
+
+typedef llvm::CachedHash<StringRef> SymName;
+
+// 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.
+template <class ELFT> class SymbolTable {
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  void addFile(std::unique_ptr<InputFile> File);
+  void addCombinedLtoObject();
+
+  llvm::ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+
+  const std::vector<std::unique_ptr<ObjectFile<ELFT>>> &getObjectFiles() const {
+    return ObjectFiles;
+  }
+
+  const std::vector<std::unique_ptr<SharedFile<ELFT>>> &getSharedFiles() const {
+    return SharedFiles;
+  }
+
+  DefinedRegular<ELFT> *addAbsolute(StringRef Name,
+                                    uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+  DefinedRegular<ELFT> *addIgnored(StringRef Name,
+                                   uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+
+  Symbol *addUndefined(StringRef Name);
+  Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
+                       uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
+
+  Symbol *addRegular(StringRef Name, const Elf_Sym &Sym,
+                     InputSectionBase<ELFT> *Section);
+  Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther);
+  Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> *Section,
+                       uintX_t Value);
+  void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+                 const typename ELFT::Verdef *Verdef);
+
+  void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
+  void addLazyObject(StringRef Name, LazyObjectFile &Obj);
+  Symbol *addBitcode(StringRef Name, bool IsWeak, uint8_t StOther, uint8_t Type,
+                     bool CanOmitFromDynSym, BitcodeFile *File);
+
+  Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
+                    uint8_t Binding, uint8_t StOther, uint8_t Type,
+                    InputFile *File);
+
+  void scanUndefinedFlags();
+  void scanShlibUndefined();
+  void scanDynamicList();
+  void scanVersionScript();
+  void scanSymbolVersions();
+
+  SymbolBody *find(StringRef Name);
+
+  void trace(StringRef Name);
+  void wrap(StringRef Name);
+
+private:
+  std::vector<SymbolBody *> findAll(StringRef Pattern);
+  std::pair<Symbol *, bool> insert(StringRef Name);
+  std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
+                                   uint8_t Visibility, bool CanOmitFromDynSym,
+                                   bool IsUsedInRegularObj, InputFile *File);
+
+  std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
+  void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
+
+  std::map<std::string, SymbolBody *> getDemangledSyms();
+
+  struct SymIndex {
+    int Idx : 31;
+    unsigned Traced : 1;
+  };
+
+  // The order the global symbols are in is not defined. We can use an arbitrary
+  // order, but it has to be reproducible. That is true even when cross linking.
+  // The default hashing of StringRef produces different results on 32 and 64
+  // bit systems so we use a map to a vector. That is arbitrary, deterministic
+  // but a bit inefficient.
+  // FIXME: Experiment with passing in a custom hashing or sorting the symbols
+  // once symbol resolution is finished.
+  llvm::DenseMap<SymName, SymIndex> Symtab;
+  std::vector<Symbol *> SymVector;
+  llvm::BumpPtrAllocator Alloc;
+
+  // Comdat groups define "link once" sections. If two comdat groups have the
+  // same name, only one of them is linked, and the other is ignored. This set
+  // is used to uniquify them.
+  llvm::DenseSet<StringRef> ComdatGroups;
+
+  // The symbol table owns all file objects.
+  std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
+  std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
+  std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles;
+  std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
+  std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
+
+  // Set of .so files to not link the same shared object file more than once.
+  llvm::DenseSet<StringRef> SoNames;
+
+  std::unique_ptr<BitcodeCompiler> Lto;
+};
+
+template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; };
+template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
new file mode 100644 (file)
index 0000000..d6a605d
--- /dev/null
@@ -0,0 +1,336 @@
+//===- 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 "InputSection.h"
+#include "OutputSections.h"
+#include "Target.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT>
+static typename ELFT::uint getSymVA(const SymbolBody &Body,
+                                    typename ELFT::uint &Addend) {
+  typedef typename ELFT::uint uintX_t;
+
+  switch (Body.kind()) {
+  case SymbolBody::DefinedSyntheticKind: {
+    auto &D = cast<DefinedSynthetic<ELFT>>(Body);
+    const OutputSectionBase<ELFT> *Sec = D.Section;
+    if (!Sec)
+      return D.Value;
+    if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
+      return Sec->getVA() + Sec->getSize();
+    return Sec->getVA() + D.Value;
+  }
+  case SymbolBody::DefinedRegularKind: {
+    auto &D = cast<DefinedRegular<ELFT>>(Body);
+    InputSectionBase<ELFT> *SC = D.Section;
+
+    // According to the ELF spec reference to a local symbol from outside
+    // the group are not allowed. Unfortunately .eh_frame breaks that rule
+    // and must be treated specially. For now we just replace the symbol with
+    // 0.
+    if (SC == &InputSection<ELFT>::Discarded)
+      return 0;
+
+    // This is an absolute symbol.
+    if (!SC)
+      return D.Value;
+
+    uintX_t Offset = D.Value;
+    if (D.isSection()) {
+      Offset += Addend;
+      Addend = 0;
+    }
+    uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
+    if (D.isTls())
+      return VA - Out<ELFT>::TlsPhdr->p_vaddr;
+    return VA;
+  }
+  case SymbolBody::DefinedCommonKind:
+    return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
+  case SymbolBody::SharedKind: {
+    auto &SS = cast<SharedSymbol<ELFT>>(Body);
+    if (!SS.NeedsCopyOrPltAddr)
+      return 0;
+    if (SS.isFunc())
+      return Body.getPltVA<ELFT>();
+    return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
+  }
+  case SymbolBody::UndefinedKind:
+    return 0;
+  case SymbolBody::LazyArchiveKind:
+  case SymbolBody::LazyObjectKind:
+    assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
+    return 0;
+  case SymbolBody::DefinedBitcodeKind:
+    llvm_unreachable("should have been replaced");
+  }
+  llvm_unreachable("invalid symbol kind");
+}
+
+SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
+                       uint8_t Type)
+    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
+      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+      NameOffset(NameOffset) {}
+
+SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
+    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
+      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+      Name({Name.data(), Name.size()}) {}
+
+StringRef SymbolBody::getName() const {
+  assert(!isLocal());
+  return StringRef(Name.S, Name.Len);
+}
+
+void SymbolBody::setName(StringRef S) {
+  Name.S = S.data();
+  Name.Len = S.size();
+}
+
+// Returns true if a symbol can be replaced at load-time by a symbol
+// with the same name defined in other ELF executable or DSO.
+bool SymbolBody::isPreemptible() const {
+  if (isLocal())
+    return false;
+
+  // Shared symbols resolve to the definition in the DSO. The exceptions are
+  // symbols with copy relocations (which resolve to .bss) or preempt plt
+  // entries (which resolve to that plt entry).
+  if (isShared())
+    return !NeedsCopyOrPltAddr;
+
+  // That's all that can be preempted in a non-DSO.
+  if (!Config->Shared)
+    return false;
+
+  // Only symbols that appear in dynsym can be preempted.
+  if (!symbol()->includeInDynsym())
+    return false;
+
+  // Only default visibility symbols can be preempted.
+  if (symbol()->Visibility != STV_DEFAULT)
+    return false;
+
+  // -Bsymbolic means that definitions are not preempted.
+  if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
+    return !isDefined();
+  return true;
+}
+
+template <class ELFT> bool SymbolBody::hasThunk() const {
+  if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+    return DR->ThunkData != nullptr;
+  if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+    return S->ThunkData != nullptr;
+  return false;
+}
+
+template <class ELFT>
+typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
+  typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
+  return OutVA + Addend;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
+  return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
+  return GotIndex * Target->GotEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
+  return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
+  return GotPltIndex * Target->GotPltEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
+  return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize +
+         PltIndex * Target->PltEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
+  if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+    return DR->ThunkData->getVA();
+  if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+    return S->ThunkData->getVA();
+  fatal("getThunkVA() not supported for Symbol class\n");
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
+  if (const auto *C = dyn_cast<DefinedCommon>(this))
+    return C->Size;
+  if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+    return DR->Size;
+  if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+    return S->Sym.st_size;
+  return 0;
+}
+
+Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
+    : SymbolBody(K, Name, StOther, Type) {}
+
+Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
+    : SymbolBody(K, NameOffset, StOther, Type) {}
+
+DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
+                               BitcodeFile *F)
+    : Defined(DefinedBitcodeKind, Name, StOther, Type) {
+  this->File = F;
+}
+
+bool DefinedBitcode::classof(const SymbolBody *S) {
+  return S->kind() == DefinedBitcodeKind;
+}
+
+Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type,
+                     InputFile *File)
+    : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {
+  this->File = File;
+}
+
+Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type,
+                     InputFile *File)
+    : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
+  this->File = File;
+}
+
+template <typename ELFT>
+DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
+                                         OutputSectionBase<ELFT> *Section)
+    : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
+      Value(Value), Section(Section) {}
+
+DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
+                             uint8_t StOther, uint8_t Type, InputFile *File)
+    : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
+      Alignment(Alignment), Size(Size) {
+  this->File = File;
+}
+
+std::unique_ptr<InputFile> Lazy::fetch() {
+  if (auto *S = dyn_cast<LazyArchive>(this))
+    return S->fetch();
+  return cast<LazyObject>(this)->fetch();
+}
+
+LazyArchive::LazyArchive(ArchiveFile &File,
+                         const llvm::object::Archive::Symbol S, uint8_t Type)
+    : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) {
+  this->File = &File;
+}
+
+LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
+    : Lazy(LazyObjectKind, Name, Type) {
+  this->File = &File;
+}
+
+std::unique_ptr<InputFile> LazyArchive::fetch() {
+  MemoryBufferRef MBRef = file()->getMember(&Sym);
+
+  // getMember returns an empty buffer if the member was already
+  // read from the library.
+  if (MBRef.getBuffer().empty())
+    return std::unique_ptr<InputFile>(nullptr);
+  return createObjectFile(MBRef, file()->getName());
+}
+
+std::unique_ptr<InputFile> LazyObject::fetch() {
+  MemoryBufferRef MBRef = file()->getBuffer();
+  if (MBRef.getBuffer().empty())
+    return std::unique_ptr<InputFile>(nullptr);
+  return createObjectFile(MBRef);
+}
+
+bool Symbol::includeInDynsym() const {
+  if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+    return false;
+  return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() ||
+         (body()->isUndefined() && Config->Shared);
+}
+
+// Print out a log message for --trace-symbol.
+void elf::printTraceSymbol(Symbol *Sym) {
+  SymbolBody *B = Sym->body();
+  outs() << getFilename(B->File);
+
+  if (B->isUndefined())
+    outs() << ": reference to ";
+  else if (B->isCommon())
+    outs() << ": common definition of ";
+  else
+    outs() << ": definition of ";
+  outs() << B->getName() << "\n";
+}
+
+template bool SymbolBody::hasThunk<ELF32LE>() const;
+template bool SymbolBody::hasThunk<ELF32BE>() const;
+template bool SymbolBody::hasThunk<ELF64LE>() const;
+template bool SymbolBody::hasThunk<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
+template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
+template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
+template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
+
+template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
+template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
+template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
+template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const;
+template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const;
+template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const;
+template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const;
+template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
+template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
+template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
+template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
+template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
+template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
+template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
+template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
+template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getPltVA<ELF32LE>() const;
+template uint32_t SymbolBody::template getPltVA<ELF32BE>() const;
+template uint64_t SymbolBody::template getPltVA<ELF64LE>() const;
+template uint64_t SymbolBody::template getPltVA<ELF64BE>() const;
+
+template uint32_t SymbolBody::template getSize<ELF32LE>() const;
+template uint32_t SymbolBody::template getSize<ELF32BE>() const;
+template uint64_t SymbolBody::template getSize<ELF64LE>() const;
+template uint64_t SymbolBody::template getSize<ELF64BE>() const;
+
+template class elf::DefinedSynthetic<ELF32LE>;
+template class elf::DefinedSynthetic<ELF32BE>;
+template class elf::DefinedSynthetic<ELF64LE>;
+template class elf::DefinedSynthetic<ELF64BE>;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
new file mode 100644 (file)
index 0000000..aa9a87d
--- /dev/null
@@ -0,0 +1,474 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// All symbols are handled as SymbolBodies regardless of their types.
+// This file defines various types of SymbolBodies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOLS_H
+#define LLD_ELF_SYMBOLS_H
+
+#include "InputSection.h"
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/AlignOf.h"
+
+namespace lld {
+namespace elf {
+
+class ArchiveFile;
+class BitcodeFile;
+class InputFile;
+class LazyObjectFile;
+class SymbolBody;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class OutputSection;
+template <class ELFT> class OutputSectionBase;
+template <class ELFT> class SharedFile;
+
+struct Symbol;
+
+// The base class for real symbol classes.
+class SymbolBody {
+public:
+  enum Kind {
+    DefinedFirst,
+    DefinedRegularKind = DefinedFirst,
+    SharedKind,
+    DefinedCommonKind,
+    DefinedBitcodeKind,
+    DefinedSyntheticKind,
+    DefinedLast = DefinedSyntheticKind,
+    UndefinedKind,
+    LazyArchiveKind,
+    LazyObjectKind,
+  };
+
+  SymbolBody(Kind K) : SymbolKind(K) {}
+
+  Symbol *symbol();
+  const Symbol *symbol() const {
+    return const_cast<SymbolBody *>(this)->symbol();
+  }
+
+  Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+  bool isUndefined() const { return SymbolKind == UndefinedKind; }
+  bool isDefined() const { return SymbolKind <= DefinedLast; }
+  bool isCommon() const { return SymbolKind == DefinedCommonKind; }
+  bool isLazy() const {
+    return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+  }
+  bool isShared() const { return SymbolKind == SharedKind; }
+  bool isLocal() const { return IsLocal; }
+  bool isPreemptible() const;
+
+  StringRef getName() const;
+  void setName(StringRef S);
+
+  uint32_t getNameOffset() const {
+    assert(isLocal());
+    return NameOffset;
+  }
+
+  uint8_t getVisibility() const { return StOther & 0x3; }
+
+  unsigned DynsymIndex = 0;
+  uint32_t GotIndex = -1;
+  uint32_t GotPltIndex = -1;
+  uint32_t PltIndex = -1;
+  uint32_t GlobalDynIndex = -1;
+  bool isInGot() const { return GotIndex != -1U; }
+  bool isInPlt() const { return PltIndex != -1U; }
+  template <class ELFT> bool hasThunk() const;
+
+  template <class ELFT>
+  typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
+
+  template <class ELFT> typename ELFT::uint getGotOffset() const;
+  template <class ELFT> typename ELFT::uint getGotVA() const;
+  template <class ELFT> typename ELFT::uint getGotPltOffset() const;
+  template <class ELFT> typename ELFT::uint getGotPltVA() const;
+  template <class ELFT> typename ELFT::uint getPltVA() const;
+  template <class ELFT> typename ELFT::uint getThunkVA() const;
+  template <class ELFT> typename ELFT::uint getSize() const;
+
+  // The file from which this symbol was created.
+  InputFile *File = nullptr;
+
+protected:
+  SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
+
+  SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
+
+  const unsigned SymbolKind : 8;
+
+public:
+  // True if the linker has to generate a copy relocation for this shared
+  // symbol or if the symbol should point to its plt entry.
+  unsigned NeedsCopyOrPltAddr : 1;
+
+  // True if this is a local symbol.
+  unsigned IsLocal : 1;
+
+  // True if this symbol has an entry in the global part of MIPS GOT.
+  unsigned IsInGlobalMipsGot : 1;
+
+  // The following fields have the same meaning as the ELF symbol attributes.
+  uint8_t Type;    // symbol type
+  uint8_t StOther; // st_other field value
+
+  // The Type field may also have this value. It means that we have not yet seen
+  // a non-Lazy symbol with this name, so we don't know what its type is. The
+  // Type field is normally set to this value for Lazy symbols unless we saw a
+  // weak undefined symbol first, in which case we need to remember the original
+  // symbol's type in order to check for TLS mismatches.
+  enum { UnknownType = 255 };
+
+  bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+  bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+  bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+  bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+  bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+  bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+
+protected:
+  struct Str {
+    const char *S;
+    size_t Len;
+  };
+  union {
+    Str Name;
+    uint32_t NameOffset;
+  };
+};
+
+// The base class for any defined symbols.
+class Defined : public SymbolBody {
+public:
+  Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
+  Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
+  static bool classof(const SymbolBody *S) { return S->isDefined(); }
+};
+
+// The defined symbol in LLVM bitcode files.
+class DefinedBitcode : public Defined {
+public:
+  DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, BitcodeFile *F);
+  static bool classof(const SymbolBody *S);
+  BitcodeFile *file() { return (BitcodeFile *)this->File; }
+};
+
+class DefinedCommon : public Defined {
+public:
+  DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther,
+                uint8_t Type, InputFile *File);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::DefinedCommonKind;
+  }
+
+  // The output offset of this common symbol in the output bss. Computed by the
+  // writer.
+  uint64_t OffsetInBss;
+
+  // The maximum alignment we have seen for this symbol.
+  uint64_t Alignment;
+
+  uint64_t Size;
+};
+
+// Regular defined symbols read from object file symbol tables.
+template <class ELFT> class DefinedRegular : public Defined {
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  DefinedRegular(StringRef Name, const Elf_Sym &Sym,
+                 InputSectionBase<ELFT> *Section)
+      : Defined(SymbolBody::DefinedRegularKind, Name, Sym.st_other,
+                Sym.getType()),
+        Value(Sym.st_value), Size(Sym.st_size),
+        Section(Section ? Section->Repl : NullInputSection) {
+    if (Section)
+      this->File = Section->getFile();
+  }
+
+  DefinedRegular(const Elf_Sym &Sym, InputSectionBase<ELFT> *Section)
+      : Defined(SymbolBody::DefinedRegularKind, Sym.st_name, Sym.st_other,
+                Sym.getType()),
+        Value(Sym.st_value), Size(Sym.st_size),
+        Section(Section ? Section->Repl : NullInputSection) {
+    assert(isLocal());
+    if (Section)
+      this->File = Section->getFile();
+  }
+
+  DefinedRegular(StringRef Name, uint8_t StOther)
+      : Defined(SymbolBody::DefinedRegularKind, Name, StOther,
+                llvm::ELF::STT_NOTYPE),
+        Value(0), Size(0), Section(NullInputSection) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::DefinedRegularKind;
+  }
+
+  uintX_t Value;
+  uintX_t Size;
+
+  // The input section this symbol belongs to. Notice that this is
+  // a reference to a pointer. We are using two levels of indirections
+  // because of ICF. If ICF decides two sections need to be merged, it
+  // manipulates this Section pointers so that they point to the same
+  // section. This is a bit tricky, so be careful to not be confused.
+  // If this is null, the symbol is an absolute symbol.
+  InputSectionBase<ELFT> *&Section;
+
+  // If non-null the symbol has a Thunk that may be used as an alternative
+  // destination for callers of this Symbol.
+  Thunk<ELFT> *ThunkData = nullptr;
+
+private:
+  static InputSectionBase<ELFT> *NullInputSection;
+};
+
+template <class ELFT>
+InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection;
+
+// DefinedSynthetic is a class to represent linker-generated ELF symbols.
+// The difference from the regular symbol is that DefinedSynthetic symbols
+// don't belong to any input files or sections. Thus, its constructor
+// takes an output section to calculate output VA, etc.
+// If Section is null, this symbol is relative to the image base.
+template <class ELFT> class DefinedSynthetic : public Defined {
+public:
+  typedef typename ELFT::uint uintX_t;
+  DefinedSynthetic(StringRef N, uintX_t Value,
+                   OutputSectionBase<ELFT> *Section);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::DefinedSyntheticKind;
+  }
+
+  // Special value designates that the symbol 'points'
+  // to the end of the section.
+  static const uintX_t SectionEnd = uintX_t(-1);
+
+  uintX_t Value;
+  const OutputSectionBase<ELFT> *Section;
+};
+
+class Undefined : public SymbolBody {
+public:
+  Undefined(StringRef Name, uint8_t StOther, uint8_t Type, InputFile *F);
+  Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, InputFile *F);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == UndefinedKind;
+  }
+
+  InputFile *file() { return this->File; }
+};
+
+template <class ELFT> class SharedSymbol : public Defined {
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::SharedKind;
+  }
+
+  SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+               const Elf_Verdef *Verdef)
+      : Defined(SymbolBody::SharedKind, Name, Sym.st_other, Sym.getType()),
+        Sym(Sym), Verdef(Verdef) {
+    // IFuncs defined in DSOs are treated as functions by the static linker.
+    if (isGnuIFunc())
+      Type = llvm::ELF::STT_FUNC;
+    this->File = F;
+  }
+
+  SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; }
+
+  const Elf_Sym &Sym;
+
+  // This field is a pointer to the symbol's version definition.
+  const Elf_Verdef *Verdef;
+
+  // OffsetInBss is significant only when needsCopy() is true.
+  uintX_t OffsetInBss = 0;
+
+  // If non-null the symbol has a Thunk that may be used as an alternative
+  // destination for callers of this Symbol.
+  Thunk<ELFT> *ThunkData = nullptr;
+  bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
+};
+
+// 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:
+  static bool classof(const SymbolBody *S) { return S->isLazy(); }
+
+  // Returns an object file for this symbol, or a nullptr if the file
+  // was already returned.
+  std::unique_ptr<InputFile> fetch();
+
+protected:
+  Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type)
+      : SymbolBody(K, Name, llvm::ELF::STV_DEFAULT, Type) {}
+};
+
+// LazyArchive symbols represents symbols in archive files.
+class LazyArchive : public Lazy {
+public:
+  LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S,
+              uint8_t Type);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyArchiveKind;
+  }
+
+  ArchiveFile *file() { return (ArchiveFile *)this->File; }
+  std::unique_ptr<InputFile> fetch();
+
+private:
+  const llvm::object::Archive::Symbol Sym;
+};
+
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Lazy {
+public:
+  LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyObjectKind;
+  }
+
+  LazyObjectFile *file() { return (LazyObjectFile *)this->File; }
+  std::unique_ptr<InputFile> fetch();
+};
+
+// Some linker-generated symbols need to be created as
+// DefinedRegular symbols.
+template <class ELFT> struct ElfSym {
+  // The content for _etext and etext symbols.
+  static DefinedRegular<ELFT> *Etext;
+  static DefinedRegular<ELFT> *Etext2;
+
+  // The content for _edata and edata symbols.
+  static DefinedRegular<ELFT> *Edata;
+  static DefinedRegular<ELFT> *Edata2;
+
+  // The content for _end and end symbols.
+  static DefinedRegular<ELFT> *End;
+  static DefinedRegular<ELFT> *End2;
+
+  // The content for _gp_disp symbol for MIPS target.
+  static SymbolBody *MipsGpDisp;
+};
+
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
+template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
+
+// 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 {
+  // Symbol binding. This is on the Symbol to track changes during resolution.
+  // In particular:
+  // An undefined weak is still weak when it resolves to a shared library.
+  // An undefined weak will not fetch archive members, but we have to remember
+  // it is weak.
+  uint8_t Binding;
+
+  // Version definition index.
+  uint16_t VersionId;
+
+  // Symbol visibility. This is the computed minimum visibility of all
+  // observed non-DSO symbols.
+  unsigned Visibility : 2;
+
+  // True if the symbol was used for linking and thus need to be added to the
+  // output file's symbol table. This is true for all symbols except for
+  // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+  // by other bitcode objects.
+  unsigned IsUsedInRegularObj : 1;
+
+  // If this flag is true and the symbol has protected or default visibility, it
+  // will appear in .dynsym. This flag is set by interposable DSO symbols in
+  // executables, by most symbols in DSOs and executables built with
+  // --export-dynamic, and by dynamic lists.
+  unsigned ExportDynamic : 1;
+
+  // True if this symbol is specified by --trace-symbol option.
+  unsigned Traced : 1;
+
+  bool includeInDynsym() const;
+  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
+
+  // 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. We
+  // assume that the size and alignment of ELF64LE symbols is sufficient for any
+  // ELFT, and we verify this with the static_asserts in replaceBody.
+  llvm::AlignedCharArrayUnion<
+      DefinedBitcode, DefinedCommon, DefinedRegular<llvm::object::ELF64LE>,
+      DefinedSynthetic<llvm::object::ELF64LE>, Undefined,
+      SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
+      Body;
+
+  SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
+  const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
+};
+
+void printTraceSymbol(Symbol *Sym);
+
+template <typename T, typename... ArgT>
+void replaceBody(Symbol *S, ArgT &&... Arg) {
+  static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
+  static_assert(llvm::AlignOf<T>::Alignment <=
+                    llvm::AlignOf<decltype(S->Body)>::Alignment,
+                "Body not aligned enough");
+  assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
+         "Not a SymbolBody");
+
+  new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
+
+  // Print out a log message if --trace-symbol was specified.
+  // This is for debugging.
+  if (S->Traced)
+    printTraceSymbol(S);
+}
+
+inline Symbol *SymbolBody::symbol() {
+  assert(!isLocal());
+  return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
+                                    offsetof(Symbol, Body));
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
new file mode 100644 (file)
index 0000000..0375eb9
--- /dev/null
@@ -0,0 +1,2120 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Machine-specific things, such as applying relocations, creation of
+// GOT or PLT entries, etc., are handled in this file.
+//
+// Refer the ELF spec for the single letter varaibles, S, A or P, used
+// in this file.
+//
+// Some functions defined in this file has "relaxTls" as part of their names.
+// They do peephole optimization for TLS variables by rewriting instructions.
+// They are not part of the ABI but optional optimization, so you can skip
+// them if you are not interested in how TLS variables are optimized.
+// See the following paper for the details.
+//
+//   Ulrich Drepper, ELF Handling For Thread-Local Storage
+//   http://www.akkadia.org/drepper/tls.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#include "Target.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "Thunks.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ELF.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+namespace lld {
+namespace elf {
+
+TargetInfo *Target;
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+StringRef getRelName(uint32_t Type) {
+  return getELFRelocationTypeName(Config->EMachine, Type);
+}
+
+template <unsigned N> static void checkInt(int64_t V, uint32_t Type) {
+  if (!isInt<N>(V))
+    error("relocation " + getRelName(Type) + " out of range");
+}
+
+template <unsigned N> static void checkUInt(uint64_t V, uint32_t Type) {
+  if (!isUInt<N>(V))
+    error("relocation " + getRelName(Type) + " out of range");
+}
+
+template <unsigned N> static void checkIntUInt(uint64_t V, uint32_t Type) {
+  if (!isInt<N>(V) && !isUInt<N>(V))
+    error("relocation " + getRelName(Type) + " out of range");
+}
+
+template <unsigned N> static void checkAlignment(uint64_t V, uint32_t Type) {
+  if ((V & (N - 1)) != 0)
+    error("improper alignment for relocation " + getRelName(Type));
+}
+
+static void errorDynRel(uint32_t Type) {
+  error("relocation " + getRelName(Type) +
+        " cannot be used against shared object; recompile with -fPIC.");
+}
+
+namespace {
+class X86TargetInfo final : public TargetInfo {
+public:
+  X86TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+  uint64_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;
+  bool isTlsLocalDynamicRel(uint32_t Type) const override;
+  bool isTlsGlobalDynamicRel(uint32_t Type) const override;
+  bool isTlsInitialExecRel(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 GotEntryAddr, 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;
+};
+
+template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
+public:
+  X86_64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  bool isTlsLocalDynamicRel(uint32_t Type) const override;
+  bool isTlsGlobalDynamicRel(uint32_t Type) const override;
+  bool isTlsInitialExecRel(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 GotEntryAddr, 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;
+};
+
+class PPCTargetInfo final : public TargetInfo {
+public:
+  PPCTargetInfo();
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+};
+
+class PPC64TargetInfo final : public TargetInfo {
+public:
+  PPC64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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;
+};
+
+class AArch64TargetInfo final : public TargetInfo {
+public:
+  AArch64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  bool isTlsInitialExecRel(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 GotEntryAddr, 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;
+};
+
+class AMDGPUTargetInfo final : public TargetInfo {
+public:
+  AMDGPUTargetInfo();
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+};
+
+class ARMTargetInfo final : public TargetInfo {
+public:
+  ARMTargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  uint64_t getImplicitAddend(const uint8_t *Buf, 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 GotEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  RelExpr getThunkExpr(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;
+};
+
+template <class ELFT> class MipsTargetInfo final : public TargetInfo {
+public:
+  MipsTargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+  uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  bool isTlsLocalDynamicRel(uint32_t Type) const override;
+  bool isTlsGlobalDynamicRel(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 GotEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  RelExpr getThunkExpr(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;
+};
+} // anonymous namespace
+
+TargetInfo *createTarget() {
+  switch (Config->EMachine) {
+  case EM_386:
+    return new X86TargetInfo();
+  case EM_AARCH64:
+    return new AArch64TargetInfo();
+  case EM_AMDGPU:
+    return new AMDGPUTargetInfo();
+  case EM_ARM:
+    return new ARMTargetInfo();
+  case EM_MIPS:
+    switch (Config->EKind) {
+    case ELF32LEKind:
+      return new MipsTargetInfo<ELF32LE>();
+    case ELF32BEKind:
+      return new MipsTargetInfo<ELF32BE>();
+    case ELF64LEKind:
+      return new MipsTargetInfo<ELF64LE>();
+    case ELF64BEKind:
+      return new MipsTargetInfo<ELF64BE>();
+    default:
+      fatal("unsupported MIPS target");
+    }
+  case EM_PPC:
+    return new PPCTargetInfo();
+  case EM_PPC64:
+    return new PPC64TargetInfo();
+  case EM_X86_64:
+    if (Config->EKind == ELF32LEKind)
+      return new X86_64TargetInfo<ELF32LE>();
+    return new X86_64TargetInfo<ELF64LE>();
+  }
+  fatal("unknown target machine");
+}
+
+TargetInfo::~TargetInfo() {}
+
+uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
+                                       uint32_t Type) const {
+  return 0;
+}
+
+bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
+
+RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+                                 const InputFile &File,
+                                 const SymbolBody &S) const {
+  return Expr;
+}
+
+bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
+
+bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
+
+bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
+  return false;
+}
+
+RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                    RelExpr Expr) const {
+  return Expr;
+}
+
+void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+X86TargetInfo::X86TargetInfo() {
+  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;
+}
+
+RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    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_PC32:
+    return R_PC;
+  case R_386_GOTPC:
+    return R_GOTONLY_PC;
+  case R_386_TLS_IE:
+    return R_GOT;
+  case R_386_GOT32:
+  case R_386_GOT32X:
+  case R_386_TLS_GOTIE:
+    return R_GOT_FROM_END;
+  case R_386_GOTOFF:
+    return R_GOTREL;
+  case R_386_TLS_LE:
+    return R_TLS;
+  case R_386_TLS_LE_32:
+    return R_NEG_TLS;
+  }
+}
+
+RelExpr X86TargetInfo::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 X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
+  write32le(Buf, Out<ELF32LE>::Dynamic->getVA());
+}
+
+void X86TargetInfo::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<ELF32LE>() + 6);
+}
+
+uint32_t X86TargetInfo::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;
+}
+
+bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
+  return Type == R_386_TLS_GD;
+}
+
+bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
+  return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM;
+}
+
+bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+  return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE;
+}
+
+void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
+  // Executable files and shared object files have
+  // separate procedure linkage tables.
+  if (Config->Pic) {
+    const uint8_t V[] = {
+        0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
+        0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp   *8(%ebx)
+        0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
+    };
+    memcpy(Buf, V, sizeof(V));
+    return;
+  }
+
+  const uint8_t PltData[] = {
+      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
+      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp   *(GOT+8)
+      0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+  write32le(Buf + 2, Got + 4);
+  write32le(Buf + 8, Got + 8);
+}
+
+void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                             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));
+
+  // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
+  Buf[1] = Config->Pic ? 0xa3 : 0x25;
+  uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+  write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
+  write32le(Buf + 7, RelOff);
+  write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
+                                          uint32_t Type) const {
+  switch (Type) {
+  default:
+    return 0;
+  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_LE:
+    return read32le(Buf);
+  }
+}
+
+void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  checkInt<32>(Val, Type);
+  write32le(Loc, Val);
+}
+
+void X86TargetInfo::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));
+  relocateOne(Loc + 5, R_386_32, Val);
+}
+
+void X86TargetInfo::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));
+  relocateOne(Loc + 5, R_386_32, Val);
+}
+
+// In some conditions, relocations can be optimized to avoid using GOT.
+// This function does that for Initial Exec to Local Exec case.
+void X86TargetInfo::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;
+    }
+  }
+  relocateOne(Loc, R_386_TLS_LE, Val);
+}
+
+void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
+  if (Type == R_386_TLS_LDO_32) {
+    relocateOne(Loc, R_386_TLS_LE, 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));
+}
+
+template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
+  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;
+}
+
+template <class ELFT>
+RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
+                                           const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    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:
+    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;
+  }
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
+  // The first entry holds the value of _DYNAMIC. It is not clear why that is
+  // required, but it is documented in the psabi and the glibc dynamic linker
+  // seems to use it (note that this is relevant for linking ld.so, not any
+  // other program).
+  write64le(Buf, Out<ELFT>::Dynamic->getVA());
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writeGotPlt(uint8_t *Buf,
+                                         const SymbolBody &S) const {
+  // See comments in X86TargetInfo::writeGotPlt.
+  write32le(Buf, S.getPltVA<ELFT>() + 6);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
+  const uint8_t PltData[] = {
+      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
+      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
+      0x0f, 0x1f, 0x40, 0x00              // nopl 0x0(rax)
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint64_t Got = Out<ELFT>::GotPlt->getVA();
+  uint64_t Plt = Out<ELFT>::Plt->getVA();
+  write32le(Buf + 2, Got - Plt + 2); // GOT+8
+  write32le(Buf + 8, Got - Plt + 4); // GOT+16
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                                      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 <relocation index>
+      0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[0]
+  };
+  memcpy(Buf, Inst, sizeof(Inst));
+
+  write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
+  write32le(Buf + 7, Index);
+  write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+template <class ELFT>
+uint32_t X86_64TargetInfo<ELFT>::getDynRel(uint32_t Type) const {
+  if (Type == R_X86_64_PC32 || Type == R_X86_64_32)
+    errorDynRel(Type);
+  return Type;
+}
+
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const {
+  return Type == R_X86_64_GOTTPOFF;
+}
+
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
+  return Type == R_X86_64_TLSGD;
+}
+
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
+  return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 ||
+         Type == R_X86_64_TLSLD;
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::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.
+  relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::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.
+  relocateOne(Loc + 8, R_X86_64_PC32, Val - 8);
+}
+
+// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
+// R_X86_64_TPOFF32 so that it does not use GOT.
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::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 {
+    fatal("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.
+  relocateOne(Loc, R_X86_64_TPOFF32, Val + 4);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::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) {
+    relocateOne(Loc, R_X86_64_TPOFF32, 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 <class ELFT>
+void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+                                         uint64_t Val) const {
+  switch (Type) {
+  case R_X86_64_32:
+    checkUInt<32>(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>(Val, Type);
+    write32le(Loc, Val);
+    break;
+  case R_X86_64_64:
+  case R_X86_64_DTPOFF64:
+  case R_X86_64_SIZE64:
+  case R_X86_64_PC64:
+    write64le(Loc, Val);
+    break;
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+template <class ELFT>
+RelExpr X86_64TargetInfo<ELFT>::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 <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
+                                           uint8_t Op, uint8_t ModRm) const {
+  const uint8_t Rex = Loc[-3];
+  // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
+  if (Op == 0x85) {
+    // See "TEST-Logical Compare" (4-428 Vol. 2B),
+    // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
+
+    // ModR/M byte has form XX YYY ZZZ, where
+    // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
+    // XX has different meanings:
+    // 00: The operand's memory address is in reg1.
+    // 01: The operand's memory address is reg1 + a byte-sized displacement.
+    // 10: The operand's memory address is reg1 + a word-sized displacement.
+    // 11: The operand is reg1 itself.
+    // If an instruction requires only one operand, the unused reg2 field
+    // holds extra opcode bits rather than a register code
+    // 0xC0 == 11 000 000 binary.
+    // 0x38 == 00 111 000 binary.
+    // We transfer reg2 to reg1 here as operand.
+    // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
+    Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
+
+    // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
+    // See "TEST-Logical Compare" (4-428 Vol. 2B).
+    Loc[-2] = 0xf7;
+
+    // Move R bit to the B bit in REX byte.
+    // REX byte is encoded as 0100WRXB, where
+    // 0100 is 4bit fixed pattern.
+    // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
+    //   default operand size is used (which is 32-bit for most but not all
+    //   instructions).
+    // REX.R This 1-bit value is an extension to the MODRM.reg field.
+    // REX.X This 1-bit value is an extension to the SIB.index field.
+    // REX.B This 1-bit value is an extension to the MODRM.rm field or the
+    // SIB.base field.
+    // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
+    Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+    relocateOne(Loc, R_X86_64_PC32, 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;
+  relocateOne(Loc, R_X86_64_PC32, Val);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  const uint8_t Op = Loc[-2];
+  const uint8_t ModRm = Loc[-1];
+
+  // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
+  if (Op == 0x8b) {
+    Loc[-2] = 0x8d;
+    relocateOne(Loc, R_X86_64_PC32, 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
+    relocateOne(Loc, R_X86_64_PC32, 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
+  relocateOne(Loc - 1, R_X86_64_PC32, Val + 1);
+}
+
+// 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; }
+
+PPCTargetInfo::PPCTargetInfo() {}
+
+void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_ADDR16_HA:
+    write16be(Loc, applyPPCHa(Val));
+    break;
+  case R_PPC_ADDR16_LO:
+    write16be(Loc, applyPPCLo(Val));
+    break;
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  return R_ABS;
+}
+
+PPC64TargetInfo::PPC64TargetInfo() {
+  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).
+  PageSize = 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;
+}
+
+static uint64_t PPC64TocOffset = 0x8000;
+
+uint64_t 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 = Out<ELF64BE>::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;
+}
+
+RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) 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 PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                               uint64_t PltEntryAddr, int32_t Index,
+                               unsigned RelOff) const {
+  uint64_t Off = GotEntryAddr - 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<uint32_t, uint64_t> 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 PPC64TargetInfo::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>(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>(Val, Type);
+    write16be(Loc, Val);
+    break;
+  case R_PPC64_ADDR16_DS:
+    checkInt<16>(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>(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>(Val, Type);
+    write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
+    break;
+  }
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+AArch64TargetInfo::AArch64TargetInfo() {
+  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;
+
+  // 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 AArch64TargetInfo::getRelExpr(uint32_t Type,
+                                      const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    return R_TLSDESC_PAGE;
+  case R_AARCH64_TLSDESC_LD64_LO12_NC:
+  case R_AARCH64_TLSDESC_ADD_LO12_NC:
+    return R_TLSDESC;
+  case R_AARCH64_TLSDESC_CALL:
+    return R_HINT;
+  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;
+  }
+}
+
+RelExpr AArch64TargetInfo::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 AArch64TargetInfo::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_NC:
+  case R_AARCH64_TLSDESC_LD64_LO12_NC:
+  case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+    return true;
+  }
+}
+
+bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+  return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
+         Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
+}
+
+uint32_t AArch64TargetInfo::getDynRel(uint32_t Type) const {
+  if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
+    return Type;
+  // Keep it going with a dummy value so that we can find more reloc errors.
+  errorDynRel(Type);
+  return R_AARCH64_ABS32;
+}
+
+void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write64le(Buf, Out<ELF64LE>::Plt->getVA());
+}
+
+static uint64_t getAArch64Page(uint64_t Expr) {
+  return Expr & (~static_cast<uint64_t>(0xFFF));
+}
+
+void AArch64TargetInfo::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 = Out<ELF64LE>::GotPlt->getVA();
+  uint64_t Plt = Out<ELF64LE>::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 AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                                 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(GotEntryAddr) - getAArch64Page(PltEntryAddr));
+  relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr);
+  relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
+}
+
+static void updateAArch64Addr(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);
+}
+
+static inline void updateAArch64Add(uint8_t *L, uint64_t Imm) {
+  or32le(L, (Imm & 0xFFF) << 10);
+}
+
+void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                    uint64_t Val) const {
+  switch (Type) {
+  case R_AARCH64_ABS16:
+  case R_AARCH64_PREL16:
+    checkIntUInt<16>(Val, Type);
+    write16le(Loc, Val);
+    break;
+  case R_AARCH64_ABS32:
+  case R_AARCH64_PREL32:
+    checkIntUInt<32>(Val, Type);
+    write32le(Loc, Val);
+    break;
+  case R_AARCH64_ABS64:
+  case R_AARCH64_PREL64:
+    write64le(Loc, Val);
+    break;
+  case R_AARCH64_ADD_ABS_LO12_NC:
+    // This relocation stores 12 bits and there's no instruction
+    // to do it. Instead, we do a 32 bits store of the value
+    // of r_addend bitwise-or'ed Loc. This assumes that the addend
+    // bits in Loc are zero.
+    or32le(Loc, (Val & 0xFFF) << 10);
+    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>(Val, Type);
+    updateAArch64Addr(Loc, Val >> 12);
+    break;
+  case R_AARCH64_ADR_PREL_LO21:
+    checkInt<21>(Val, Type);
+    updateAArch64Addr(Loc, Val);
+    break;
+  case R_AARCH64_CALL26:
+  case R_AARCH64_JUMP26:
+    checkInt<28>(Val, Type);
+    or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
+    break;
+  case R_AARCH64_CONDBR19:
+    checkInt<21>(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_NC:
+    checkAlignment<8>(Val, Type);
+    or32le(Loc, (Val & 0xFF8) << 7);
+    break;
+  case R_AARCH64_LDST128_ABS_LO12_NC:
+    or32le(Loc, (Val & 0x0FF8) << 6);
+    break;
+  case R_AARCH64_LDST16_ABS_LO12_NC:
+    or32le(Loc, (Val & 0x0FFC) << 9);
+    break;
+  case R_AARCH64_LDST8_ABS_LO12_NC:
+    or32le(Loc, (Val & 0xFFF) << 10);
+    break;
+  case R_AARCH64_LDST32_ABS_LO12_NC:
+    or32le(Loc, (Val & 0xFFC) << 8);
+    break;
+  case R_AARCH64_LDST64_ABS_LO12_NC:
+    or32le(Loc, (Val & 0xFF8) << 7);
+    break;
+  case R_AARCH64_TSTBR14:
+    checkInt<16>(Val, Type);
+    or32le(Loc, (Val & 0xFFFC) << 3);
+    break;
+  case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    checkInt<24>(Val, Type);
+    updateAArch64Add(Loc, Val >> 12);
+    break;
+  case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+  case R_AARCH64_TLSDESC_ADD_LO12_NC:
+    updateAArch64Add(Loc, Val);
+    break;
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+void AArch64TargetInfo::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_NC]
+  //   add     x0, x0, :tlsdesc_los:v     [_AARCH64_TLSDESC_ADD_LO12_NC]
+  //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
+  //   blr     x1
+  // And it can optimized to:
+  //   movz    x0, #0x0, lsl #16
+  //   movk    x0, #0x10
+  //   nop
+  //   nop
+  checkUInt<32>(Val, Type);
+
+  switch (Type) {
+  case R_AARCH64_TLSDESC_ADD_LO12_NC:
+  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_NC:
+    write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
+    return;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+  }
+}
+
+void AArch64TargetInfo::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_NC]
+  //   add     x0, x0, :tlsdesc_los:v     [_AARCH64_TLSDESC_ADD_LO12_NC]
+  //   .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_NC:
+  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_NC:
+    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 AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                       uint64_t Val) const {
+  checkUInt<32>(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");
+}
+
+AMDGPUTargetInfo::AMDGPUTargetInfo() {
+  GotRel = R_AMDGPU_ABS64;
+  GotEntrySize = 8;
+}
+
+void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
+  switch (Type) {
+  case R_AMDGPU_GOTPCREL:
+  case R_AMDGPU_REL32:
+    write32le(Loc, Val);
+    break;
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  switch (Type) {
+  case R_AMDGPU_REL32:
+    return R_PC;
+  case R_AMDGPU_GOTPCREL:
+    return R_GOT_PC;
+  default:
+    fatal("do not know how to handle relocation " + Twine(Type));
+  }
+}
+
+ARMTargetInfo::ARMTargetInfo() {
+  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;
+}
+
+RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) 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_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:
+    // GOT(S) + - GOT_ORG
+    return R_GOT_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_PREL31:
+  case R_ARM_REL32:
+  case R_ARM_THM_MOVW_PREL_NC:
+  case R_ARM_THM_MOVT_PREL:
+    return R_PC;
+  }
+}
+
+uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
+  if (Type == R_ARM_ABS32)
+    return Type;
+  // Keep it going with a dummy value so that we can find more reloc errors.
+  errorDynRel(Type);
+  return R_ARM_ABS32;
+}
+
+void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write32le(Buf, Out<ELF32LE>::Plt->getVA());
+}
+
+void ARMTargetInfo::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 = Out<ELF32LE>::GotPlt->getVA();
+  uint64_t L1 = Out<ELF32LE>::Plt->getVA() + 8;
+  write32le(Buf + 16, GotPlt - L1 - 8);
+}
+
+void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                             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, GotEntryAddr - L1 - 8);
+}
+
+RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+                                    const InputFile &File,
+                                    const SymbolBody &S) const {
+  // 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<ELF32LE>() & 1) == 1))
+      return R_THUNK_PC;
+    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)
+      return R_THUNK_PLT_PC;
+    if ((S.getVA<ELF32LE>() & 1) == 0)
+      return R_THUNK_PC;
+    break;
+  }
+  return Expr;
+}
+
+void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  switch (Type) {
+  case R_ARM_NONE:
+    break;
+  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:
+    write32le(Loc, Val);
+    break;
+  case R_ARM_PREL31:
+    checkInt<31>(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>(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
+  case R_ARM_JUMP24:
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+    checkInt<26>(Val, Type);
+    write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+    break;
+  case R_ARM_THM_JUMP11:
+    checkInt<12>(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>(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
+  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>(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>(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>(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:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+uint64_t ARMTargetInfo::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:
+    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
+  }
+  }
+}
+
+template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
+  GotPltHeaderEntriesNum = 2;
+  PageSize = 65536;
+  GotEntrySize = sizeof(typename ELFT::uint);
+  GotPltEntrySize = sizeof(typename ELFT::uint);
+  PltEntrySize = 16;
+  PltHeaderSize = 32;
+  CopyRel = R_MIPS_COPY;
+  PltRel = R_MIPS_JUMP_SLOT;
+  if (ELFT::Is64Bits) {
+    RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
+    TlsGotRel = R_MIPS_TLS_TPREL64;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+  } else {
+    RelativeRel = R_MIPS_REL32;
+    TlsGotRel = R_MIPS_TLS_TPREL32;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+  }
+}
+
+template <class ELFT>
+RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
+                                         const SymbolBody &S) const {
+  if (ELFT::Is64Bits)
+    // See comment in the calculateMips64RelChain.
+    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_GOTREL;
+  case R_MIPS_26:
+    return R_PLT;
+  case R_MIPS_HI16:
+  case R_MIPS_LO16:
+  case R_MIPS_GOT_OFST:
+    // MIPS _gp_disp designates offset between start of function and 'gp'
+    // pointer into GOT. __gnu_local_gp is equal to the current value of
+    // the 'gp'. Therefore any relocations against them do not require
+    // dynamic relocation.
+    if (&S == ElfSym<ELFT>::MipsGpDisp)
+      return R_PC;
+    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;
+  // fallthrough
+  case R_MIPS_CALL16:
+  case R_MIPS_GOT_DISP:
+  case R_MIPS_TLS_GOTTPREL:
+    return R_MIPS_GOT_OFF;
+  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 <class ELFT>
+uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
+  if (Type == R_MIPS_32 || Type == R_MIPS_64)
+    return RelativeRel;
+  // Keep it going with a dummy value so that we can find more reloc errors.
+  errorDynRel(Type);
+  return R_MIPS_32;
+}
+
+template <class ELFT>
+bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
+  return Type == R_MIPS_TLS_LDM;
+}
+
+template <class ELFT>
+bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
+  return Type == R_MIPS_TLS_GD;
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write32<ELFT::TargetEndianness>(Buf, Out<ELFT>::Plt->getVA());
+}
+
+static uint16_t mipsHigh(uint64_t V) { return (V + 0x8000) >> 16; }
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static int64_t getPcRelocAddend(const uint8_t *Loc) {
+  uint32_t Instr = read32<E>(Loc);
+  uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+  return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT);
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
+  uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+  uint32_t Instr = read32<E>(Loc);
+  if (SHIFT > 0)
+    checkAlignment<(1 << SHIFT)>(V, Type);
+  checkInt<BSIZE + SHIFT>(V, Type);
+  write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
+}
+
+template <endianness E>
+static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(V));
+}
+
+template <endianness E>
+static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, 0x3c1c0000);      // lui   $28, %hi(&GOTPLT[0])
+  write32<E>(Buf + 4, 0x8f990000);  // lw    $25, %lo(&GOTPLT[0])($28)
+  write32<E>(Buf + 8, 0x279c0000);  // addiu $28, $28, %lo(&GOTPLT[0])
+  write32<E>(Buf + 12, 0x031cc023); // subu  $24, $24, $28
+  write32<E>(Buf + 16, 0x03e07825); // move  $15, $31
+  write32<E>(Buf + 20, 0x0018c082); // srl   $24, $24, 2
+  write32<E>(Buf + 24, 0x0320f809); // jalr  $25
+  write32<E>(Buf + 28, 0x2718fffe); // subu  $24, $24, 2
+  uint64_t Got = Out<ELFT>::GotPlt->getVA();
+  writeMipsHi16<E>(Buf, Got);
+  writeMipsLo16<E>(Buf + 4, Got);
+  writeMipsLo16<E>(Buf + 8, Got);
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                                    uint64_t PltEntryAddr, int32_t Index,
+                                    unsigned RelOff) const {
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, 0x3c0f0000);      // lui   $15, %hi(.got.plt entry)
+  write32<E>(Buf + 4, 0x8df90000);  // l[wd] $25, %lo(.got.plt entry)($15)
+  write32<E>(Buf + 8, 0x03200008);  // jr    $25
+  write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
+  writeMipsHi16<E>(Buf, GotEntryAddr);
+  writeMipsLo16<E>(Buf + 4, GotEntryAddr);
+  writeMipsLo16<E>(Buf + 12, GotEntryAddr);
+}
+
+template <class ELFT>
+RelExpr MipsTargetInfo<ELFT>::getThunkExpr(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 Expr;
+  auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
+  if (!F)
+    return Expr;
+  // If current file has PIC code, LA25 stub is not required.
+  if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
+    return Expr;
+  auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
+  if (!D || !D->Section)
+    return Expr;
+  // LA25 is required if target file has PIC code
+  // or target symbol is a PIC symbol.
+  const ELFFile<ELFT> &DefFile = D->Section->getFile()->getObj();
+  bool PicFile = DefFile.getHeader()->e_flags & EF_MIPS_PIC;
+  bool PicSym = (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+  return (PicFile || PicSym) ? R_THUNK_ABS : Expr;
+}
+
+template <class ELFT>
+uint64_t MipsTargetInfo<ELFT>::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:
+    return read32<E>(Buf);
+  case R_MIPS_26:
+    // FIXME (simon): If the relocation target symbol is not a PLT entry
+    // we should use another expression for calculation:
+    // ((A << 2) | (P & 0xf0000000)) >> 2
+    return SignExtend64<28>(read32<E>(Buf) << 2);
+  case R_MIPS_GPREL16:
+  case R_MIPS_LO16:
+  case R_MIPS_PCLO16:
+  case R_MIPS_TLS_DTPREL_HI16:
+  case R_MIPS_TLS_DTPREL_LO16:
+  case R_MIPS_TLS_TPREL_HI16:
+  case R_MIPS_TLS_TPREL_LO16:
+    return SignExtend64<16>(read32<E>(Buf));
+  case R_MIPS_PC16:
+    return getPcRelocAddend<E, 16, 2>(Buf);
+  case R_MIPS_PC19_S2:
+    return getPcRelocAddend<E, 19, 2>(Buf);
+  case R_MIPS_PC21_S2:
+    return getPcRelocAddend<E, 21, 2>(Buf);
+  case R_MIPS_PC26_S2:
+    return getPcRelocAddend<E, 26, 2>(Buf);
+  case R_MIPS_PC32:
+    return getPcRelocAddend<E, 32, 0>(Buf);
+  }
+}
+
+static std::pair<uint32_t, uint64_t> calculateMips64RelChain(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.
+  // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+  // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+  // The first relocation is a 'real' relocation which is calculated
+  // using the corresponding symbol's value. The second and the third
+  // relocations used to modify result of the first one: extend it to
+  // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+  // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+  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("unsupported relocations combination " + Twine(Type));
+  return std::make_pair(Type & 0xff, Val);
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::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)
+    Val -= 0x8000;
+  else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16)
+    Val -= 0x7000;
+  if (ELFT::Is64Bits)
+    std::tie(Type, Val) = calculateMips64RelChain(Type, Val);
+  switch (Type) {
+  case R_MIPS_32:
+  case R_MIPS_GPREL32:
+    write32<E>(Loc, Val);
+    break;
+  case R_MIPS_64:
+    write64<E>(Loc, Val);
+    break;
+  case R_MIPS_26:
+    write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | (Val >> 2));
+    break;
+  case R_MIPS_GOT_DISP:
+  case R_MIPS_GOT_PAGE:
+  case R_MIPS_GOT16:
+  case R_MIPS_GPREL16:
+  case R_MIPS_TLS_GD:
+  case R_MIPS_TLS_LDM:
+    checkInt<16>(Val, Type);
+  // fallthrough
+  case R_MIPS_CALL16:
+  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<E>(Loc, Val);
+    break;
+  case R_MIPS_HI16:
+  case R_MIPS_PCHI16:
+  case R_MIPS_TLS_DTPREL_HI16:
+  case R_MIPS_TLS_TPREL_HI16:
+    writeMipsHi16<E>(Loc, Val);
+    break;
+  case R_MIPS_JALR:
+    // Ignore this optimization relocation for now
+    break;
+  case R_MIPS_PC16:
+    applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC19_S2:
+    applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC21_S2:
+    applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC26_S2:
+    applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC32:
+    applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
+    break;
+  default:
+    fatal("unrecognized reloc " + Twine(Type));
+  }
+}
+
+template <class ELFT>
+bool MipsTargetInfo<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
+  return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
+}
+}
+}
diff --git a/ELF/Target.h b/ELF/Target.h
new file mode 100644 (file)
index 0000000..d335c1e
--- /dev/null
@@ -0,0 +1,114 @@
+//===- Target.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_TARGET_H
+#define LLD_ELF_TARGET_H
+
+#include "InputSection.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+
+#include <memory>
+
+namespace lld {
+namespace elf {
+class InputFile;
+class SymbolBody;
+
+class TargetInfo {
+public:
+  virtual bool isTlsInitialExecRel(uint32_t Type) const;
+  virtual bool isTlsLocalDynamicRel(uint32_t Type) const;
+  virtual bool isTlsGlobalDynamicRel(uint32_t Type) const;
+  virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
+  virtual void writeGotPltHeader(uint8_t *Buf) const {}
+  virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
+  virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
+
+  // If lazy binding is supported, the first entry of the PLT has code
+  // to call the dynamic linker to resolve PLT entries the first time
+  // they are called. This function writes that code.
+  virtual void writePltHeader(uint8_t *Buf) const {}
+
+  virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                        uint64_t PltEntryAddr, int32_t Index,
+                        unsigned RelOff) const {}
+
+  // Returns true if a relocation only uses the low bits of a value such that
+  // all those bits are in in the same page. For example, if the relocation
+  // only uses the low 12 bits in a system with 4k pages. If this is true, the
+  // bits will always have the same value at runtime and we don't have to emit
+  // a dynamic relocation.
+  virtual bool usesOnlyLowPageBits(uint32_t Type) const;
+
+  // Decide whether a Thunk is needed for the relocation from File
+  // targeting S. Returns one of:
+  // Expr if there is no Thunk required
+  // R_THUNK_ABS if thunk is required and expression is absolute
+  // R_THUNK_PC if thunk is required and expression is pc rel
+  // R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel
+  virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
+                               const InputFile &File,
+                               const SymbolBody &S) const;
+  virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
+  virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
+  virtual ~TargetInfo();
+
+  unsigned TlsGdRelaxSkip = 1;
+  unsigned PageSize = 4096;
+
+  // On freebsd x86_64 the first page cannot be mmaped.
+  // On linux that is controled by vm.mmap_min_addr. At least on some x86_64
+  // installs that is 65536, so the first 15 pages cannot be used.
+  // Given that, the smallest value that can be used in here is 0x10000.
+  // If using 2MB pages, the smallest page aligned address that works is
+  // 0x200000, but it looks like every OS uses 4k pages for executables.
+  uint64_t DefaultImageBase = 0x10000;
+
+  uint32_t CopyRel;
+  uint32_t GotRel;
+  uint32_t PltRel;
+  uint32_t RelativeRel;
+  uint32_t IRelativeRel;
+  uint32_t TlsDescRel;
+  uint32_t TlsGotRel;
+  uint32_t TlsModuleIndexRel;
+  uint32_t TlsOffsetRel;
+  unsigned GotEntrySize;
+  unsigned GotPltEntrySize;
+  unsigned PltEntrySize;
+  unsigned PltHeaderSize;
+
+  // At least on x86_64 positions 1 and 2 are used by the first plt entry
+  // to support lazy loading.
+  unsigned GotPltHeaderEntriesNum = 3;
+
+  // Set to 0 for variant 2
+  unsigned TcbSize = 0;
+
+  virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                  RelExpr Expr) const;
+  virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
+  virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+};
+
+StringRef getRelName(uint32_t Type);
+uint64_t getPPC64TocBase();
+
+const unsigned MipsGPOffset = 0x7ff0;
+
+extern TargetInfo *Target;
+TargetInfo *createTarget();
+}
+}
+
+#endif
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
new file mode 100644 (file)
index 0000000..1ebbb17
--- /dev/null
@@ -0,0 +1,268 @@
+//===- Thunks.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains Thunk subclasses.
+//
+// A thunk is a small piece of code written after an input section
+// which is used to jump between "incompatible" functions
+// such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
+//
+// If a jump target is too far and its address doesn't fit to a
+// short jump instruction, we need to create a thunk too, but we
+// haven't supported it yet.
+//
+// i386 and x86-64 don't need thunks.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Thunks.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Support/Allocator.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+namespace lld {
+namespace elf {
+
+namespace {
+// Specific ARM Thunk implementations. The naming convention is:
+// Source State, TargetState, Target Requirement, ABS or PI, Range
+template <class ELFT>
+class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
+public:
+  ARMToThumbV7ABSLongThunk(const SymbolBody &Dest,
+                           const InputSection<ELFT> &Owner)
+      : Thunk<ELFT>(Dest, Owner) {}
+
+  uint32_t size() const override { return 12; }
+  void writeTo(uint8_t *Buf) const override;
+};
+
+template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
+public:
+  ARMToThumbV7PILongThunk(const SymbolBody &Dest,
+                          const InputSection<ELFT> &Owner)
+      : Thunk<ELFT>(Dest, Owner) {}
+
+  uint32_t size() const override { return 16; }
+  void writeTo(uint8_t *Buf) const override;
+};
+
+template <class ELFT>
+class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
+public:
+  ThumbToARMV7ABSLongThunk(const SymbolBody &Dest,
+                           const InputSection<ELFT> &Owner)
+      : Thunk<ELFT>(Dest, Owner) {}
+
+  uint32_t size() const override { return 10; }
+  void writeTo(uint8_t *Buf) const override;
+};
+
+template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
+public:
+  ThumbToARMV7PILongThunk(const SymbolBody &Dest,
+                          const InputSection<ELFT> &Owner)
+      : Thunk<ELFT>(Dest, Owner) {}
+
+  uint32_t size() const override { return 12; }
+  void writeTo(uint8_t *Buf) const override;
+};
+
+// MIPS LA25 thunk
+template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
+public:
+  MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner)
+      : Thunk<ELFT>(Dest, Owner) {}
+
+  uint32_t size() const override { return 16; }
+  void writeTo(uint8_t *Buf) const override;
+};
+} // anonymous namespace
+
+// ARM Target Thunks
+template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
+  return S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
+}
+
+template <class ELFT>
+void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+  const uint8_t Data[] = {
+      0x00, 0xc0, 0x00, 0xe3, // movw         ip,:lower16:S
+      0x00, 0xc0, 0x40, 0xe3, // movt         ip,:upper16:S
+      0x1c, 0xff, 0x2f, 0xe1, // bx   ip
+  };
+  uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
+  Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
+}
+
+template <class ELFT>
+void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+  const uint8_t Data[] = {
+      0x40, 0xf2, 0x00, 0x0c, // movw         ip, :lower16:S
+      0xc0, 0xf2, 0x00, 0x0c, // movt         ip, :upper16:S
+      0x60, 0x47,             // bx   ip
+  };
+  uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
+  Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
+}
+
+template <class ELFT>
+void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+  const uint8_t Data[] = {
+      0xf0, 0xcf, 0x0f, 0xe3, // P:  movw ip,:lower16:S - (P + (L1-P) +8)
+      0x00, 0xc0, 0x40, 0xe3, //     movt ip,:upper16:S - (P + (L1-P+4) +8)
+      0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+      0x1c, 0xff, 0x2f, 0xe1, //     bx r12
+  };
+  uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+  uint64_t P = this->getVA();
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
+  Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
+}
+
+template <class ELFT>
+void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+  const uint8_t Data[] = {
+      0x4f, 0xf6, 0xf4, 0x7c, // P:  movw ip,:lower16:S - (P + (L1-P) + 4)
+      0xc0, 0xf2, 0x00, 0x0c, //     movt ip,:upper16:S - (P + (L1-P+4) + 4)
+      0xfc, 0x44,             // L1: add  r12, pc
+      0x60, 0x47,             //     bx   r12
+  };
+  uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+  uint64_t P = this->getVA();
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
+  Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
+}
+
+// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
+template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
+  const endianness E = ELFT::TargetEndianness;
+
+  uint64_t S = this->Destination.template getVA<ELFT>();
+  write32<E>(Buf, 0x3c190000);                // lui   $25, %hi(func)
+  write32<E>(Buf + 4, 0x08000000 | (S >> 2)); // j     func
+  write32<E>(Buf + 8, 0x27390000);            // addiu $25, $25, %lo(func)
+  write32<E>(Buf + 12, 0x00000000);           // nop
+  Target->relocateOne(Buf, R_MIPS_HI16, S);
+  Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
+}
+
+template <class ELFT>
+Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
+    : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
+
+template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
+  return Owner.OutSec->getVA() + Owner.OutSecOff + Offset;
+}
+
+template <class ELFT> Thunk<ELFT>::~Thunk() {}
+
+// Creates a thunk for Thumb-ARM interworking.
+template <class ELFT>
+static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
+                                   InputSection<ELFT> &IS) {
+  // ARM relocations need ARM to Thumb interworking Thunks.
+  // Thumb relocations need Thumb to ARM relocations.
+  // Use position independent Thunks if we require position independent code.
+  BumpPtrAllocator &Alloc = IS.getFile()->Alloc;
+  switch (Reloc) {
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_JUMP24:
+    if (Config->Pic)
+      return new (Alloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
+    return new (Alloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+    if (Config->Pic)
+      return new (Alloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
+    return new (Alloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
+  }
+  fatal("unrecognized relocation type");
+}
+
+template <class ELFT>
+static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
+  // Only one Thunk supported per symbol.
+  if (S.hasThunk<ELFT>())
+    return;
+
+  // ARM Thunks are added to the same InputSection as the relocation. This
+  // isn't strictly necessary but it makes it more likely that a limited range
+  // branch can reach the Thunk, and it makes Thunks to the PLT section easier
+  Thunk<ELFT> *T = createThunkArm(Reloc, S, IS);
+  IS.addThunk(T);
+  if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S))
+    Sym->ThunkData = T;
+  else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
+    Sym->ThunkData = T;
+  else
+    fatal("symbol not DefinedRegular or Shared");
+}
+
+template <class ELFT>
+static void addThunkMips(uint32_t RelocType, SymbolBody &S,
+                         InputSection<ELFT> &IS) {
+  // Only one Thunk supported per symbol.
+  if (S.hasThunk<ELFT>())
+    return;
+
+  // Mips Thunks are added to the InputSection defining S.
+  auto *R = cast<DefinedRegular<ELFT>>(&S);
+  auto *Sec = cast<InputSection<ELFT>>(R->Section);
+  auto *T = new (IS.getFile()->Alloc) MipsThunk<ELFT>(S, *Sec);
+  Sec->addThunk(T);
+  R->ThunkData = T;
+}
+
+template <class ELFT>
+void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
+  if (Config->EMachine == EM_ARM)
+    addThunkARM<ELFT>(RelocType, S, IS);
+  else if (Config->EMachine == EM_MIPS)
+    addThunkMips<ELFT>(RelocType, S, IS);
+  else
+    llvm_unreachable("add Thunk only supported for ARM and Mips");
+}
+
+template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
+                                InputSection<ELF32LE> &);
+template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
+                                InputSection<ELF32BE> &);
+template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
+                                InputSection<ELF64LE> &);
+template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
+                                InputSection<ELF64BE> &);
+
+template class Thunk<ELF32LE>;
+template class Thunk<ELF32BE>;
+template class Thunk<ELF64LE>;
+template class Thunk<ELF64BE>;
+
+} // namespace elf
+} // namespace lld
diff --git a/ELF/Thunks.h b/ELF/Thunks.h
new file mode 100644 (file)
index 0000000..b937d79
--- /dev/null
@@ -0,0 +1,56 @@
+//===- Thunks.h --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_THUNKS_H
+#define LLD_ELF_THUNKS_H
+
+#include "Relocations.h"
+
+namespace lld {
+namespace elf {
+class SymbolBody;
+template <class ELFT> class InputSection;
+
+// Class to describe an instance of a Thunk.
+// A Thunk is a code-sequence inserted by the linker in between a caller and
+// the callee. The relocation to the callee is redirected to the Thunk, which
+// after executing transfers control to the callee. Typical uses of Thunks
+// include transferring control from non-pi to pi and changing state on
+// targets like ARM.
+//
+// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk
+// is stored in a field of the Symbol Destination.
+// Thunks to be written to an InputSection are recorded by the InputSection.
+template <class ELFT> class Thunk {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
+  virtual ~Thunk();
+
+  virtual uint32_t size() const { return 0; }
+  virtual void writeTo(uint8_t *Buf) const {}
+  uintX_t getVA() const;
+
+protected:
+  const SymbolBody &Destination;
+  const InputSection<ELFT> &Owner;
+  uint64_t Offset;
+};
+
+// For a Relocation to symbol S from InputSection Src, create a Thunk and
+// update the fields of S and the InputSection that the Thunk body will be
+// written to. At present there are implementations for ARM and Mips Thunks.
+template <class ELFT>
+void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
new file mode 100644 (file)
index 0000000..387bec3
--- /dev/null
@@ -0,0 +1,1283 @@
+//===- 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 "LinkerScript.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Target.h"
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+// The writer writes a SymbolTable result to a file.
+template <class ELFT> class Writer {
+public:
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Ehdr Elf_Ehdr;
+  typedef typename ELFT::Phdr Elf_Phdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::Rela Elf_Rela;
+  Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
+  void run();
+
+private:
+  // This describes a program header entry.
+  // Each contains type, access flags and range of output sections that will be
+  // placed in it.
+  struct Phdr {
+    Phdr(unsigned Type, unsigned Flags) {
+      H.p_type = Type;
+      H.p_flags = Flags;
+    }
+    Elf_Phdr H = {};
+    OutputSectionBase<ELFT> *First = nullptr;
+    OutputSectionBase<ELFT> *Last = nullptr;
+  };
+
+  void copyLocalSymbols();
+  void addReservedSymbols();
+  void createSections();
+  void addPredefinedSections();
+  bool needsGot();
+
+  void createPhdrs();
+  void assignAddresses();
+  void assignFileOffsets();
+  void setPhdrs();
+  void fixHeaders();
+  void fixSectionAlignments();
+  void fixAbsoluteSymbols();
+  void openFile();
+  void writeHeader();
+  void writeSections();
+  void writeBuildId();
+  bool needsInterpSection() const {
+    return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
+  }
+  bool isOutputDynamic() const {
+    return !Symtab.getSharedFiles().empty() || Config->Pic;
+  }
+
+  void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
+
+  std::unique_ptr<FileOutputBuffer> Buffer;
+
+  BumpPtrAllocator Alloc;
+  std::vector<OutputSectionBase<ELFT> *> OutputSections;
+  std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
+
+  void addRelIpltSymbols();
+  void addStartEndSymbols();
+  void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
+
+  SymbolTable<ELFT> &Symtab;
+  std::vector<Phdr> Phdrs;
+
+  uintX_t FileSize;
+  uintX_t SectionHeaderOff;
+};
+} // anonymous namespace
+
+template <class ELFT>
+StringRef elf::getOutputSectionName(InputSectionBase<ELFT> *S) {
+  StringRef Dest = Script<ELFT>::X->getOutputSection(S);
+  if (!Dest.empty())
+    return Dest;
+
+  StringRef Name = S->getSectionName();
+  for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
+                      ".init_array.", ".fini_array.", ".ctors.", ".dtors.",
+                      ".tbss.", ".gcc_except_table.", ".tdata."})
+    if (Name.startswith(V))
+      return V.drop_back();
+  return Name;
+}
+
+template <class ELFT>
+void elf::reportDiscarded(InputSectionBase<ELFT> *IS,
+                          const std::unique_ptr<elf::ObjectFile<ELFT>> &File) {
+  if (!Config->PrintGcSections || !IS || IS->Live)
+    return;
+  errs() << "removing unused section from '" << IS->getSectionName()
+         << "' in file '" << File->getName() << "'\n";
+}
+
+template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Ehdr Elf_Ehdr;
+
+  // Create singleton output sections.
+  OutputSection<ELFT> Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+  DynamicSection<ELFT> Dynamic;
+  EhOutputSection<ELFT> EhFrame;
+  GotSection<ELFT> Got;
+  InterpSection<ELFT> Interp;
+  PltSection<ELFT> Plt;
+  RelocationSection<ELFT> RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn",
+                                  Config->ZCombreloc);
+  StringTableSection<ELFT> DynStrTab(".dynstr", true);
+  StringTableSection<ELFT> ShStrTab(".shstrtab", false);
+  SymbolTableSection<ELFT> DynSymTab(DynStrTab);
+  VersionTableSection<ELFT> VerSym;
+  VersionNeedSection<ELFT> VerNeed;
+
+  OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
+  ElfHeader.setSize(sizeof(Elf_Ehdr));
+  OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC);
+  ProgramHeaders.updateAlignment(sizeof(uintX_t));
+
+  // Instantiate optional output sections if they are needed.
+  std::unique_ptr<BuildIdSection<ELFT>> BuildId;
+  std::unique_ptr<EhFrameHeader<ELFT>> EhFrameHdr;
+  std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
+  std::unique_ptr<GotPltSection<ELFT>> GotPlt;
+  std::unique_ptr<HashTableSection<ELFT>> HashTab;
+  std::unique_ptr<RelocationSection<ELFT>> RelaPlt;
+  std::unique_ptr<StringTableSection<ELFT>> StrTab;
+  std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
+  std::unique_ptr<OutputSection<ELFT>> MipsRldMap;
+  std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef;
+
+  if (Config->BuildId == BuildIdKind::Fnv1)
+    BuildId.reset(new BuildIdFnv1<ELFT>);
+  else if (Config->BuildId == BuildIdKind::Md5)
+    BuildId.reset(new BuildIdMd5<ELFT>);
+  else if (Config->BuildId == BuildIdKind::Sha1)
+    BuildId.reset(new BuildIdSha1<ELFT>);
+  else if (Config->BuildId == BuildIdKind::Hexstring)
+    BuildId.reset(new BuildIdHexstring<ELFT>);
+
+  if (Config->EhFrameHdr)
+    EhFrameHdr.reset(new EhFrameHeader<ELFT>);
+
+  if (Config->GnuHash)
+    GnuHashTab.reset(new GnuHashTableSection<ELFT>);
+  if (Config->SysvHash)
+    HashTab.reset(new HashTableSection<ELFT>);
+  StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt";
+  GotPlt.reset(new GotPltSection<ELFT>);
+  RelaPlt.reset(new RelocationSection<ELFT>(S, false /*Sort*/));
+  if (!Config->StripAll) {
+    StrTab.reset(new StringTableSection<ELFT>(".strtab", false));
+    SymTabSec.reset(new SymbolTableSection<ELFT>(*StrTab));
+  }
+  if (Config->EMachine == EM_MIPS && !Config->Shared) {
+    // This is a MIPS specific section to hold a space within the data segment
+    // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+    // See "Dynamic section" in Chapter 5 in the following document:
+    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+    MipsRldMap.reset(new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
+                                             SHF_ALLOC | SHF_WRITE));
+    MipsRldMap->setSize(sizeof(uintX_t));
+    MipsRldMap->updateAlignment(sizeof(uintX_t));
+  }
+  if (!Config->VersionDefinitions.empty())
+    VerDef.reset(new VersionDefinitionSection<ELFT>());
+
+  Out<ELFT>::Bss = &Bss;
+  Out<ELFT>::BuildId = BuildId.get();
+  Out<ELFT>::DynStrTab = &DynStrTab;
+  Out<ELFT>::DynSymTab = &DynSymTab;
+  Out<ELFT>::Dynamic = &Dynamic;
+  Out<ELFT>::EhFrame = &EhFrame;
+  Out<ELFT>::EhFrameHdr = EhFrameHdr.get();
+  Out<ELFT>::GnuHashTab = GnuHashTab.get();
+  Out<ELFT>::Got = &Got;
+  Out<ELFT>::GotPlt = GotPlt.get();
+  Out<ELFT>::HashTab = HashTab.get();
+  Out<ELFT>::Interp = &Interp;
+  Out<ELFT>::Plt = &Plt;
+  Out<ELFT>::RelaDyn = &RelaDyn;
+  Out<ELFT>::RelaPlt = RelaPlt.get();
+  Out<ELFT>::ShStrTab = &ShStrTab;
+  Out<ELFT>::StrTab = StrTab.get();
+  Out<ELFT>::SymTab = SymTabSec.get();
+  Out<ELFT>::VerDef = VerDef.get();
+  Out<ELFT>::VerSym = &VerSym;
+  Out<ELFT>::VerNeed = &VerNeed;
+  Out<ELFT>::MipsRldMap = MipsRldMap.get();
+  Out<ELFT>::Opd = nullptr;
+  Out<ELFT>::OpdBuf = nullptr;
+  Out<ELFT>::TlsPhdr = nullptr;
+  Out<ELFT>::ElfHeader = &ElfHeader;
+  Out<ELFT>::ProgramHeaders = &ProgramHeaders;
+
+  Writer<ELFT>(*Symtab).run();
+}
+
+// The main function of the writer.
+template <class ELFT> void Writer<ELFT>::run() {
+  if (!Config->DiscardAll)
+    copyLocalSymbols();
+  addReservedSymbols();
+  createSections();
+  if (HasError)
+    return;
+
+  if (Config->Relocatable) {
+    assignFileOffsets();
+  } else {
+    createPhdrs();
+    fixHeaders();
+    if (ScriptConfig->DoLayout) {
+      Script<ELFT>::X->assignAddresses(OutputSections);
+    } else {
+      fixSectionAlignments();
+      assignAddresses();
+    }
+    assignFileOffsets();
+    setPhdrs();
+    fixAbsoluteSymbols();
+  }
+
+  openFile();
+  if (HasError)
+    return;
+  writeHeader();
+  writeSections();
+  writeBuildId();
+  if (HasError)
+    return;
+  if (auto EC = Buffer->commit())
+    error(EC, "failed to write to the output file");
+}
+
+template <class ELFT>
+static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
+  if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+    return;
+
+  if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT &&
+      Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
+    return;
+
+  std::string Msg = "undefined symbol: " + Sym->getName().str();
+  if (Sym->File)
+    Msg += " in " + getFilename(Sym->File);
+  if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
+    warning(Msg);
+  else
+    error(Msg);
+}
+
+template <class ELFT>
+static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
+                               const SymbolBody &B) {
+  if (B.isFile())
+    return false;
+
+  // We keep sections in symtab for relocatable output.
+  if (B.isSection())
+    return Config->Relocatable;
+
+  // If sym references a section in a discarded group, don't keep it.
+  if (Sec == &InputSection<ELFT>::Discarded)
+    return false;
+
+  if (Config->DiscardNone)
+    return true;
+
+  // In ELF assembly .L symbols are normally discarded by the assembler.
+  // If the assembler fails to do so, the linker discards them if
+  // * --discard-locals is used.
+  // * The symbol is in a SHF_MERGE section, which is normally the reason for
+  //   the assembler keeping the .L symbol.
+  if (!SymName.startswith(".L") && !SymName.empty())
+    return true;
+
+  if (Config->DiscardLocals)
+    return false;
+
+  return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
+}
+
+template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
+  if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
+    return false;
+
+  if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
+    // Always include absolute symbols.
+    if (!D->Section)
+      return true;
+    // Exclude symbols pointing to garbage-collected sections.
+    if (!D->Section->Live)
+      return false;
+    if (auto *S = dyn_cast<MergeInputSection<ELFT>>(D->Section))
+      if (!S->getSectionPiece(D->Value)->Live)
+        return false;
+  }
+  return true;
+}
+
+// Local symbols are not in the linker's symbol table. This function scans
+// each object file's symbol table to copy local symbols to the output.
+template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
+  if (!Out<ELFT>::SymTab)
+    return;
+  for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+       Symtab.getObjectFiles()) {
+    const char *StrTab = F->getStringTable().data();
+    for (SymbolBody *B : F->getLocalSymbols()) {
+      auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+      // No reason to keep local undefined symbol in symtab.
+      if (!DR)
+        continue;
+      if (!includeInSymtab<ELFT>(*B))
+        continue;
+      StringRef SymName(StrTab + B->getNameOffset());
+      InputSectionBase<ELFT> *Sec = DR->Section;
+      if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
+        continue;
+      ++Out<ELFT>::SymTab->NumLocals;
+      if (Config->Relocatable)
+        B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
+      F->KeptLocalSyms.push_back(
+          std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
+    }
+  }
+}
+
+// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
+// we would like to make sure appear is a specific order to maximize their
+// coverage by a single signed 16-bit offset from the TOC base pointer.
+// Conversely, the special .tocbss section should be first among all SHT_NOBITS
+// sections. This will put it next to the loaded special PPC64 sections (and,
+// thus, within reach of the TOC base pointer).
+static int getPPC64SectionRank(StringRef SectionName) {
+  return StringSwitch<int>(SectionName)
+      .Case(".tocbss", 0)
+      .Case(".branch_lt", 2)
+      .Case(".toc", 3)
+      .Case(".toc1", 4)
+      .Case(".opd", 5)
+      .Default(1);
+}
+
+template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
+  if (!Config->ZRelro)
+    return false;
+  typename ELFT::uint Flags = Sec->getFlags();
+  if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
+    return false;
+  if (Flags & SHF_TLS)
+    return true;
+  uint32_t Type = Sec->getType();
+  if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
+      Type == SHT_PREINIT_ARRAY)
+    return true;
+  if (Sec == Out<ELFT>::GotPlt)
+    return Config->ZNow;
+  if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
+    return true;
+  StringRef S = Sec->getName();
+  return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
+         S == ".eh_frame";
+}
+
+// Output section ordering is determined by this function.
+template <class ELFT>
+static bool compareSections(OutputSectionBase<ELFT> *A,
+                            OutputSectionBase<ELFT> *B) {
+  typedef typename ELFT::uint uintX_t;
+
+  int Comp = Script<ELFT>::X->compareSections(A->getName(), B->getName());
+  if (Comp != 0)
+    return Comp < 0;
+
+  uintX_t AFlags = A->getFlags();
+  uintX_t BFlags = B->getFlags();
+
+  // Allocatable sections go first to reduce the total PT_LOAD size and
+  // so debug info doesn't change addresses in actual code.
+  bool AIsAlloc = AFlags & SHF_ALLOC;
+  bool BIsAlloc = BFlags & SHF_ALLOC;
+  if (AIsAlloc != BIsAlloc)
+    return AIsAlloc;
+
+  // We don't have any special requirements for the relative order of
+  // two non allocatable sections.
+  if (!AIsAlloc)
+    return false;
+
+  // We want the read only sections first so that they go in the PT_LOAD
+  // covering the program headers at the start of the file.
+  bool AIsWritable = AFlags & SHF_WRITE;
+  bool BIsWritable = BFlags & SHF_WRITE;
+  if (AIsWritable != BIsWritable)
+    return BIsWritable;
+
+  // For a corresponding reason, put non exec sections first (the program
+  // header PT_LOAD is not executable).
+  bool AIsExec = AFlags & SHF_EXECINSTR;
+  bool BIsExec = BFlags & SHF_EXECINSTR;
+  if (AIsExec != BIsExec)
+    return BIsExec;
+
+  // If we got here we know that both A and B are in the same PT_LOAD.
+
+  // The TLS initialization block needs to be a single contiguous block in a R/W
+  // PT_LOAD, so stick TLS sections directly before R/W sections. The TLS NOBITS
+  // sections are placed here as they don't take up virtual address space in the
+  // PT_LOAD.
+  bool AIsTls = AFlags & SHF_TLS;
+  bool BIsTls = BFlags & SHF_TLS;
+  if (AIsTls != BIsTls)
+    return AIsTls;
+
+  // The next requirement we have is to put nobits sections last. The
+  // reason is that the only thing the dynamic linker will see about
+  // them is a p_memsz that is larger than p_filesz. Seeing that it
+  // zeros the end of the PT_LOAD, so that has to correspond to the
+  // nobits sections.
+  bool AIsNoBits = A->getType() == SHT_NOBITS;
+  bool BIsNoBits = B->getType() == SHT_NOBITS;
+  if (AIsNoBits != BIsNoBits)
+    return BIsNoBits;
+
+  // We place RelRo section before plain r/w ones.
+  bool AIsRelRo = isRelroSection(A);
+  bool BIsRelRo = isRelroSection(B);
+  if (AIsRelRo != BIsRelRo)
+    return AIsRelRo;
+
+  // Some architectures have additional ordering restrictions for sections
+  // within the same PT_LOAD.
+  if (Config->EMachine == EM_PPC64)
+    return getPPC64SectionRank(A->getName()) <
+           getPPC64SectionRank(B->getName());
+
+  return false;
+}
+
+// Until this function is called, common symbols do not belong to any section.
+// This function adds them to end of BSS section.
+template <class ELFT>
+void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
+  if (Syms.empty())
+    return;
+
+  // Sort the common symbols by alignment as an heuristic to pack them better.
+  std::stable_sort(Syms.begin(), Syms.end(),
+                   [](const DefinedCommon *A, const DefinedCommon *B) {
+                     return A->Alignment > B->Alignment;
+                   });
+
+  uintX_t Off = Out<ELFT>::Bss->getSize();
+  for (DefinedCommon *C : Syms) {
+    Off = alignTo(Off, C->Alignment);
+    Out<ELFT>::Bss->updateAlignment(C->Alignment);
+    C->OffsetInBss = Off;
+    Off += C->Size;
+  }
+
+  Out<ELFT>::Bss->setSize(Off);
+}
+
+template <class ELFT>
+static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
+                                    OutputSectionBase<ELFT> *Sec,
+                                    typename ELFT::uint Val) {
+  SymbolBody *S = Table.find(Name);
+  if (!S)
+    return nullptr;
+  if (!S->isUndefined() && !S->isShared())
+    return S->symbol();
+  return Table.addSynthetic(Name, Sec, Val);
+}
+
+// The beginning and the ending of .rel[a].plt section are marked
+// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
+// executable. The runtime needs these symbols in order to resolve
+// all IRELATIVE relocs on startup. For dynamic executables, we don't
+// need these symbols, since IRELATIVE relocs are resolved through GOT
+// and PLT. For details, see http://www.airs.com/blog/archives/403.
+template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
+  if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
+    return;
+  StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
+  addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0);
+
+  S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
+  addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt,
+                       DefinedSynthetic<ELFT>::SectionEnd);
+}
+
+// The linker is expected to define some symbols depending on
+// the linking result. This function defines such symbols.
+template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
+  if (Config->EMachine == EM_MIPS) {
+    // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
+    // so that it points to an absolute address which is relative to GOT.
+    // See "Global Data Symbols" in Chapter 6 in the following document:
+    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+    Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset);
+
+    // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+    // start of function and 'gp' pointer into GOT.
+    Symbol *Sym =
+        addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset);
+    if (Sym)
+      ElfSym<ELFT>::MipsGpDisp = Sym->body();
+
+    // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
+    // pointer. This symbol is used in the code generated by .cpload pseudo-op
+    // in case of using -mno-shared option.
+    // https://sourceware.org/ml/binutils/2004-12/msg00094.html
+    addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got,
+                         MipsGPOffset);
+  }
+
+  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
+  // is magical and is used to produce a R_386_GOTPC relocation.
+  // The R_386_GOTPC relocation value doesn't actually depend on the
+  // symbol value, so it could use an index of STN_UNDEF which, according
+  // to the spec, means the symbol value is 0.
+  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
+  // the object file.
+  // The situation is even stranger on x86_64 where the assembly doesn't
+  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
+  // an undefined symbol in the .o files.
+  // Given that the symbol is effectively unused, we just create a dummy
+  // hidden one to avoid the undefined symbol error.
+  if (!Config->Relocatable)
+    Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
+
+  // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
+  // static linking the linker is required to optimize away any references to
+  // __tls_get_addr, so it's not defined anywhere. Create a hidden definition
+  // to avoid the undefined symbol error.
+  if (!isOutputDynamic())
+    Symtab.addIgnored("__tls_get_addr");
+
+  auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
+                       DefinedRegular<ELFT> *&Sym2) {
+    Sym1 = Symtab.addIgnored(S, STV_DEFAULT);
+
+    // The name without the underscore is not a reserved name,
+    // so it is defined only when there is a reference against it.
+    assert(S.startswith("_"));
+    S = S.substr(1);
+    if (SymbolBody *B = Symtab.find(S))
+      if (B->isUndefined())
+        Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
+  };
+
+  Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
+  Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
+  Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
+}
+
+// Sort input sections by section name suffixes for
+// __attribute__((init_priority(N))).
+template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
+  if (S)
+    reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
+}
+
+// Sort input sections by the special rule for .ctors and .dtors.
+template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
+  if (S)
+    reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
+}
+
+// Create output section objects and add them to OutputSections.
+template <class ELFT> void Writer<ELFT>::createSections() {
+  // Create output sections for input object file sections.
+  std::vector<OutputSectionBase<ELFT> *> RegularSections;
+  OutputSectionFactory<ELFT> Factory;
+  for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+       Symtab.getObjectFiles()) {
+    for (InputSectionBase<ELFT> *C : F->getSections()) {
+      if (isDiscarded(C)) {
+        reportDiscarded(C, F);
+        continue;
+      }
+      OutputSectionBase<ELFT> *Sec;
+      bool IsNew;
+      std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
+      if (IsNew) {
+        OwningSections.emplace_back(Sec);
+        OutputSections.push_back(Sec);
+        RegularSections.push_back(Sec);
+      }
+      Sec->addSection(C);
+    }
+  }
+
+  // If we have a .opd section (used under PPC64 for function descriptors),
+  // store a pointer to it here so that we can use it later when processing
+  // relocations.
+  Out<ELFT>::Opd = Factory.lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC);
+
+  Out<ELFT>::Dynamic->PreInitArraySec = Factory.lookup(
+      ".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC);
+  Out<ELFT>::Dynamic->InitArraySec =
+      Factory.lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC);
+  Out<ELFT>::Dynamic->FiniArraySec =
+      Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
+
+  // Sort section contents for __attribute__((init_priority(N)).
+  sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
+  sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
+  sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+  sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+
+  // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
+  // symbols for sections, so that the runtime can get the start and end
+  // addresses of each section by section name. Add such symbols.
+  if (!Config->Relocatable) {
+    addStartEndSymbols();
+    for (OutputSectionBase<ELFT> *Sec : RegularSections)
+      addStartStopSymbols(Sec);
+  }
+
+  // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
+  // It should be okay as no one seems to care about the type.
+  // Even the author of gold doesn't remember why gold behaves that way.
+  // https://sourceware.org/ml/binutils/2002-03/msg00360.html
+  if (isOutputDynamic())
+    Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0);
+
+  // Define __rel[a]_iplt_{start,end} symbols if needed.
+  addRelIpltSymbols();
+
+  // Add scripted symbols with zero values now.
+  // Real values will be assigned later
+  Script<ELFT>::X->addScriptedSymbols();
+
+  if (!Out<ELFT>::EhFrame->empty()) {
+    OutputSections.push_back(Out<ELFT>::EhFrame);
+    Out<ELFT>::EhFrame->finalize();
+  }
+
+  // Scan relocations. This must be done after every symbol is declared so that
+  // we can correctly decide if a dynamic relocation is needed.
+  for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+       Symtab.getObjectFiles()) {
+    for (InputSectionBase<ELFT> *C : F->getSections()) {
+      if (isDiscarded(C))
+        continue;
+      if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
+        scanRelocations(*S);
+        continue;
+      }
+      if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
+        if (S->RelocSection)
+          scanRelocations(*S, *S->RelocSection);
+    }
+  }
+
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    Sec->assignOffsets();
+
+  // Now that we have defined all possible symbols including linker-
+  // synthesized ones. Visit all symbols to give the finishing touches.
+  std::vector<DefinedCommon *> CommonSymbols;
+  for (Symbol *S : Symtab.getSymbols()) {
+    SymbolBody *Body = S->body();
+
+    // We only report undefined symbols in regular objects. This means that we
+    // will accept an undefined reference in bitcode if it can be optimized out.
+    if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak())
+      reportUndefined<ELFT>(Symtab, Body);
+
+    if (auto *C = dyn_cast<DefinedCommon>(Body))
+      CommonSymbols.push_back(C);
+
+    if (!includeInSymtab<ELFT>(*Body))
+      continue;
+    if (Out<ELFT>::SymTab)
+      Out<ELFT>::SymTab->addSymbol(Body);
+
+    if (isOutputDynamic() && S->includeInDynsym()) {
+      Out<ELFT>::DynSymTab->addSymbol(Body);
+      if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
+        if (SS->file()->isNeeded())
+          Out<ELFT>::VerNeed->addSymbol(SS);
+    }
+  }
+
+  // Do not proceed if there was an undefined symbol.
+  if (HasError)
+    return;
+
+  addCommonSymbols(CommonSymbols);
+
+  // So far we have added sections from input object files.
+  // This function adds linker-created Out<ELFT>::* sections.
+  addPredefinedSections();
+
+  std::stable_sort(OutputSections.begin(), OutputSections.end(),
+                   compareSections<ELFT>);
+
+  unsigned I = 1;
+  for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+    Sec->SectionIndex = I++;
+    Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
+  }
+
+  // Finalizers fix each section's size.
+  // .dynsym is finalized early since that may fill up .gnu.hash.
+  if (isOutputDynamic())
+    Out<ELFT>::DynSymTab->finalize();
+
+  // Fill other section headers. The dynamic table is finalized
+  // at the end because some tags like RELSZ depend on result
+  // of finalizing other sections. The dynamic string table is
+  // finalized once the .dynamic finalizer has added a few last
+  // strings. See DynamicSection::finalize()
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic)
+      Sec->finalize();
+
+  if (isOutputDynamic())
+    Out<ELFT>::Dynamic->finalize();
+
+  // Now that all output offsets are fixed. Finalize mergeable sections
+  // to fix their maps from input offsets to output offsets.
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    Sec->finalizePieces();
+}
+
+template <class ELFT> bool Writer<ELFT>::needsGot() {
+  if (!Out<ELFT>::Got->empty())
+    return true;
+
+  // We add the .got section to the result for dynamic MIPS target because
+  // its address and properties are mentioned in the .dynamic section.
+  if (Config->EMachine == EM_MIPS)
+    return true;
+
+  // If we have a relocation that is relative to GOT (such as GOTOFFREL),
+  // we need to emit a GOT even if it's empty.
+  return Out<ELFT>::Got->HasGotOffRel;
+}
+
+// This function add Out<ELFT>::* sections to OutputSections.
+template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
+  auto Add = [&](OutputSectionBase<ELFT> *C) {
+    if (C)
+      OutputSections.push_back(C);
+  };
+
+  // A core file does not usually contain unmodified segments except
+  // the first page of the executable. Add the build ID section to beginning of
+  // the file so that the section is included in the first page.
+  if (Out<ELFT>::BuildId)
+    OutputSections.insert(OutputSections.begin(), Out<ELFT>::BuildId);
+
+  // Add .interp at first because some loaders want to see that section
+  // on the first page of the executable file when loaded into memory.
+  if (needsInterpSection())
+    OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp);
+
+  // This order is not the same as the final output order
+  // because we sort the sections using their attributes below.
+  Add(Out<ELFT>::SymTab);
+  Add(Out<ELFT>::ShStrTab);
+  Add(Out<ELFT>::StrTab);
+  if (isOutputDynamic()) {
+    Add(Out<ELFT>::DynSymTab);
+
+    bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
+    if (Out<ELFT>::VerDef || HasVerNeed)
+      Add(Out<ELFT>::VerSym);
+    Add(Out<ELFT>::VerDef);
+    if (HasVerNeed)
+      Add(Out<ELFT>::VerNeed);
+
+    Add(Out<ELFT>::GnuHashTab);
+    Add(Out<ELFT>::HashTab);
+    Add(Out<ELFT>::Dynamic);
+    Add(Out<ELFT>::DynStrTab);
+    if (Out<ELFT>::RelaDyn->hasRelocs())
+      Add(Out<ELFT>::RelaDyn);
+    Add(Out<ELFT>::MipsRldMap);
+  }
+
+  // We always need to add rel[a].plt to output if it has entries.
+  // Even during static linking it can contain R_[*]_IRELATIVE relocations.
+  if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
+    Add(Out<ELFT>::RelaPlt);
+    Out<ELFT>::RelaPlt->Static = !isOutputDynamic();
+  }
+
+  if (needsGot())
+    Add(Out<ELFT>::Got);
+  if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty())
+    Add(Out<ELFT>::GotPlt);
+  if (!Out<ELFT>::Plt->empty())
+    Add(Out<ELFT>::Plt);
+  if (!Out<ELFT>::EhFrame->empty())
+    Add(Out<ELFT>::EhFrameHdr);
+  if (Out<ELFT>::Bss->getSize() > 0)
+    Add(Out<ELFT>::Bss);
+}
+
+// The linker is expected to define SECNAME_start and SECNAME_end
+// symbols for a few sections. This function defines them.
+template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
+  auto Define = [&](StringRef Start, StringRef End,
+                    OutputSectionBase<ELFT> *OS) {
+    if (OS) {
+      this->Symtab.addSynthetic(Start, OS, 0);
+      this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd);
+    } else {
+      addOptionalSynthetic(this->Symtab, Start,
+                           (OutputSectionBase<ELFT> *)nullptr, 0);
+      addOptionalSynthetic(this->Symtab, End,
+                           (OutputSectionBase<ELFT> *)nullptr, 0);
+    }
+  };
+
+  Define("__preinit_array_start", "__preinit_array_end",
+         Out<ELFT>::Dynamic->PreInitArraySec);
+  Define("__init_array_start", "__init_array_end",
+         Out<ELFT>::Dynamic->InitArraySec);
+  Define("__fini_array_start", "__fini_array_end",
+         Out<ELFT>::Dynamic->FiniArraySec);
+}
+
+// If a section name is valid as a C identifier (which is rare because of
+// the leading '.'), linkers are expected to define __start_<secname> and
+// __stop_<secname> symbols. They are at beginning and end of the section,
+// respectively. This is not requested by the ELF standard, but GNU ld and
+// gold provide the feature, and used by many programs.
+template <class ELFT>
+void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
+  StringRef S = Sec->getName();
+  if (!isValidCIdentifier(S))
+    return;
+  StringSaver Saver(Alloc);
+  StringRef Start = Saver.save("__start_" + S);
+  StringRef Stop = Saver.save("__stop_" + S);
+  if (SymbolBody *B = Symtab.find(Start))
+    if (B->isUndefined())
+      Symtab.addSynthetic(Start, Sec, 0);
+  if (SymbolBody *B = Symtab.find(Stop))
+    if (B->isUndefined())
+      Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd);
+}
+
+template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
+  if (!(Sec->getFlags() & SHF_ALLOC))
+    return false;
+
+  // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
+  // responsible for allocating space for them, not the PT_LOAD that
+  // contains the TLS initialization image.
+  if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS)
+    return false;
+  return true;
+}
+
+static uint32_t toPhdrFlags(uint64_t Flags) {
+  uint32_t Ret = PF_R;
+  if (Flags & SHF_WRITE)
+    Ret |= PF_W;
+  if (Flags & SHF_EXECINSTR)
+    Ret |= PF_X;
+  return Ret;
+}
+
+// Decide which program headers to create and which sections to include in each
+// one.
+template <class ELFT> void Writer<ELFT>::createPhdrs() {
+  auto AddHdr = [this](unsigned Type, unsigned Flags) {
+    return &*Phdrs.emplace(Phdrs.end(), Type, Flags);
+  };
+
+  auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) {
+    Hdr.Last = Sec;
+    if (!Hdr.First)
+      Hdr.First = Sec;
+    Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlignment());
+  };
+
+  // The first phdr entry is PT_PHDR which describes the program header itself.
+  Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
+  AddSec(Hdr, Out<ELFT>::ProgramHeaders);
+
+  // PT_INTERP must be the second entry if exists.
+  if (needsInterpSection()) {
+    Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags()));
+    AddSec(Hdr, Out<ELFT>::Interp);
+  }
+
+  // Add the first PT_LOAD segment for regular output sections.
+  uintX_t Flags = PF_R;
+  Phdr *Load = AddHdr(PT_LOAD, Flags);
+  AddSec(*Load, Out<ELFT>::ElfHeader);
+  AddSec(*Load, Out<ELFT>::ProgramHeaders);
+
+  Phdr TlsHdr(PT_TLS, PF_R);
+  Phdr RelRo(PT_GNU_RELRO, PF_R);
+  Phdr Note(PT_NOTE, PF_R);
+  for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+    if (!(Sec->getFlags() & SHF_ALLOC))
+      break;
+
+    // If we meet TLS section then we create TLS header
+    // and put all TLS sections inside for futher use when
+    // assign addresses.
+    if (Sec->getFlags() & SHF_TLS)
+      AddSec(TlsHdr, Sec);
+
+    if (!needsPtLoad<ELFT>(Sec))
+      continue;
+
+    // If flags changed then we want new load segment.
+    uintX_t NewFlags = toPhdrFlags(Sec->getFlags());
+    if (Flags != NewFlags) {
+      Load = AddHdr(PT_LOAD, NewFlags);
+      Flags = NewFlags;
+    }
+
+    AddSec(*Load, Sec);
+
+    if (isRelroSection(Sec))
+      AddSec(RelRo, Sec);
+    if (Sec->getType() == SHT_NOTE)
+      AddSec(Note, Sec);
+  }
+
+  // Add the TLS segment unless it's empty.
+  if (TlsHdr.First)
+    Phdrs.push_back(std::move(TlsHdr));
+
+  // Add an entry for .dynamic.
+  if (isOutputDynamic()) {
+    Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags()));
+    AddSec(H, Out<ELFT>::Dynamic);
+  }
+
+  // PT_GNU_RELRO includes all sections that should be marked as
+  // read-only by dynamic linker after proccessing relocations.
+  if (RelRo.First)
+    Phdrs.push_back(std::move(RelRo));
+
+  // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
+  if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
+    Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME,
+                        toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags()));
+    AddSec(Hdr, Out<ELFT>::EhFrameHdr);
+  }
+
+  // PT_GNU_STACK is a special section to tell the loader to make the
+  // pages for the stack non-executable.
+  if (!Config->ZExecStack)
+    AddHdr(PT_GNU_STACK, PF_R | PF_W);
+
+  if (Note.First)
+    Phdrs.push_back(std::move(Note));
+
+  Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size());
+}
+
+// The first section of each PT_LOAD and the first section after PT_GNU_RELRO
+// have to be page aligned so that the dynamic linker can set the permissions.
+template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
+  for (const Phdr &P : Phdrs)
+    if (P.H.p_type == PT_LOAD)
+      P.First->PageAlign = true;
+
+  for (const Phdr &P : Phdrs) {
+    if (P.H.p_type != PT_GNU_RELRO)
+      continue;
+    // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
+    // have to align it to a page.
+    auto End = OutputSections.end();
+    auto I = std::find(OutputSections.begin(), End, P.Last);
+    if (I == End || (I + 1) == End)
+      continue;
+    OutputSectionBase<ELFT> *Sec = *(I + 1);
+    if (needsPtLoad(Sec))
+      Sec->PageAlign = true;
+  }
+}
+
+// We should set file offsets and VAs for elf header and program headers
+// sections. These are special, we do not include them into output sections
+// list, but have them to simplify the code.
+template <class ELFT> void Writer<ELFT>::fixHeaders() {
+  uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Config->ImageBase;
+  Out<ELFT>::ElfHeader->setVA(BaseVA);
+  uintX_t Off = Out<ELFT>::ElfHeader->getSize();
+  Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA);
+}
+
+// Assign VAs (addresses at run-time) to output sections.
+template <class ELFT> void Writer<ELFT>::assignAddresses() {
+  uintX_t VA = Config->ImageBase + Out<ELFT>::ElfHeader->getSize() +
+               Out<ELFT>::ProgramHeaders->getSize();
+
+  uintX_t ThreadBssOffset = 0;
+  for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+    uintX_t Alignment = Sec->getAlignment();
+    if (Sec->PageAlign)
+      Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
+
+    // We only assign VAs to allocated sections.
+    if (needsPtLoad<ELFT>(Sec)) {
+      VA = alignTo(VA, Alignment);
+      Sec->setVA(VA);
+      VA += Sec->getSize();
+    } else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) {
+      uintX_t TVA = VA + ThreadBssOffset;
+      TVA = alignTo(TVA, Alignment);
+      Sec->setVA(TVA);
+      ThreadBssOffset = TVA - VA + Sec->getSize();
+    }
+  }
+}
+
+// Adjusts the file alignment for a given output section and returns
+// its new file offset. The file offset must be the same with its
+// virtual address (modulo the page size) so that the loader can load
+// executables without any address adjustment.
+template <class ELFT, class uintX_t>
+static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) {
+  uintX_t Alignment = Sec->getAlignment();
+  if (Sec->PageAlign)
+    Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
+  Off = alignTo(Off, Alignment);
+
+  // Relocatable output does not have program headers
+  // and does not need any other offset adjusting.
+  if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC))
+    return Off;
+  return alignTo(Off, Target->PageSize, Sec->getVA());
+}
+
+// Assign file offsets to output sections.
+template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
+  uintX_t Off = 0;
+
+  auto Set = [&](OutputSectionBase<ELFT> *Sec) {
+    if (Sec->getType() == SHT_NOBITS) {
+      Sec->setFileOffset(Off);
+      return;
+    }
+
+    Off = getFileAlignment<ELFT>(Off, Sec);
+    Sec->setFileOffset(Off);
+    Off += Sec->getSize();
+  };
+
+  Set(Out<ELFT>::ElfHeader);
+  Set(Out<ELFT>::ProgramHeaders);
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    Set(Sec);
+
+  SectionHeaderOff = alignTo(Off, sizeof(uintX_t));
+  FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+}
+
+// Finalize the program headers. We call this function after we assign
+// file offsets and VAs to all sections.
+template <class ELFT> void Writer<ELFT>::setPhdrs() {
+  for (Phdr &P : Phdrs) {
+    Elf_Phdr &H = P.H;
+    OutputSectionBase<ELFT> *First = P.First;
+    OutputSectionBase<ELFT> *Last = P.Last;
+    if (First) {
+      H.p_filesz = Last->getFileOff() - First->getFileOff();
+      if (Last->getType() != SHT_NOBITS)
+        H.p_filesz += Last->getSize();
+      H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
+      H.p_offset = First->getFileOff();
+      H.p_vaddr = First->getVA();
+    }
+    if (H.p_type == PT_LOAD)
+      H.p_align = Target->PageSize;
+    else if (H.p_type == PT_GNU_RELRO)
+      H.p_align = 1;
+    H.p_paddr = H.p_vaddr;
+
+    // The TLS pointer goes after PT_TLS. At least glibc will align it,
+    // so round up the size to make sure the offsets are correct.
+    if (H.p_type == PT_TLS) {
+      Out<ELFT>::TlsPhdr = &H;
+      H.p_memsz = alignTo(H.p_memsz, H.p_align);
+    }
+  }
+}
+
+static uint32_t getMipsEFlags(bool Is64Bits) {
+  // FIXME: In fact ELF flags depends on ELF flags of input object files
+  // and selected emulation. For now just use hard coded values.
+  if (Is64Bits)
+    return EF_MIPS_CPIC | EF_MIPS_PIC | EF_MIPS_ARCH_64R2;
+
+  uint32_t V = EF_MIPS_CPIC | EF_MIPS_ABI_O32 | EF_MIPS_ARCH_32R2;
+  if (Config->Shared)
+    V |= EF_MIPS_PIC;
+  return V;
+}
+
+template <class ELFT> static typename ELFT::uint getEntryAddr() {
+  if (Symbol *S = Config->EntrySym)
+    return S->body()->getVA<ELFT>();
+  if (Config->EntryAddr != uint64_t(-1))
+    return Config->EntryAddr;
+  return 0;
+}
+
+template <class ELFT> static uint8_t getELFEncoding() {
+  if (ELFT::TargetEndianness == llvm::support::little)
+    return ELFDATA2LSB;
+  return ELFDATA2MSB;
+}
+
+static uint16_t getELFType() {
+  if (Config->Pic)
+    return ET_DYN;
+  if (Config->Relocatable)
+    return ET_REL;
+  return ET_EXEC;
+}
+
+// This function is called after we have assigned address and size
+// to each section. This function fixes some predefined absolute
+// symbol values that depend on section address and size.
+template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
+  auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
+    if (S1)
+      S1->Value = V;
+    if (S2)
+      S2->Value = V;
+  };
+
+  // _etext is the first location after the last read-only loadable segment.
+  // _edata is the first location after the last read-write loadable segment.
+  // _end is the first location after the uninitialized data region.
+  for (Phdr &P : Phdrs) {
+    Elf_Phdr &H = P.H;
+    if (H.p_type != PT_LOAD)
+      continue;
+    Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, H.p_vaddr + H.p_memsz);
+
+    uintX_t Val = H.p_vaddr + H.p_filesz;
+    if (H.p_flags & PF_W)
+      Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
+    else
+      Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
+  }
+}
+
+template <class ELFT> void Writer<ELFT>::writeHeader() {
+  uint8_t *Buf = Buffer->getBufferStart();
+  memcpy(Buf, "\177ELF", 4);
+
+  auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+
+  // Write the ELF header.
+  auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
+  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+  EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>();
+  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
+  EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
+  EHdr->e_type = getELFType();
+  EHdr->e_machine = FirstObj.EMachine;
+  EHdr->e_version = EV_CURRENT;
+  EHdr->e_entry = getEntryAddr<ELFT>();
+  EHdr->e_shoff = SectionHeaderOff;
+  EHdr->e_ehsize = sizeof(Elf_Ehdr);
+  EHdr->e_phnum = Phdrs.size();
+  EHdr->e_shentsize = sizeof(Elf_Shdr);
+  EHdr->e_shnum = OutputSections.size() + 1;
+  EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+
+  if (Config->EMachine == EM_MIPS)
+    EHdr->e_flags = getMipsEFlags(ELFT::Is64Bits);
+
+  if (!Config->Relocatable) {
+    EHdr->e_phoff = sizeof(Elf_Ehdr);
+    EHdr->e_phentsize = sizeof(Elf_Phdr);
+  }
+
+  // Write the program header table.
+  auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+  for (Phdr &P : Phdrs)
+    *HBuf++ = P.H;
+
+  // Write the section header table. Note that the first table entry is null.
+  auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    Sec->writeHeaderTo(++SHdrs);
+}
+
+template <class ELFT> void Writer<ELFT>::openFile() {
+  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(Config->OutputFile, FileSize,
+                               FileOutputBuffer::F_executable);
+  if (auto EC = BufferOrErr.getError())
+    error(EC, "failed to open " + Config->OutputFile);
+  else
+    Buffer = std::move(*BufferOrErr);
+}
+
+// Write section contents to a mmap'ed file.
+template <class ELFT> void Writer<ELFT>::writeSections() {
+  uint8_t *Buf = Buffer->getBufferStart();
+
+  // PPC64 needs to process relocations in the .opd section before processing
+  // relocations in code-containing sections.
+  if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd) {
+    Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
+    Sec->writeTo(Buf + Sec->getFileOff());
+  }
+
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    if (Sec != Out<ELFT>::Opd)
+      Sec->writeTo(Buf + Sec->getFileOff());
+}
+
+template <class ELFT> void Writer<ELFT>::writeBuildId() {
+  if (!Out<ELFT>::BuildId)
+    return;
+
+  // Compute a hash of all sections except .debug_* sections.
+  // We skip debug sections because they tend to be very large
+  // and their contents are very likely to be the same as long as
+  // other sections are the same.
+  uint8_t *Start = Buffer->getBufferStart();
+  uint8_t *Last = Start;
+  std::vector<ArrayRef<uint8_t>> Regions;
+  for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+    uint8_t *End = Start + Sec->getFileOff();
+    if (!Sec->getName().startswith(".debug_"))
+      Regions.push_back({Last, End});
+    Last = End;
+  }
+  Regions.push_back({Last, Start + FileSize});
+  Out<ELFT>::BuildId->writeBuildId(Regions);
+}
+
+template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
+template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
+template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
+template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
diff --git a/ELF/Writer.h b/ELF/Writer.h
new file mode 100644 (file)
index 0000000..df25d8e
--- /dev/null
@@ -0,0 +1,38 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_WRITER_H
+#define LLD_ELF_WRITER_H
+
+#include <memory>
+
+namespace llvm {
+  class StringRef;
+}
+
+namespace lld {
+namespace elf {
+template <class ELFT> class InputSectionBase;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class SymbolTable;
+
+template <class ELFT> void writeResult(SymbolTable<ELFT> *Symtab);
+
+template <class ELFT> void markLive();
+
+template <class ELFT>
+llvm::StringRef getOutputSectionName(InputSectionBase<ELFT> *S);
+
+template <class ELFT>
+void reportDiscarded(InputSectionBase<ELFT> *IS,
+                     const std::unique_ptr<elf::ObjectFile<ELFT>> &File);
+}
+}
+
+#endif
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ec97986
--- /dev/null
@@ -0,0 +1,62 @@
+==============================================================================
+lld License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2011-2016 by the contributors listed in CREDITS.TXT
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+The lld software contains code written by third parties.  Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the lld Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program             Directory
+-------             ---------
+<none yet>
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..dc05cde
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+
+LLVM Linker (lld)
+==============================
+
+This directory and its subdirectories contain source code for the LLVM Linker, a
+modular cross platform linker which is built as part of the LLVM compiler
+infrastructure project.
+
+lld is open source software. You may freely distribute it under the terms of
+the license agreement found in LICENSE.txt.
diff --git a/cmake/modules/FindVTune.cmake b/cmake/modules/FindVTune.cmake
new file mode 100644 (file)
index 0000000..bd0cbe9
--- /dev/null
@@ -0,0 +1,31 @@
+# - Find VTune ittnotify.
+# Defines:
+# VTune_FOUND
+# VTune_INCLUDE_DIRS
+# VTune_LIBRARIES
+
+set(dirs
+  "$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/"
+  "C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/"
+  "$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/"
+  "C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/"
+  )
+
+find_path(VTune_INCLUDE_DIRS ittnotify.h
+    PATHS ${dirs}
+    PATH_SUFFIXES include)
+
+if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+  set(vtune_lib_dir lib64)
+else()
+  set(vtune_lib_dir lib32)
+endif()
+
+find_library(VTune_LIBRARIES libittnotify
+    HINTS "${VTune_INCLUDE_DIRS}/.."
+    PATHS ${dirs}
+    PATH_SUFFIXES ${vtune_lib_dir})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+    VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS)
diff --git a/docs/AtomLLD.rst b/docs/AtomLLD.rst
new file mode 100644 (file)
index 0000000..4d36ac6
--- /dev/null
@@ -0,0 +1,61 @@
+ATOM-based lld
+==============
+
+ATOM-based lld is a new set of modular code for creating linker tools.
+Currently it supports Mach-O.
+
+* End-User Features:
+
+  * Compatible with existing linker options
+  * Reads standard Object Files
+  * Writes standard Executable Files
+  * Remove clang's reliance on "the system linker"
+  * Uses the LLVM `"UIUC" BSD-Style license`__.
+
+* Applications:
+
+  * Modular design
+  * Support cross linking
+  * Easy to add new CPU support
+  * Can be built as static tool or library
+
+* Design and Implementation:
+
+  * Extensive unit tests
+  * Internal linker model can be dumped/read to textual format
+  * Additional linking features can be plugged in as "passes"
+  * OS specific and CPU specific code factored out
+
+Why a new linker?
+-----------------
+
+The fact that clang relies on whatever linker tool you happen to have installed
+means that clang has been very conservative adopting features which require a
+recent linker.
+
+In the same way that the MC layer of LLVM has removed clang's reliance on the
+system assembler tool, the lld project will remove clang's reliance on the
+system linker tool.
+
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 2
+
+   design
+   getting_started
+   ReleaseNotes
+   development
+   windows_support
+   open_projects
+   sphinx_intro
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
+__ http://llvm.org/docs/DeveloperPolicy.html#license
diff --git a/docs/C++11.rst b/docs/C++11.rst
new file mode 100644 (file)
index 0000000..0c4391e
--- /dev/null
@@ -0,0 +1,9 @@
+C++11
+=====
+
+Originally, LLD was developed in C++11 unlike the rest of LLVM. Now, all of
+LLVM, LLD, and Clang are developed using C++11. See the `LLVM Coding
+Standards`_ for details on the precise subset of C++11 supported by the various
+host compilers.
+
+.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d4f3b05
--- /dev/null
@@ -0,0 +1,8 @@
+if (LLVM_ENABLE_SPHINX)
+  if (SPHINX_FOUND)
+    include(AddSphinxTarget)
+    if (${SPHINX_OUTPUT_HTML})
+      add_sphinx_target(html lld)
+    endif()
+  endif()
+endif()
diff --git a/docs/Driver.rst b/docs/Driver.rst
new file mode 100644 (file)
index 0000000..5f2d946
--- /dev/null
@@ -0,0 +1,79 @@
+======
+Driver
+======
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+This document describes the lld driver. The purpose of this document is to
+describe both the motivation and design goals for the driver, as well as details
+of the internal implementation.
+
+Overview
+========
+
+The lld driver is designed to support a number of different command line
+interfaces. The main interfaces we plan to support are binutils' ld, Apple's
+ld, and Microsoft's link.exe.
+
+Flavors
+-------
+
+Each of these different interfaces is referred to as a flavor. There is also an
+extra flavor "core" which is used to exercise the core functionality of the
+linker it the test suite.
+
+* gnu
+* darwin
+* link
+* core
+
+Selecting a Flavor
+^^^^^^^^^^^^^^^^^^
+
+There are two different ways to tell lld which flavor to be. They are checked in
+order, so the second overrides the first. The first is to symlink :program:`lld`
+as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
+it as the first command line argument using ``-flavor``::
+
+  $ lld -flavor gnu
+
+There is a shortcut for ``-flavor core`` as ``-core``.
+
+
+Adding an Option to an existing Flavor
+======================================
+
+#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
+
+#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
+   for the option.
+
+#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
+   `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
+   for corresponding to the option.
+
+#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
+
+
+Adding a Flavor
+===============
+
+#. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to
+   :cpp:class:`lld::UniversalDriver::Flavor`.
+
+#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
+   :cpp:func:`lld::Driver::strToFlavor` and
+   :cpp:func:`lld::UniversalDriver::link`.
+   This allows the flavor to be selected via symlink and :option:`-flavor`.
+
+#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
+   describes the options. If the options are a superset of another driver, that
+   driver's td file can simply be included. The :file:`{flavor}Options.td` file
+   must also be added to :file:`lib/Driver/CMakeLists.txt`.
+
+#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
+   in :file:`lib/Driver/{flavor}Driver.cpp`.
diff --git a/docs/NewLLD.rst b/docs/NewLLD.rst
new file mode 100644 (file)
index 0000000..1f9bf87
--- /dev/null
@@ -0,0 +1,350 @@
+The ELF and COFF Linkers
+========================
+
+We started rewriting the ELF (Unix) and COFF (Windows) linkers in May 2015.
+Since then, we have been making a steady progress towards providing
+drop-in replacements for the system linkers.
+
+Currently, the Windows support is mostly complete and is about 2x faster
+than the linker that comes as a part of Micrsoft Visual Studio toolchain.
+
+The ELF support is in progress and is able to link large programs
+such as Clang or LLD itself. Unless your program depends on linker scripts,
+you can expect it to be linkable with LLD.
+It is currently about 1.2x to 2x faster than GNU gold linker.
+We aim to make it a drop-in replacement for the GNU linker.
+
+We expect that FreeBSD is going to be the first large system
+to adopt LLD as the system linker.
+We are working on it in collaboration with the FreeBSD project.
+
+The linkers are notably small; as of June 2016,
+the COFF linker is under 7k lines and the ELF linker is about 13k lines,
+while gold is 146K lines.
+
+The linkers are designed to be as fast and simple as possible.
+Because it is simple, it is easy to extend to support new features.
+It already supports several advanced features such section garbage
+collection and identical code folding.
+
+The COFF linker supports i386, x86-64 and ARM. The ELF linker supports
+i386, x86-64, x32, MIPS32, MIPS64, PowerPC, AMDGPU, ARM and Aarch64,
+although the quality varies depending on platform. By default, LLD
+provides support for all targets because the amount of code we have for
+each target is so small. We do not even provide a way to disable
+targets at compile time.
+
+There are a few key design choices that we made to achieve these goals.
+We will describe them in this document.
+
+The ELF Linker as a Library
+---------------------------
+
+You can embed LLD to your program by linking against it and calling the linker's
+entry point function lld::elf::link.
+
+The current policy is that it is your reponsibility to give trustworthy object
+files. The function is guaranteed to return as long as you do not pass corrupted
+or malicious object files. A corrupted file could cause a fatal error or SEGV.
+That being said, you don't need to worry too much about it if you create object
+files in the usual way and give them to the linker. It is naturally expected to
+work, or otherwise it's a linker's bug.
+
+Design
+======
+
+We will describe the design of the linkers in the rest of the document.
+
+Key Concepts
+------------
+
+Linkers are fairly large pieces of software.
+There are many design choices you have to make to create a complete linker.
+
+This is a list of design choices we've made for ELF and COFF LLD.
+We believe that these high-level design choices achieved a right balance
+between speed, simplicity and extensibility.
+
+* Implement as native linkers
+
+  We implemented the linkers as native linkers for each file format.
+
+  The two linkers share the same design but do not share code.
+  Sharing code makes sense if the benefit is worth its cost.
+  In our case, ELF and COFF are different enough that we thought the layer to
+  abstract the differences wouldn't worth its complexity and run-time cost.
+  Elimination of the abstract layer has greatly simplified the implementation.
+
+* Speed by design
+
+  One of the most important things in archiving high performance is to
+  do less rather than do it efficiently.
+  Therefore, the high-level design matters more than local optimizations.
+  Since we are trying to create a high-performance linker,
+  it is very important to keep the design as efficient as possible.
+
+  Broadly speaking, we do not do anything until we have to do it.
+  For example, we do not read section contents or relocations
+  until we need them to continue linking.
+  When we need to do some costly operation (such as looking up
+  a hash table for each symbol), we do it only once.
+  We obtain a handler (which is typically just a pointer to actual data)
+  on the first operation and use it throughout the process.
+
+* Efficient archive file handling
+
+  LLD's handling of archive files (the files with ".a" file extension) is different
+  from the traditional Unix linkers and similar to Windows linkers.
+  We'll describe how the traditional Unix linker handles archive files,
+  what the problem is, and how LLD approached the problem.
+
+  The traditional Unix linker maintains a set of undefined symbols during linking.
+  The linker visits each file in the order as they appeared in the command line
+  until the set becomes empty. What the linker would do depends on file type.
+
+  - If the linker visits an object file, the linker links object files to the result,
+    and undefined symbols in the object file are added to the set.
+
+  - If the linker visits an archive file, it checks for the archive file's symbol table
+    and extracts all object files that have definitions for any symbols in the set.
+
+  This algorithm sometimes leads to a counter-intuitive behavior.
+  If you give archive files before object files, nothing will happen
+  because when the linker visits archives, there is no undefined symbols in the set.
+  As a result, no files are extracted from the first archive file,
+  and the link is done at that point because the set is empty after it visits one file.
+
+  You can fix the problem by reordering the files,
+  but that cannot fix the issue of mutually-dependent archive files.
+
+  Linking mutually-dependent archive files is tricky.
+  You may specify the same archive file multiple times to
+  let the linker visit it more than once.
+  Or, you may use the special command line options, `--start-group` and `--end-group`,
+  to let the linker loop over the files between the options until
+  no new symbols are added to the set.
+
+  Visiting the same archive files multiple makes the linker slower.
+
+  Here is how LLD approached the problem. Instead of memorizing only undefined symbols,
+  we program LLD so that it memorizes all symbols.
+  When it sees an undefined symbol that can be resolved by extracting an object file
+  from an archive file it previously visited, it immediately extracts the file and link it.
+  It is doable because LLD does not forget symbols it have seen in archive files.
+
+  We believe that the LLD's way is efficient and easy to justify.
+
+  The semantics of LLD's archive handling is different from the traditional Unix's.
+  You can observe it if you carefully craft archive files to exploit it.
+  However, in reality, we don't know any program that cannot link
+  with our algorithm so far, so it's not going to cause trouble.
+
+Numbers You Want to Know
+------------------------
+
+To give you intuition about what kinds of data the linker is mainly working on,
+I'll give you the list of objects and their numbers LLD has to read and process
+in order to link a very large executable. In order to link Chrome with debug info,
+which is roughly 2 GB in output size, LLD reads
+
+- 17,000 files,
+- 1,800,000 sections,
+- 6,300,000 symbols, and
+- 13,000,000 relocations.
+
+LLD produces the 2 GB executable in 15 seconds.
+
+These numbers vary depending on your program, but in general,
+you have a lot of relocations and symbols for each file.
+If your program is written in C++, symbol names are likely to be
+pretty long because of name mangling.
+
+It is important to not waste time on relocations and symbols.
+
+In the above case, the total amount of symbol strings is 450 MB,
+and inserting all of them to a hash table takes 1.5 seconds.
+Therefore, if you causally add a hash table lookup for each symbol,
+it would slow down the linker by 10%. So, don't do that.
+
+On the other hand, you don't have to pursue efficiency
+when handling files.
+
+Important Data Strcutures
+-------------------------
+
+We will describe the key data structures in LLD in this section.
+The linker can be understood as the interactions between them.
+Once you understand their functions, the code of the linker should look obvious to you.
+
+* SymbolBody
+
+  SymbolBody is a class to represent symbols.
+  They are created for symbols in object files or archive files.
+  The linker creates linker-defined symbols as well.
+
+  There are basically three types of SymbolBodies: Defined, Undefined, or Lazy.
+
+  - Defined symbols are for all symbols that are considered as "resolved",
+    including real defined symbols, COMDAT symbols, common symbols,
+    absolute symbols, linker-created symbols, etc.
+  - Undefined symbols represent undefined symbols, which need to be replaced by
+    Defined symbols by the resolver until the link is complete.
+  - Lazy symbols represent symbols we found in archive file headers
+    which can turn into Defined if we read archieve members.
+
+* Symbol
+
+  A Symbol is a container for a SymbolBody. There's only one Symbol for each
+  unique symbol name (this uniqueness is guaranteed by the symbol table).
+  Each global symbol has only one SymbolBody at any one time, which is
+  the SymbolBody stored within a memory region of the Symbol large enough
+  to store any SymbolBody.
+
+  As the resolver reads symbols from input files, it replaces the Symbol's
+  SymbolBody with the "best" SymbolBody for its symbol name by constructing
+  the new SymbolBody in place on top of the existing SymbolBody. For example,
+  if the resolver is given a defined symbol, and the SymbolBody with its name
+  is undefined, it will construct a Defined SymbolBody over the Undefined
+  SymbolBody.
+
+  This means that each SymbolBody pointer always points to the best SymbolBody,
+  and it is possible to get from a SymbolBody to a Symbol, or vice versa,
+  by adding or subtracting a fixed offset. This memory layout helps reduce
+  the cache miss rate through high locality and a small number of required
+  pointer indirections.
+
+* SymbolTable
+
+  SymbolTable is basically a hash table from strings to Symbols
+  with a logic to resolve symbol conflicts. It resolves conflicts by symbol type.
+
+  - If we add Defined and Undefined symbols, the symbol table will keep the former.
+  - If we add Defined and Lazy symbols, it will keep the former.
+  - If we add Lazy and Undefined, it will keep the former,
+    but it will also trigger the Lazy symbol to load the archive member
+    to actually resolve the symbol.
+
+* Chunk (COFF specific)
+
+  Chunk represents a chunk of data that will occupy space in an output.
+  Each regular section becomes a chunk.
+  Chunks created for common or BSS symbols are not backed by sections.
+  The linker may create chunks to append additional data to an output as well.
+
+  Chunks know about their size, how to copy their data to mmap'ed outputs,
+  and how to apply relocations to them.
+  Specifically, section-based chunks know how to read relocation tables
+  and how to apply them.
+
+* InputSection (ELF specific)
+
+  Since we have less synthesized data for ELF, we don't abstract slices of
+  input files as Chunks for ELF. Instead, we directly use the input section
+  as an internal data type.
+
+  InputSection knows about their size and how to copy themselves to
+  mmap'ed outputs, just like COFF Chunks.
+
+* OutputSection
+
+  OutputSection is a container of InputSections (ELF) or Chunks (COFF).
+  An InputSection or Chunk belongs to at most one OutputSection.
+
+There are mainly three actors in this linker.
+
+* InputFile
+
+  InputFile is a superclass of file readers.
+  We have a different subclass for each input file type,
+  such as regular object file, archive file, etc.
+  They are responsible for creating and owning SymbolBodies and
+  InputSections/Chunks.
+
+* Writer
+
+  The writer is responsible for writing file headers and InputSections/Chunks to a file.
+  It creates OutputSections, put all InputSections/Chunks into them,
+  assign unique, non-overlapping addresses and file offsets to them,
+  and then write them down to a file.
+
+* Driver
+
+  The linking process is driven by the driver. The driver
+
+  - processes command line options,
+  - creates a symbol table,
+  - creates an InputFile for each input file and put all symbols in it into the symbol table,
+  - checks if there's no remaining undefined symbols,
+  - creates a writer,
+  - and passes the symbol table to the writer to write the result to a file.
+
+Link-Time Optimization
+----------------------
+
+LTO is implemented by handling LLVM bitcode files as object files.
+The linker resolves symbols in bitcode files normally. If all symbols
+are successfully resolved, it then runs LLVM passes
+with all bitcode files to convert them to one big regular ELF/COFF file.
+Finally, the linker replaces bitcode symbols with ELF/COFF symbols,
+so that they are linked as if they were in the native format from the beginning.
+
+The details are described in this document.
+http://llvm.org/docs/LinkTimeOptimization.html
+
+Glossary
+--------
+
+* RVA (COFF)
+
+  Short for Relative Virtual Address.
+
+  Windows executables or DLLs are not position-independent; they are
+  linked against a fixed address called an image base. RVAs are
+  offsets from an image base.
+
+  Default image bases are 0x140000000 for executables and 0x18000000
+  for DLLs. For example, when we are creating an executable, we assume
+  that the executable will be loaded at address 0x140000000 by the
+  loader, so we apply relocations accordingly. Result texts and data
+  will contain raw absolute addresses.
+
+* VA
+
+  Short for Virtual Address. For COFF, it is equivalent to RVA + image base.
+
+* Base relocations (COFF)
+
+  Relocation information for the loader. If the loader decides to map
+  an executable or a DLL to a different address than their image
+  bases, it fixes up binaries using information contained in the base
+  relocation table. A base relocation table consists of a list of
+  locations containing addresses. The loader adds a difference between
+  RVA and actual load address to all locations listed there.
+
+  Note that this run-time relocation mechanism is much simpler than ELF.
+  There's no PLT or GOT. Images are relocated as a whole just
+  by shifting entire images in memory by some offsets. Although doing
+  this breaks text sharing, I think this mechanism is not actually bad
+  on today's computers.
+
+* ICF
+
+  Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF).
+
+  ICF is an optimization to reduce output size by merging read-only sections
+  by not only their names but by their contents. If two read-only sections
+  happen to have the same metadata, actual contents and relocations,
+  they are merged by ICF. It is known as an effective technique,
+  and it usually reduces C++ program's size by a few percent or more.
+
+  Note that this is not entirely sound optimization. C/C++ require
+  different functions have different addresses. If a program depends on
+  that property, it would fail at runtime.
+
+  On Windows, that's not really an issue because MSVC link.exe enabled
+  the optimization by default. As long as your program works
+  with the linker's default settings, your program should be safe with ICF.
+
+  On Unix, your program is generally not guaranteed to be safe with ICF,
+  although large programs happen to work correctly.
+  LLD works fine with ICF for example.
diff --git a/docs/README.txt b/docs/README.txt
new file mode 100644 (file)
index 0000000..eb09a2d
--- /dev/null
@@ -0,0 +1,12 @@
+lld Documentation
+=================
+
+The lld documentation is written using the Sphinx documentation generator. It is
+currently tested with Sphinx 1.1.3.
+
+We currently use the 'nature' theme and a Beaker inspired structure.
+
+To rebuild documents into html:
+
+   [/lld/docs]> make html
+
diff --git a/docs/Readers.rst b/docs/Readers.rst
new file mode 100644 (file)
index 0000000..f949963
--- /dev/null
@@ -0,0 +1,171 @@
+.. _Readers:
+
+Developing lld Readers
+======================
+
+Introduction
+------------
+
+The purpose of a "Reader" is to take an object file in a particular format
+and create an `lld::File`:cpp:class: (which is a graph of Atoms)
+representing the object file.  A Reader inherits from
+`lld::Reader`:cpp:class: which lives in
+:file:`include/lld/Core/Reader.h` and
+:file:`lib/Core/Reader.cpp`.
+
+The Reader infrastructure for an object format ``Foo`` requires the
+following pieces in order to fit into lld:
+
+:file:`include/lld/ReaderWriter/ReaderFoo.h`
+
+   .. cpp:class:: ReaderOptionsFoo : public ReaderOptions
+
+      This Options class is the only way to configure how the Reader will
+      parse any file into an `lld::Reader`:cpp:class: object.  This class
+      should be declared in the `lld`:cpp:class: namespace.
+
+   .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
+
+      This factory function configures and create the Reader. This function
+      should be declared in the `lld`:cpp:class: namespace.
+
+:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
+
+   .. cpp:class:: ReaderFoo : public Reader
+
+      This is the concrete Reader class which can be called to parse
+      object files. It should be declared in an anonymous namespace or
+      if there is shared code with the `lld::WriterFoo`:cpp:class: you
+      can make a nested namespace (e.g. `lld::foo`:cpp:class:).
+
+You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
+``.h`` file. An important design aspect of lld is that all Readers are
+created *only* through an object-format-specific
+:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
+parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
+class is the one-and-only way to control how the Reader operates when
+parsing an input file into an Atom graph. For instance, you may want the
+Reader to only accept certain architectures. The options class can be
+instantiated from command line options or be programmatically configured.
+
+Where to start
+--------------
+
+The lld project already has a skeleton of source code for Readers for
+``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format.
+If your file format is a variant of one of those, you should modify the
+existing Reader to support your variant. This is done by customizing the Options
+class for the Reader and making appropriate changes to the ``.cpp`` file to
+interpret those options and act accordingly.
+
+If your object file format is not a variant of any existing Reader, you'll need
+to create a new Reader subclass with the organization described above.
+
+Readers are factories
+---------------------
+
+The linker will usually only instantiate your Reader once.  That one Reader will
+have its loadFile() method called many times with different input files.
+To support multithreaded linking, the Reader may be parsing multiple input
+files in parallel. Therefore, there should be no parsing state in you Reader
+object.  Any parsing state should be in ivars of your File subclass or in
+some temporary object.
+
+The key method to implement in a reader is::
+
+  virtual error_code loadFile(LinkerInput &input,
+                              std::vector<std::unique_ptr<File>> &result);
+
+It takes a memory buffer (which contains the contents of the object file
+being read) and returns an instantiated lld::File object which is
+a collection of Atoms. The result is a vector of File pointers (instead of
+simple a File pointer) because some file formats allow multiple object
+"files" to be encoded in one file system file.
+
+
+Memory Ownership
+----------------
+
+Atoms are always owned by their File object. During core linking when Atoms
+are coalesced or stripped away, core linking does not delete them.
+Core linking just removes those unused Atoms from its internal list.
+The destructor of a File object is responsible for deleting all Atoms it
+owns, and if ownership of the MemoryBuffer was passed to it, the File
+destructor needs to delete that too.
+
+Making Atoms
+------------
+
+The internal model of lld is purely Atom based.  But most object files do not
+have an explicit concept of Atoms, instead most have "sections". The way
+to think of this is that a section is just a list of Atoms with common
+attributes.
+
+The first step in parsing section-based object files is to cleave each
+section into a list of Atoms. The technique may vary by section type. For
+code sections (e.g. .text), there are usually symbols at the start of each
+function. Those symbol addresses are the points at which the section is
+cleaved into discrete Atoms.  Some file formats (like ELF) also include the
+length of each symbol in the symbol table. Otherwise, the length of each
+Atom is calculated to run to the start of the next symbol or the end of the
+section.
+
+Other sections types can be implicitly cleaved. For instance c-string literals
+or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
+the content of the section.  It is important to cleave sections into Atoms
+to remove false dependencies. For instance the .eh_frame section often
+has no symbols, but contains "pointers" to the functions for which it
+has unwind info.  If the .eh_frame section was not cleaved (but left as one
+big Atom), there would always be a reference (from the eh_frame Atom) to
+each function.  So the linker would be unable to coalesce or dead stripped
+away the function atoms.
+
+The lld Atom model also requires that a reference to an undefined symbol be
+modeled as a Reference to an UndefinedAtom. So the Reader also needs to
+create an UndefinedAtom for each undefined symbol in the object file.
+
+Once all Atoms have been created, the second step is to create References
+(recall that Atoms are "nodes" and References are "edges"). Most References
+are created by looking at the "relocation records" in the object file. If
+a function contains a call to "malloc", there is usually a relocation record
+specifying the address in the section and the symbol table index. Your
+Reader will need to convert the address to an Atom and offset and the symbol
+table index into a target Atom. If "malloc" is not defined in the object file,
+the target Atom of the Reference will be an UndefinedAtom.
+
+
+Performance
+-----------
+Once you have the above working to parse an object file into Atoms and
+References, you'll want to look at performance.  Some techniques that can
+help performance are:
+
+* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
+  just have each atom point to its subrange of References in that vector.
+  This can be faster that allocating each Reference as separate object.
+* Pre-scan the symbol table and determine how many atoms are in each section
+  then allocate space for all the Atom objects at once.
+* Don't copy symbol names or section content to each Atom, instead use
+  StringRef and ArrayRef in each Atom to point to its name and content in the
+  MemoryBuffer.
+
+
+Testing
+-------
+
+We are still working on infrastructure to test Readers. The issue is that
+you don't want to check in binary files to the test suite. And the tools
+for creating your object file from assembly source may not be available on
+every OS.
+
+We are investigating a way to use YAML to describe the section, symbols,
+and content of a file. Then have some code which will write out an object
+file from that YAML description.
+
+Once that is in place, you can write test cases that contain section/symbols
+YAML and is run through the linker to produce Atom/References based YAML which
+is then run through FileCheck to verify the Atoms and References are as
+expected.
+
+
+
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
new file mode 100644 (file)
index 0000000..5344fc4
--- /dev/null
@@ -0,0 +1,102 @@
+======================
+LLD 3.9 Release Notes
+======================
+
+.. contents::
+    :local:
+
+Introduction
+============
+
+This document contains the release notes for the LLD linker, release 3.9.
+Here we describe the status of LLD, including major improvements
+from the previous release. All LLD releases may be downloaded
+from the `LLVM releases web site <http://llvm.org/releases/>`_.
+
+What's new in ELF Support?
+==========================
+
+LLD 3.9 is a major milestone for us. It is the first release that can
+link real-world large userland programs, including LLVM/Clang/LLD
+themselves. In fact, for example, it can now be used to produce most
+userland programs distributed as part of FreeBSD.
+
+Many contributors have joined to the project to develop new features,
+port it to new architectures and fix issues since the last release.
+
+Link-Time Optimization
+----------------------
+
+Initial support for LTO has been added. It is compatible with
+`the LLVM gold plugin <http://llvm.org/docs/GoldPlugin.html>`_ in terms of
+command line flags and input file format so that LLD is usable as a
+drop-in replacement for GNU gold. LTO is implemented as a native
+feature unlike the GNU gold's plugin mechanism.
+
+Identical Code Folding
+----------------------
+
+LLD 3.9 can now merge identical code sections to produce smaller
+output files. It is expected to be used with ``-ffunction-sections``.
+
+Symbol Versioning
+-----------------
+
+LLD 3.9 is able to link against versioned symbols as well as produce
+versioned symbols. Both the original Sun's symbol versioning scheme
+and the GNU extension are supported.
+
+New Targets
+-----------
+
+LLD has expanded support for new targets, including ARM/Thumb, the x32
+ABI and MIPS N64 ABI, in addition to the existing support for x86,
+x86-64, MIPS, PowerPC and PPC64.
+
+TLS Relocation Optimizations
+----------------------------
+
+The ELF ABI specification of the thread-local variable define a few
+peephole optimizations linkers can do by rewriting instructions at the
+link-time to reduce run-time overhead to access TLS variables. That
+feature has been implemented.
+
+New Linker Flags
+----------------
+
+Many command line options have been added in this release, including:
+
+- Symbol resolution and output options: ``-Bsymbolic-functions``,
+  ``-export-dynamic-symbol``, ``-image-base``, ``-pie``, ``-end-lib``,
+  ``-start-lib``, ``-build-id={md5,sha1,none,0x<hexstring>}``.
+
+- Symbol versioning option: ``-dynamic-list``.
+
+- LTO options: ``-lto-O``, ``-lto-aa-pipeline``, ``-lto-jobs``,
+  ``-lto-newpm-passes``, ``-plugin``, ``-plugin-eq``, ``-plugin-opt``,
+  ``-plugin-opt-eq``, ``-disable-verify``, ``-mllvm``.
+
+- Driver optionss: ``-help``, ``-version``, ``-unresolved-symbols``.
+
+- Debug options: ``-demangle``, ``-reproduce``, ``-save-temps``,
+  ``-strip-debug``, ``-trace``, ``-trace-symbol``,
+  ``-warn-execstack``.
+
+- Exception handling option: ``-eh-frame-hdr``.
+
+- Identical Code Folding option: ``-icf``.
+
+Changes to the MIPS Target
+--------------------------
+
+* Added support for MIPS N64 ABI.
+* Added support for TLS relocations for both O32 and N64 MIPS ABIs.
+
+Building LLVM Toolchain with LLD
+--------------------------------
+
+A new CMake variable, ``LLVM_ENABLE_LLD``, has been added to use LLD
+to build the LLVM toolchain. If the varaible is true, ``-fuse-ld=lld``
+option will be added to linker flags so that ``ld.lld`` is used
+instead of default ``ld``.  Because ``-fuse-ld=lld`` is a new compiler
+driver option, you need Clang 3.8 or newer to use the feature.
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644 (file)
index 0000000..724ad6e
Binary files /dev/null and b/docs/_static/favicon.ico differ
diff --git a/docs/_templates/indexsidebar.html b/docs/_templates/indexsidebar.html
new file mode 100644 (file)
index 0000000..61968f2
--- /dev/null
@@ -0,0 +1,4 @@
+<h3>Bugs</h3>
+
+<p>lld bugs should be reported at the
+  LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
new file mode 100644 (file)
index 0000000..519a24b
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+<style type="text/css">
+  table.right { float: right; margin-left: 20px; }
+  table.right td { border: 1px solid #ccc; }
+</style>
+{% endblock %}
+
+{% block rootrellink %}
+  <li><a href="{{ pathto('index') }}">lld Home</a>&nbsp;|&nbsp;</li>
+{% endblock %}
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..88fcdd8
--- /dev/null
@@ -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 X.Y version.
+version = '3.2'
+# The full version, including alpha/beta/rc tags.
+release = '3.2'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%Y-%m-%d'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'llvm-theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ["."]
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# If given, this must be the name of an image file (path relative to the
+# configuration directory) that is the favicon of the docs. Modern browsers use
+# this as icon for tabs, windows and bookmarks. It should be a Windows-style
+# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None.  The
+# image file will be copied to the _static directory of the output HTML, but
+# only if the file does not already exist there.
+html_favicon = '_static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%Y-%m-%d'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {'index': 'indexsidebar.html'}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {'index': 'index.html'}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'llddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('contents', 'lld.tex', u'lld Documentation',
+   u'LLVM project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('contents', 'lld', u'lld Documentation',
+     [u'LLVM project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('contents', 'lld', u'lld Documentation',
+   u'LLVM project', 'lld', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# FIXME: Define intersphinx configration.
+intersphinx_mapping = {}
+
+
+# -- Options for extensions ----------------------------------------------------
+
+# Enable this if you want TODOs to show up in the generated documentation.
+todo_include_todos = True
diff --git a/docs/design.rst b/docs/design.rst
new file mode 100644 (file)
index 0000000..14d1809
--- /dev/null
@@ -0,0 +1,418 @@
+.. _design:
+
+Linker Design
+=============
+
+Introduction
+------------
+
+lld is a new generation of linker.  It is not "section" based like traditional
+linkers which mostly just interlace sections from multiple object files into the
+output file.  Instead, lld is based on "Atoms".  Traditional section based
+linking work well for simple linking, but their model makes advanced linking
+features difficult to implement.  Features like dead code stripping, reordering
+functions for locality, and C++ coalescing require the linker to work at a finer
+grain.
+
+An atom is an indivisible chunk of code or data.  An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc.  An atom also
+has a list of References.  A Reference contains: a kind, an optional offset, an
+optional addend, and an optional target atom.
+
+The Atom model allows the linker to use standard graph theory models for linking
+data structures.  Each atom is a node, and each Reference is an edge.  The
+feature of dead code stripping is implemented by following edges to mark all
+live atoms, and then delete the non-live atoms.
+
+
+Atom Model
+----------
+
+An atom is an indivisible chunk of code or data.  Typically each user written
+function or global variable is an atom.  In addition, the compiler may emit
+other atoms, such as for literal c-strings or floating point constants, or for
+runtime data structures like dwarf unwind info or pointers to initializers.
+
+A simple "hello world" object file would be modeled like this:
+
+.. image:: hello.png
+
+There are three atoms: main, a proxy for printf, and an anonymous atom
+containing the c-string literal "hello world".  The Atom "main" has two
+references. One is the call site for the call to printf, and the other is a
+reference for the instruction that loads the address of the c-string literal.
+
+There are only four different types of atoms:
+
+       * DefinedAtom
+               95% of all atoms.  This is a chunk of code or data
+
+       * UndefinedAtom
+          This is a place holder in object files for a reference to some atom
+          outside the translation unit.During core linking it is usually replaced
+          by (coalesced into) another Atom.
+
+       * SharedLibraryAtom
+               If a required symbol name turns out to be defined in a dynamic shared
+               library (and not some object file).  A SharedLibraryAtom is the
+               placeholder Atom used to represent that fact.
+
+               It is similar to an UndefinedAtom, but it also tracks information
+               about the associated shared library.
+
+       * AbsoluteAtom
+               This is for embedded support where some stuff is implemented in ROM at
+               some fixed address.  This atom has no content.  It is just an address
+               that the Writer needs to fix up any references to point to.
+
+
+File Model
+----------
+
+The linker views the input files as basically containers of Atoms and
+References, and just a few attributes of their own.  The linker works with three
+kinds of files: object files, static libraries, and dynamic shared libraries.
+Each kind of file has reader object which presents the file in the model
+expected by the linker.
+
+Object File
+~~~~~~~~~~~
+
+An object file is just a container of atoms.  When linking an object file, a
+reader is instantiated which parses the object file and instantiates a set of
+atoms representing all content in the .o file.  The linker adds all those atoms
+to a master graph.
+
+Static Library (Archive)
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the traditional unix static archive which is just a collection of object
+files with a "table of contents". When linking with a static library, by default
+nothing is added to the master graph of atoms. Instead, if after merging all
+atoms from object files into a master graph, if any "undefined" atoms are left
+remaining in the master graph, the linker reads the table of contents for each
+static library to see if any have the needed definitions. If so, the set of
+atoms from the specified object file in the static library is added to the
+master graph of atoms.
+
+Dynamic Library (Shared Object)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dynamic libraries are different than object files and static libraries in that
+they don't directly add any content.  Their purpose is to check at build time
+that the remaining undefined references can be resolved at runtime, and provide
+a list of dynamic libraries (SO_NEEDED) that will be needed at runtime.  The way
+this is modeled in the linker is that a dynamic library contributes no atoms to
+the initial graph of atoms.  Instead, (like static libraries) if there are
+"undefined" atoms in the master graph of all atoms, then each dynamic library is
+checked to see if exports the required symbol. If so, a "shared library" atom is
+instantiated by the by the reader which the linker uses to replace the
+"undefined" atom.
+
+Linking Steps
+-------------
+
+Through the use of abstract Atoms, the core of linking is architecture
+independent and file format independent.  All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.
+
+The overall steps in linking are:
+
+  #. Command line processing
+
+  #. Parsing input files
+
+  #. Resolving
+
+  #. Passes/Optimizations
+
+  #. Generate output file
+
+The Resolving and Passes steps are done purely on the master graph of atoms, so
+they have no notion of file formats such as mach-o or ELF.
+
+
+Input Files
+~~~~~~~~~~~
+
+Existing developer tools using different file formats for object files.
+A goal of lld is to be file format independent.  This is done
+through a plug-in model for reading object files. The lld::Reader is the base
+class for all object file readers.  A Reader follows the factory method pattern.
+A Reader instantiates an lld::File object (which is a graph of Atoms) from a
+given object file (on disk or in-memory).
+
+Every Reader subclass defines its own "options" class (for instance the mach-o
+Reader defines the class ReaderOptionsMachO).  This options class is the
+one-and-only way to control how the Reader operates when parsing an input file
+into an Atom graph.  For instance, you may want the Reader to only accept
+certain architectures.  The options class can be instantiated from command
+line options, or it can be subclassed and the ivars programmatically set.
+
+Resolving
+~~~~~~~~~
+
+The resolving step takes all the atoms' graphs from each object file and
+combines them into one master object graph.  Unfortunately, it is not as simple
+as appending the atom list from each file into one big list.  There are many
+cases where atoms need to be coalesced.  That is, two or more atoms need to be
+coalesced into one atom.  This is necessary to support: C language "tentative
+definitions", C++ weak symbols for templates and inlines defined in headers,
+replacing undefined atoms with actual definition atoms, and for merging copies
+of constants like c-strings and floating point constants.
+
+The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols.  By-content is used for constant data
+that can be merged.
+
+The resolving process maintains some global linking "state", including a "symbol
+table" which is a map from llvm::StringRef to lld::Atom*.  With these data
+structures, the linker iterates all atoms in all input files. For each atom, it
+checks if the atom is named and has a global or hidden scope.  If so, the atom
+is added to the symbol table map.  If there already is a matching atom in that
+table, that means the current atom needs to be coalesced with the found atom, or
+it is a multiple definition error.
+
+When all initial input file atoms have been processed by the resolver, a scan is
+made to see if there are any undefined atoms in the graph.  If there are, the
+linker scans all libraries (both static and dynamic) looking for definitions to
+replace the undefined atoms.  It is an error if any undefined atoms are left
+remaining.
+
+Dead code stripping (if requested) is done at the end of resolving.  The linker
+does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
+executable) and follows each references and marks each Atom that it visits as
+"live".  When done, all atoms not marked "live" are removed.
+
+The result of the Resolving phase is the creation of an lld::File object.  The
+goal is that the lld::File model is **the** internal representation
+throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
+lld::File.  The file writers (mach-o, ELF, COFF) taken an lld::File and produce
+their file kind, and every Pass only operates on an lld::File.  This is not only
+a simpler, consistent model, but it enables the state of the linker to be dumped
+at any point in the link for testing purposes.
+
+
+Passes
+~~~~~~
+
+The Passes step is an open ended set of routines that each get a change to
+modify or enhance the current lld::File object. Some example Passes are:
+
+  * stub (PLT) generation
+
+  * GOT instantiation
+
+  * order_file optimization
+
+  * branch island generation
+
+  * branch shim generation
+
+  * Objective-C optimizations (Darwin specific)
+
+  * TLV instantiation (Darwin specific)
+
+  * DTrace probe processing (Darwin specific)
+
+  * compact unwind encoding (Darwin specific)
+
+
+Some of these passes are specific to Darwin's runtime environments.  But many of
+the passes are applicable to any OS (such as generating branch island for out of
+range branch instructions).
+
+The general structure of a pass is to iterate through the atoms in the current
+lld::File object, inspecting each atom and doing something.  For instance, the
+stub pass, looks for call sites to shared library atoms (e.g. call to printf).
+It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
+each proxy atom needed, and these new atoms are added to the current lld::File
+object.  Next, all the noted call sites to shared library atoms have their
+References altered to point to the stub atom instead of the shared library atom.
+
+
+Generate Output File
+~~~~~~~~~~~~~~~~~~~~
+
+Once the passes are done, the output file writer is given current lld::File
+object.  The writer's job is to create the executable content file wrapper and
+place the content of the atoms into it.
+
+lld uses a plug-in model for writing output files. All concrete writers (e.g.
+ELF, mach-o, etc) are subclasses of the lld::Writer class.
+
+Unlike the Reader class which has just one method to instantiate an lld::File,
+the Writer class has multiple methods.  The crucial method is to generate the
+output file, but there are also methods which allow the Writer to contribute
+Atoms to the resolver and specify passes to run.
+
+An example of contributing
+atoms is that if the Writer knows a main executable is being linked and such
+an executable requires a specially named entry point (e.g. "_main"), the Writer
+can add an UndefinedAtom with that special name to the resolver.  This will
+cause the resolver to issue an error if that symbol is not defined.
+
+Sometimes a Writer supports lazily created symbols, such as names for the start
+of sections. To support this, the Writer can create a File object which vends
+no initial atoms, but does lazily supply atoms by name as needed.
+
+Every Writer subclass defines its own "options" class (for instance the mach-o
+Writer defines the class WriterOptionsMachO).  This options class is the
+one-and-only way to control how the Writer operates when producing an output
+file from an Atom graph.  For instance, you may want the Writer to optimize
+the output for certain OS versions, or strip local symbols, etc. The options
+class can be instantiated from command line options, or it can be subclassed
+and the ivars programmatically set.
+
+
+lld::File representations
+-------------------------
+
+Just as LLVM has three representations of its IR model, lld has two
+representations of its File/Atom/Reference model:
+
+ * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
+
+ * textual (in YAML)
+
+
+Textual representations in YAML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In designing a textual format we want something easy for humans to read and easy
+for the linker to parse.  Since an atom has lots of attributes most of which are
+usually just the default, we should define default values for every attribute so
+that those can be omitted from the text representation.  Here is the atoms for a
+simple hello world program expressed in YAML::
+
+  target-triple:   x86_64-apple-darwin11
+
+  atoms:
+      - name:    _main
+        scope:   global
+        type:    code
+        content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+                   00, 00, 31, c0, 5d, c3 ]
+        fixups:
+        - offset: 07
+          kind:   pcrel32
+          target: 2
+        - offset: 0E
+          kind:   call32
+          target: _fprintf
+
+      - type:    c-string
+        content: [ 73, 5A, 00 ]
+
+  ...
+
+The biggest use for the textual format will be writing test cases.  Writing test
+cases in C is problematic because the compiler may vary its output over time for
+its own optimization reasons which my inadvertently disable or break the linker
+feature trying to be tested. By writing test cases in the linkers own textual
+format, we can exactly specify every attribute of every atom and thus target
+specific linker logic.
+
+The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
+library comes with the classes: ReaderYAML and WriterYAML.
+
+
+Testing
+-------
+
+The lld project contains a test suite which is being built up as new code is
+added to lld.  All new lld functionality should have a tests added to the test
+suite.  The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven.  Each
+test is a text file with comments telling lit how to run the test and check the
+result To facilitate testing, the lld project builds a tool called lld-core.
+This tool reads a YAML file (default from stdin), parses it into one or more
+lld::File objects in memory and then feeds those lld::File objects to the
+resolver phase.
+
+
+Resolver testing
+~~~~~~~~~~~~~~~~
+
+Basic testing is the "core linking" or resolving phase.  That is where the
+linker merges object files.  All test cases are written in YAML.  One feature of
+YAML is that it allows multiple "documents" to be encoding in one YAML stream.
+That means one text file can appear to the linker as multiple .o files - the
+normal case for the linker.
+
+Here is a simple example of a core linking test case. It checks that an
+undefined atom from one file will be replaced by a definition from another
+file::
+
+  # RUN: lld-core %s | FileCheck %s
+
+  #
+  # Test that undefined atoms are replaced with defined atoms.
+  #
+
+  ---
+  atoms:
+      - name:              foo
+        definition:        undefined
+  ---
+  atoms:
+      - name:              foo
+        scope:             global
+        type:              code
+  ...
+
+  # CHECK:       name:       foo
+  # CHECK:       scope:      global
+  # CHECK:       type:       code
+  # CHECK-NOT:   name:       foo
+  # CHECK:       ...
+
+
+Passes testing
+~~~~~~~~~~~~~~
+
+Since Passes just operate on an lld::File object, the lld-core tool has the
+option to run a particular pass (after resolving).  Thus, you can write a YAML
+test case with carefully crafted input to exercise areas of a Pass and the check
+the resulting lld::File object as represented in YAML.
+
+
+Design Issues
+-------------
+
+There are a number of open issues in the design of lld.  The plan is to wait and
+make these design decisions when we need to.
+
+
+Debug Info
+~~~~~~~~~~
+
+Currently, the lld model says nothing about debug info.  But the most popular
+debug format is DWARF and there is some impedance mismatch with the lld model
+and DWARF.  In lld there are just Atoms and only Atoms that need to be in a
+special section at runtime have an associated section.  Also, Atoms do not have
+addresses.  The way DWARF is spec'ed different parts of DWARF are supposed to go
+into specially named sections and the DWARF references function code by address.
+
+CPU and OS specific functionality
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
+differences in linking.  We just keep adding virtual methods to the base
+Platform class as we find linking areas that might need customization.  At some
+point we'll need to structure this better.
+
+
+File Attributes
+~~~~~~~~~~~~~~~
+
+Currently, lld::File just has a path and a way to iterate its atoms. We will
+need to add more attributes on a File.  For example, some equivalent to the
+target triple.  There is also a number of cached or computed attributes that
+could make various Passes more efficient.  For instance, on Darwin there are a
+number of Objective-C optimizations that can be done by a Pass.  But it would
+improve the plain C case if the Objective-C optimization Pass did not have to
+scan all atoms looking for any Objective-C data structures.  This could be done
+if the lld::File object had an attribute that said if the file had any
+Objective-C data in it. The Resolving phase would then be required to "merge"
+that attribute as object files are added.
diff --git a/docs/development.rst b/docs/development.rst
new file mode 100644 (file)
index 0000000..918e177
--- /dev/null
@@ -0,0 +1,48 @@
+.. _development:
+
+Development
+===========
+
+lld is developed as part of the `LLVM <http://llvm.org>`_ project.
+
+Using C++11 in lld
+------------------
+
+:doc:`C++11`.
+
+Creating a Reader
+-----------------
+
+See the :ref:`Creating a Reader <Readers>` guide.
+
+
+Modifying the Driver
+--------------------
+
+See :doc:`Driver`.
+
+
+Debugging
+---------
+
+You can run lld with ``-mllvm -debug`` command line options to enable debugging
+printouts. If you want to enable debug information for some specific pass, you
+can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
+the ``DEBUG_WITH_TYPE()`` macro.
+
+
+
+Documentation
+-------------
+
+The project documentation is written in reStructuredText and generated using the
+`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
+information on writing documentation for the project, see the
+:ref:`sphinx_intro`.
+
+.. toctree::
+   :hidden:
+
+   C++11
+   Readers
+   Driver
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
new file mode 100644 (file)
index 0000000..97c3d1b
--- /dev/null
@@ -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 (file)
index 0000000..70df111
Binary files /dev/null and b/docs/hello.png differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..d019c4f
--- /dev/null
@@ -0,0 +1,25 @@
+.. _index:
+
+lld - The LLVM Linker
+=====================
+
+lld contains two linkers whose architectures are different from each other.
+
+.. toctree::
+   :maxdepth: 1
+
+   NewLLD
+   AtomLLD
+
+Source
+------
+
+lld is available in the LLVM SVN repository::
+
+  svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+lld is also available via the read-only git mirror::
+
+  git clone http://llvm.org/git/lld.git
+
+Put it in llvm's tools/ directory, rerun cmake, then build target lld.
diff --git a/docs/llvm-theme/layout.html b/docs/llvm-theme/layout.html
new file mode 100644 (file)
index 0000000..0cd0918
--- /dev/null
@@ -0,0 +1,22 @@
+{#
+    sphinxdoc/layout.html
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Sphinx layout template for the sphinxdoc theme.
+
+    :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+#}
+{% extends "basic/layout.html" %}
+
+{% block relbar1 %}
+<div class="logo">
+<a href="{{ pathto('index') }}"><img src="{{
+pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
+</div>
+{{ super() }}
+{% endblock %}
+
+{# put the sidebar before the body #}
+{% block sidebar1 %}{{ sidebar() }}{% endblock %}
+{% block sidebar2 %}{% endblock %}
diff --git a/docs/llvm-theme/static/contents.png b/docs/llvm-theme/static/contents.png
new file mode 100644 (file)
index 0000000..7fb8215
Binary files /dev/null and b/docs/llvm-theme/static/contents.png differ
diff --git a/docs/llvm-theme/static/llvm.css b/docs/llvm-theme/static/llvm.css
new file mode 100644 (file)
index 0000000..32802bb
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme.  Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+    font-size: 14px;
+    letter-spacing: -0.01em;
+    line-height: 150%;
+    text-align: center;
+    background-color: #BFD1D4;
+    color: black;
+    padding: 0;
+    border: 1px solid #aaa;
+
+    margin: 0px 80px 0px 80px;
+    min-width: 740px;
+}
+
+div.logo {
+    background-color: white;
+    text-align: left;
+    padding: 10px 10px 15px 15px;
+}
+
+div.document {
+    background-color: white;
+    text-align: left;
+    background-image: url(contents.png);
+    background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+    margin: 0 240px 0 0;
+    border-right: 1px solid #ccc;
+}
+
+div.body {
+    margin: 0;
+    padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+    font-size: 1em;
+}
+
+div.related ul {
+    background-image: url(navigation.png);
+    height: 2em;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+    margin: 0;
+    padding: 0;
+    height: 2em;
+    float: left;
+}
+
+div.related ul li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+div.related ul li a {
+    margin: 0;
+    padding: 0 5px 0 5px;
+    line-height: 1.75em;
+    color: #EE9816;
+}
+
+div.related ul li a:hover {
+    color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+    padding: 0;
+}
+
+div.sphinxsidebar {
+    margin: 0;
+    padding: 0.5em 15px 15px 0;
+    width: 210px;
+    float: right;
+    font-size: 1em;
+    text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+    margin: 1em 0 0.5em 0;
+    font-size: 1em;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border: 1px solid #86989B;
+    background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+    color: white;
+}
+
+div.sphinxsidebar ul {
+    padding-left: 1.5em;
+    margin-top: 7px;
+    padding: 0;
+    line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+    margin-left: 20px;
+}
+
+div.footer {
+    background-color: #E3EFF1;
+    color: #86989B;
+    padding: 3px 8px 3px 0;
+    clear: both;
+    font-size: 0.8em;
+    text-align: right;
+}
+
+div.footer a {
+    color: #86989B;
+    text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {
+    margin: 0.8em 0 0.5em 0;
+}
+
+a {
+    color: #CA7900;
+    text-decoration: none;
+}
+
+a:hover {
+    color: #2491CF;
+}
+
+div.body a {
+    text-decoration: underline;
+}
+
+h1 {
+    margin: 0;
+    padding: 0.7em 0 0.3em 0;
+    font-size: 1.5em;
+    color: #11557C;
+}
+
+h2 {
+    margin: 1.3em 0 0.2em 0;
+    font-size: 1.35em;
+    padding: 0;
+}
+
+h3 {
+    margin: 1em 0 -0.3em 0;
+    font-size: 1.2em;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+    color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+    display: none;
+    margin: 0 0 0 0.3em;
+    padding: 0 0.2em 0 0.2em;
+    color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+    display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+    color: #777;
+    background-color: #eee;
+}
+
+a.headerlink {
+    color: #c60f0f!important;
+    font-size: 1em;
+    margin-left: 6px;
+    padding: 0 4px 0 4px;
+    text-decoration: none!important;
+}
+
+a.headerlink:hover {
+    background-color: #ccc;
+    color: white!important;
+}
+
+cite, code, tt {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.01em;
+}
+
+tt {
+    background-color: #f2f2f2;
+    border-bottom: 1px solid #ddd;
+    color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+    border: 0;
+}
+
+hr {
+    border: 1px solid #abc;
+    margin: 2em;
+}
+
+a tt {
+    border: 0;
+    color: #CA7900;
+}
+
+a tt:hover {
+    color: #2491CF;
+}
+
+pre {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.015em;
+    line-height: 120%;
+    padding: 0.5em;
+    border: 1px solid #ccc;
+    background-color: #f8f8f8;
+}
+
+pre a {
+    color: inherit;
+    text-decoration: underline;
+}
+
+td.linenos pre {
+    padding: 0.5em 0;
+}
+
+div.quotebar {
+    background-color: #f8f8f8;
+    max-width: 250px;
+    float: right;
+    padding: 2px 7px;
+    border: 1px solid #ccc;
+}
+
+div.topic {
+    background-color: #f8f8f8;
+}
+
+table {
+    border-collapse: collapse;
+    margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+    padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+    font-size: 0.9em;
+    margin: 1em 0 1em 0;
+    border: 1px solid #86989B;
+    background-color: #f7f7f7;
+    padding: 0;
+}
+
+div.admonition p, div.warning p {
+    margin: 0.5em 1em 0.5em 1em;
+    padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+    margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+    margin: 0;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border-bottom: 1px solid #86989B;
+    font-weight: bold;
+    background-color: #AFC1C4;
+}
+
+div.warning {
+    border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+    background-color: #CF0000;
+    border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+    margin: 0.1em 0.5em 0.5em 3em;
+    padding: 0;
+}
+
+div.versioninfo {
+    margin: 1em 0 0 0;
+    border: 1px solid #ccc;
+    background-color: #DDEAF0;
+    padding: 8px;
+    line-height: 1.3em;
+    font-size: 0.9em;
+}
+
+.viewcode-back {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
diff --git a/docs/llvm-theme/static/logo.png b/docs/llvm-theme/static/logo.png
new file mode 100644 (file)
index 0000000..4fc8990
Binary files /dev/null and b/docs/llvm-theme/static/logo.png differ
diff --git a/docs/llvm-theme/static/navigation.png b/docs/llvm-theme/static/navigation.png
new file mode 100644 (file)
index 0000000..1081dc1
Binary files /dev/null and b/docs/llvm-theme/static/navigation.png differ
diff --git a/docs/llvm-theme/theme.conf b/docs/llvm-theme/theme.conf
new file mode 100644 (file)
index 0000000..330fc92
--- /dev/null
@@ -0,0 +1,4 @@
+[theme]
+inherit = basic
+stylesheet = llvm.css
+pygments_style = friendly
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644 (file)
index 0000000..8471252
--- /dev/null
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+       set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+       set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+       set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+       :help
+       echo.Please use `make ^<target^>` where ^<target^> is one of
+       echo.  html       to make standalone HTML files
+       echo.  dirhtml    to make HTML files named index.html in directories
+       echo.  singlehtml to make a single large HTML file
+       echo.  pickle     to make pickle files
+       echo.  json       to make JSON files
+       echo.  htmlhelp   to make HTML files and a HTML help project
+       echo.  qthelp     to make HTML files and a qthelp project
+       echo.  devhelp    to make HTML files and a Devhelp project
+       echo.  epub       to make an epub
+       echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+       echo.  text       to make text files
+       echo.  man        to make manual pages
+       echo.  texinfo    to make Texinfo files
+       echo.  gettext    to make PO message catalogs
+       echo.  changes    to make an overview over all changed/added/deprecated items
+       echo.  linkcheck  to check all external links for integrity
+       echo.  doctest    to run all doctests embedded in the documentation if enabled
+       goto end
+)
+
+if "%1" == "clean" (
+       for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+       del /q /s %BUILDDIR%\*
+       goto end
+)
+
+if "%1" == "html" (
+       %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+       goto end
+)
+
+if "%1" == "dirhtml" (
+       %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+       goto end
+)
+
+if "%1" == "singlehtml" (
+       %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+       goto end
+)
+
+if "%1" == "pickle" (
+       %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can process the pickle files.
+       goto end
+)
+
+if "%1" == "json" (
+       %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can process the JSON files.
+       goto end
+)
+
+if "%1" == "htmlhelp" (
+       %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+       goto end
+)
+
+if "%1" == "qthelp" (
+       %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+       echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
+       echo.To view the help file:
+       echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
+       goto end
+)
+
+if "%1" == "devhelp" (
+       %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished.
+       goto end
+)
+
+if "%1" == "epub" (
+       %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The epub file is in %BUILDDIR%/epub.
+       goto end
+)
+
+if "%1" == "latex" (
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+       goto end
+)
+
+if "%1" == "text" (
+       %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The text files are in %BUILDDIR%/text.
+       goto end
+)
+
+if "%1" == "man" (
+       %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The manual pages are in %BUILDDIR%/man.
+       goto end
+)
+
+if "%1" == "texinfo" (
+       %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+       goto end
+)
+
+if "%1" == "gettext" (
+       %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+       goto end
+)
+
+if "%1" == "changes" (
+       %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.The overview file is in %BUILDDIR%/changes.
+       goto end
+)
+
+if "%1" == "linkcheck" (
+       %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+       goto end
+)
+
+if "%1" == "doctest" (
+       %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+       goto end
+)
+
+:end
diff --git a/docs/open_projects.rst b/docs/open_projects.rst
new file mode 100644 (file)
index 0000000..eeb9f9f
--- /dev/null
@@ -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 (file)
index 0000000..6845bc8
--- /dev/null
@@ -0,0 +1,147 @@
+.. _sphinx_intro:
+
+Sphinx Introduction for LLVM Developers
+=======================================
+
+This document is intended as a short and simple introduction to the Sphinx
+documentation generation system for LLVM developers.
+
+Quickstart
+----------
+
+To get started writing documentation, you will need to:
+
+ 1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
+
+ 2. Understand how to :ref:`build the documentation
+    <building_the_documentation>`.
+
+ 3. Start :ref:`writing documentation <writing_documentation>`!
+
+.. _installing_sphinx:
+
+Installing Sphinx
+~~~~~~~~~~~~~~~~~
+
+You should be able to install Sphinx using the standard Python package
+installation tool ``easy_install``, as follows::
+
+  $ sudo easy_install sphinx
+  Searching for sphinx
+  Reading http://pypi.python.org/simple/sphinx/
+  Reading http://sphinx.pocoo.org/
+  Best match: Sphinx 1.1.3
+  ... more lines here ..
+
+If you do not have root access (or otherwise want to avoid installing Sphinx in
+system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
+
+If you do not have the ``easy_install`` tool on your system, you should be able
+to install it using:
+
+  Linux
+    Use your distribution's standard package management tool to install it,
+    i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
+
+  Mac OS X
+    All modern Mac OS X systems come with ``easy_install`` as part of the base
+    system.
+
+  Windows
+    See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
+    page for instructions.
+
+
+.. _building_the_documentation:
+
+Building the documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to build the documentation, all you should need to do is change to the
+``docs`` directory and invoke make as follows::
+
+  $ cd path/to/project/docs
+  $ make html
+
+Note that on Windows there is a ``make.bat`` command in the docs directory which
+supplies the same interface as the ``Makefile``.
+
+That command will invoke ``sphinx-build`` with the appropriate options for the
+project, and generate the HTML documentation in a ``_build`` subdirectory. You
+can browse it starting from the index page by visiting
+``_build/html/index.html``.
+
+Sphinx supports a wide variety of generation formats (including LaTeX, man
+pages, and plain text). The ``Makefile`` includes a number of convenience
+targets for invoking ``sphinx-build`` appropriately, the common ones are:
+
+  make html
+    Generate the HTML output.
+
+  make latexpdf
+    Generate LaTeX documentation and convert to a PDF.
+
+  make man
+    Generate man pages.
+
+
+.. _writing_documentation:
+
+Writing documentation
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation itself is written in the reStructuredText (ReST) format, and Sphinx
+defines additional tags to support features like cross-referencing.
+
+The ReST format itself is organized around documents mostly being readable
+plaintext documents. You should generally be able to write new documentation
+easily just by following the style of the existing documentation.
+
+If you want to understand the formatting of the documents more, the best place
+to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
+
+
+Learning More
+-------------
+
+If you want to learn more about the Sphinx system, the best place to start is
+the Sphinx documentation itself, available `here
+<http://sphinx.pocoo.org/contents.html>`_.
+
+
+.. _installing_sphinx_in_a_venv:
+
+Installing Sphinx in a Virtual Environment
+------------------------------------------
+
+Most Python developers prefer to work with tools inside a *virtualenv* (virtual
+environment) instance, which functions as an application sandbox. This avoids
+polluting your system installation with different packages used by various
+projects (and ensures that dependencies for different packages don't conflict
+with one another). Of course, you need to first have the virtualenv software
+itself which generally would be installed at the system level::
+
+  $ sudo easy_install virtualenv
+
+but after that you no longer need to install additional packages in the system
+directories.
+
+Once you have the *virtualenv* tool itself installed, you can create a
+virtualenv for Sphinx using::
+
+  $ virtualenv ~/my-sphinx-install
+  New python executable in /Users/dummy/my-sphinx-install/bin/python
+  Installing setuptools............done.
+  Installing pip...............done.
+
+  $ ~/my-sphinx-install/bin/easy_install sphinx
+  ... install messages here ...
+
+and from now on you can "activate" the *virtualenv* using::
+
+  $ source ~/my-sphinx-install/bin/activate
+
+which will change your PATH to ensure the sphinx-build tool from inside the
+virtual environment will be used. See the `virtualenv website
+<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
+virtual environments.
diff --git a/docs/windows_support.rst b/docs/windows_support.rst
new file mode 100644 (file)
index 0000000..c4c338a
--- /dev/null
@@ -0,0 +1,97 @@
+.. raw:: html
+
+  <style type="text/css">
+    .none { background-color: #FFCCCC }
+    .partial { background-color: #FFFF99 }
+    .good { background-color: #CCFF99 }
+  </style>
+
+.. role:: none
+.. role:: partial
+.. role:: good
+
+===============
+Windows support
+===============
+
+LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with
+``-flavor link``, the driver for Windows operating system is used to parse
+command line options, and it drives further linking processes. LLD accepts
+almost all command line options that the linker shipped with Microsoft Visual
+C++ (link.exe) supports.
+
+The current status is that LLD 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.
+  Options for Windows 8 app store are not recognized too
+  (e.g. ``/APPCONTAINER``).
+
+Linking against DLL
+  :good:`Done`. LLD can read import libraries needed to link against DLL. Both
+  export-by-name and export-by-ordinal are supported.
+
+Linking against static library
+  :good:`Done`. The format of static library (.lib) on Windows is actually the
+  same as on Unix (.a). LLD can read it.
+
+Creating DLL
+  :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported
+  functions can be specified either via command line (``/EXPORT``) or via
+  module-definition file (.def). Both export-by-name and export-by-ordinal are
+  supported. LLD uses Microsoft ``lib.exe`` tool to create an import library
+  file.
+
+Windows resource files support
+  :good:`Done`. If an ``.rc`` file is given, LLD converts the file to a COFF
+  file using some external commands and link it. Specifically, ``rc.exe`` is
+  used to compile a resource file (.rc) to a compiled resource (.res)
+  file. ``rescvt.exe`` is then used to convert a compiled resource file to a
+  COFF object file section. Both tools are shipped with MSVC.
+
+Safe Structured Exception Handler (SEH)
+  :good:`Done` for 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" <llvm-source-dir>`` from VS command prompt,
+#. open LLVM.sln with Visual Studio, and
+#. build ``lld`` target in ``lld executables`` folder
+
+Alternatively, you can use msbuild if you don't like to work in an IDE::
+
+  msbuild LLVM.sln /m /target:"lld executables\lld"
+  
+MSBuild.exe had been shipped as a component of the .NET framework, but since
+2013 it's part of Visual Studio. You can find it at "C:\\Program Files
+(x86)\\msbuild".
+
+You can build LLD as a 64 bit application. To do that, open VS2013 x64 command
+prompt and run cmake for "Visual Studio 12 Win64" target.
+
+Using Ninja
+-----------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G ninja <llvm-source-dir>`` from VS command prompt,
+#. run ``ninja lld``
diff --git a/include/lld/Config/Version.h b/include/lld/Config/Version.h
new file mode 100644 (file)
index 0000000..41433c1
--- /dev/null
@@ -0,0 +1,51 @@
+//===- lld/Config/Version.h - LLD Version Number ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines version macros and version-related utility functions
+/// for lld.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_VERSION_H
+#define LLD_VERSION_H
+
+#include "lld/Config/Version.inc"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+/// \brief Helper macro for LLD_VERSION_STRING.
+#define LLD_MAKE_VERSION_STRING2(X) #X
+
+/// \brief Helper macro for LLD_VERSION_STRING.
+#define LLD_MAKE_VERSION_STRING(X, Y) LLD_MAKE_VERSION_STRING2(X.Y)
+
+/// \brief A string that describes the lld version number, e.g., "1.0".
+#define LLD_VERSION_STRING                                                     \
+  LLD_MAKE_VERSION_STRING(LLD_VERSION_MAJOR, LLD_VERSION_MINOR)
+
+namespace lld {
+/// \brief Retrieves the repository path (e.g., Subversion path) that
+/// identifies the particular lld branch, tag, or trunk from which this
+/// lld was built.
+llvm::StringRef getLLDRepositoryPath();
+
+/// \brief Retrieves the repository revision number (or identifer) from which
+/// this lld was built.
+llvm::StringRef getLLDRevision();
+
+/// \brief Retrieves the full repository version that is an amalgamation of
+/// the information in getLLDRepositoryPath() and getLLDRevision().
+std::string getLLDRepositoryVersion();
+
+/// \brief Retrieves a string representing the complete lld version.
+llvm::StringRef getLLDVersion();
+}
+
+#endif // LLD_VERSION_H
diff --git a/include/lld/Config/Version.inc.in b/include/lld/Config/Version.inc.in
new file mode 100644 (file)
index 0000000..c893a56
--- /dev/null
@@ -0,0 +1,5 @@
+#define LLD_VERSION @LLD_VERSION@
+#define LLD_VERSION_MAJOR @LLD_VERSION_MAJOR@
+#define LLD_VERSION_MINOR @LLD_VERSION_MINOR@
+#define LLD_REVISION_STRING "@LLD_REVISION@"
+#define LLD_REPOSITORY_STRING "@LLD_REPOSITORY@"
diff --git a/include/lld/Core/AbsoluteAtom.h b/include/lld/Core/AbsoluteAtom.h
new file mode 100644 (file)
index 0000000..ed25297
--- /dev/null
@@ -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 (file)
index 0000000..2c736e7
--- /dev/null
@@ -0,0 +1,47 @@
+//===- Core/ArchiveLibraryFile.h - Models static library ------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+#include <set>
+
+namespace lld {
+
+///
+/// The ArchiveLibraryFile subclass of File is used to represent unix
+/// static library archives.  These libraries provide no atoms to the
+/// initial set of atoms linked.  Instead, when the Resolver will query
+/// ArchiveLibraryFile instances for specific symbols names using the
+/// find() method.  If the archive contains an object file which has a
+/// DefinedAtom whose scope is not translationUnit, then that entire
+/// object file File is returned.
+///
+class ArchiveLibraryFile : public File {
+public:
+  static bool classof(const File *f) {
+    return f->kind() == kindArchiveLibrary;
+  }
+
+  /// Check if any member of the archive contains an Atom with the
+  /// specified name and return the File object for that member, or nullptr.
+  virtual File *find(StringRef name) = 0;
+
+  virtual std::error_code
+  parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
+
+protected:
+  /// only subclasses of ArchiveLibraryFile can be instantiated
+  ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H
diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h
new file mode 100644 (file)
index 0000000..42ca2bb
--- /dev/null
@@ -0,0 +1,129 @@
+//===- Core/Atom.h - A node in linking graph ------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ATOM_H
+#define LLD_CORE_ATOM_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+
+class File;
+
+template<typename T>
+class OwningAtomPtr;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms.  Each Atom is a node
+/// and each Reference is an edge. An Atom can be a DefinedAtom which has
+/// content or a UndefinedAtom which is a placeholder and represents an
+/// undefined symbol (extern declaration).
+///
+class Atom {
+  template<typename T> friend class OwningAtomPtr;
+public:
+  /// Whether this atom is defined or a proxy for an undefined symbol
+  enum Definition {
+    definitionRegular,      ///< Normal C/C++ function or global variable.
+    definitionAbsolute,     ///< Asm-only (foo = 10). Not tied to any content.
+    definitionUndefined,    ///< Only in .o files to model reference to undef.
+    definitionSharedLibrary ///< Only in shared libraries to model export.
+  };
+
+  /// The scope in which this atom is acessible to other atoms.
+  enum Scope {
+    scopeTranslationUnit,  ///< Accessible only to atoms in the same translation
+                           ///  unit (e.g. a C static).
+    scopeLinkageUnit,      ///< Accessible to atoms being linked but not visible
+                           ///  to runtime loader (e.g. visibility=hidden).
+    scopeGlobal            ///< Accessible to all atoms and visible to runtime
+                           ///  loader (e.g. visibility=default).
+  };
+
+
+  /// file - returns the File that produced/owns this Atom
+  virtual const File& file() const = 0;
+
+  /// name - The name of the atom. For a function atom, it is the (mangled)
+  /// name of the function.
+  virtual StringRef name() const = 0;
+
+  /// definition - Whether this atom is a definition or represents an undefined
+  /// symbol.
+  Definition definition() const { return _definition; }
+
+  static bool classof(const Atom *a) { return true; }
+
+protected:
+  /// Atom is an abstract base class.  Only subclasses can access constructor.
+  explicit Atom(Definition def) : _definition(def) {}
+
+  /// The memory for Atom objects is always managed by the owning File
+  /// object.  Therefore, no one but the owning File object should call
+  /// delete on an Atom.  In fact, some File objects may bulk allocate
+  /// an array of Atoms, so they cannot be individually deleted by anyone.
+  virtual ~Atom() {}
+
+private:
+  Definition _definition;
+};
+
+/// Class which owns an atom pointer and runs the atom destructor when the
+/// owning pointer goes out of scope.
+template<typename T>
+class OwningAtomPtr {
+private:
+  OwningAtomPtr(const OwningAtomPtr &) = delete;
+  void operator=(const OwningAtomPtr&) = delete;
+public:
+  OwningAtomPtr() : atom(nullptr) { }
+  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;
+};
+
+} // 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 (file)
index 0000000..e3193f8
--- /dev/null
@@ -0,0 +1,378 @@
+//===- 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() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global
+///
+///  C static function:  staic void func() {} <br>
+///    name=func, type=code, perm=r_x
+///
+///  C global variable:  int count = 1; <br>
+///    name=count, type=data, perm=rw_, scope=global
+///
+///  C tentative definition:  int bar; <br>
+///    name=bar, type=zerofill, perm=rw_, scope=global,
+///    merge=asTentative, interposable=yesAndRuntimeWeak
+///
+///  Uninitialized C static variable:  static int stuff; <br>
+///    name=stuff, type=zerofill, perm=rw_
+///
+///  Weak C function:  __attribute__((weak)) void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global, merge=asWeak
+///
+///  Hidden C function:  __attribute__((visibility("hidden"))) void foo() {}<br>
+///    name=foo, type=code, perm=r_x, scope=linkageUnit
+///
+///  No-dead-strip function:  __attribute__((used)) void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global, deadStrip=never
+///
+///  Non-inlined C++ inline method:  inline void Foo::doit() {} <br>
+///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+///    mergeDupes=asWeak
+///
+///  Non-inlined C++ inline method whose address is taken:
+///     inline void Foo::doit() {} <br>
+///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+///    mergeDupes=asAddressedWeak
+///
+///  literal c-string:  "hello" <br>
+///    name="" type=cstring, perm=r__, scope=linkageUnit
+///
+///  literal double:  1.234 <br>
+///    name="" type=literal8, perm=r__, scope=linkageUnit
+///
+///  constant:  { 1,2,3 } <br>
+///    name="" type=constant, perm=r__, scope=linkageUnit
+///
+///  Pointer to initializer function:  <br>
+///    name="" type=initializer, perm=rw_l,
+///    sectionChoice=customRequired
+///
+///  C function place in custom section:  __attribute__((section("__foo")))
+///                                       void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global,
+///    sectionChoice=customRequired, customSectionName=__foo
+///
+class DefinedAtom : public Atom {
+public:
+  enum Interposable {
+    interposeNo,            // linker can directly bind uses of this atom
+    interposeYes,           // linker must indirect (through GOT) uses
+    interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
+                               // linked image
+  };
+
+  enum Merge {
+    mergeNo,                // Another atom with same name is error
+    mergeAsTentative,       // Is ANSI C tentative definition, can be coalesced
+    mergeAsWeak,            // Is C++ inline definition that was not inlined,
+                            // but address was not taken, so atom can be hidden
+                            // by linker
+    mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
+                               // address was taken.
+    mergeSameNameAndSize,   // Another atom with different size is error
+    mergeByLargestSection,  // Choose an atom whose section is the largest.
+    mergeByContent,         // Merge with other constants with same content.
+  };
+
+  enum ContentType {
+    typeUnknown,            // for use with definitionUndefined
+    typeMachHeader,         // atom representing mach_header [Darwin]
+    typeCode,               // executable code
+    typeResolver,           // function which returns address of target
+    typeBranchIsland,       // linker created for large binaries
+    typeBranchShim,         // linker created to switch thumb mode
+    typeStub,               // linker created for calling external function
+    typeStubHelper,         // linker created for initial stub binding
+    typeConstant,           // a read-only constant
+    typeCString,            // a zero terminated UTF8 C string
+    typeUTF16String,        // a zero terminated UTF16 string
+    typeCFI,                // a FDE or CIE from dwarf unwind info
+    typeLSDA,               // extra unwinding info
+    typeLiteral4,           // a four-btye read-only constant
+    typeLiteral8,           // an eight-btye read-only constant
+    typeLiteral16,          // a sixteen-btye read-only constant
+    typeData,               // read-write data
+    typeDataFast,           // allow data to be quickly accessed
+    typeZeroFill,           // zero-fill data
+    typeZeroFillFast,       // allow zero-fill data to be quicky accessed
+    typeConstData,          // read-only data after dynamic linker is done
+    typeObjC1Class,         // ObjC1 class [Darwin]
+    typeLazyPointer,        // pointer through which a stub jumps
+    typeLazyDylibPointer,   // pointer through which a stub jumps [Darwin]
+    typeNonLazyPointer,     // pointer to external symbol
+    typeCFString,           // NS/CFString object [Darwin]
+    typeGOT,                // pointer to external symbol
+    typeInitializerPtr,     // pointer to initializer function
+    typeTerminatorPtr,      // pointer to terminator function
+    typeCStringPtr,         // pointer to UTF8 C string [Darwin]
+    typeObjCClassPtr,       // pointer to ObjC class [Darwin]
+    typeObjC2CategoryList,  // pointers to ObjC category [Darwin]
+    typeObjCImageInfo,      // pointer to ObjC class [Darwin]
+    typeObjCMethodList,     // pointer to ObjC method list [Darwin]
+    typeDTraceDOF,          // runtime data for Dtrace [Darwin]
+    typeInterposingTuples,  // tuples of interposing info for dyld [Darwin]
+    typeTempLTO,            // temporary atom for bitcode reader
+    typeCompactUnwindInfo,  // runtime data for unwinder [Darwin]
+    typeProcessedUnwindInfo,// compressed compact unwind info [Darwin]
+    typeThunkTLV,           // thunk used to access a TLV [Darwin]
+    typeTLVInitialData,     // initial data for a TLV [Darwin]
+    typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
+    typeTLVInitializerPtr,  // pointer to thread local initializer [Darwin]
+    typeDSOHandle,          // atom representing DSO handle [Darwin]
+    typeSectCreate,         // Created via the -sectcreate option [Darwin]
+  };
+
+  // Permission bits for atoms and segments. The order of these values are
+  // important, because the layout pass may sort atoms by permission if other
+  // attributes are the same.
+  enum ContentPermissions {
+    perm___  = 0,           // mapped as unaccessible
+    permR__  = 8,           // mapped read-only
+    permRW_  = 8 + 2,       // mapped readable and writable
+    permRW_L = 8 + 2 + 1,   // initially mapped r/w, then made read-only
+                            // loader writable
+    permR_X  = 8 + 4,       // mapped readable and executable
+    permRWX  = 8 + 2 + 4,   // mapped readable and writable and executable
+    permUnknown = 16        // unknown or invalid permissions
+  };
+
+  enum SectionChoice {
+    sectionBasedOnContent,  // linker infers final section based on content
+    sectionCustomPreferred, // linker may place in specific section
+    sectionCustomRequired   // linker must place in specific section
+  };
+
+  enum DeadStripKind {
+    deadStripNormal,        // linker may dead strip this atom
+    deadStripNever,         // linker must never dead strip this atom
+    deadStripAlways         // linker must remove this atom if unused
+  };
+
+  enum DynamicExport {
+    /// \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<uint8_t> rawContent() const = 0;
+
+  /// This class abstracts iterating over the sequence of References
+  /// in an Atom.  Concrete instances of DefinedAtom must implement
+  /// the derefIterator() and incrementIterator() methods.
+  class reference_iterator {
+  public:
+    reference_iterator(const DefinedAtom &a, const void *it)
+      : _atom(a), _it(it) { }
+
+    const Reference *operator*() const {
+      return _atom.derefIterator(_it);
+    }
+
+    const Reference *operator->() const {
+      return _atom.derefIterator(_it);
+    }
+
+    bool operator==(const reference_iterator &other) const {
+      return _it == other._it;
+    }
+
+    bool operator!=(const reference_iterator &other) const {
+      return !(*this == other);
+    }
+
+    reference_iterator &operator++() {
+      _atom.incrementIterator(_it);
+      return *this;
+    }
+  private:
+    const DefinedAtom &_atom;
+    const void *_it;
+  };
+
+  /// \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;
+  }
+
+  // Returns true if lhs should be placed before rhs in the final output.
+  static bool compareByPosition(const DefinedAtom *lhs,
+                                const DefinedAtom *rhs);
+
+protected:
+  // DefinedAtom is an abstract base class. Only subclasses can access
+  // constructor.
+  DefinedAtom() : Atom(definitionRegular) { }
+
+  ~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 (file)
index 0000000..b0bf73b
--- /dev/null
@@ -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 <system_error>
+
+namespace lld {
+
+const std::error_category &YamlReaderCategory();
+
+enum class YamlReaderError {
+  unknown_keyword,
+  illegal_value
+};
+
+inline std::error_code make_error_code(YamlReaderError e) {
+  return std::error_code(static_cast<int>(e), YamlReaderCategory());
+}
+
+/// Creates an error_code object that has associated with it an arbitrary
+/// error messsage.  The value() of the error_code will always be non-zero
+/// but its value is meaningless. The messsage() will be (a copy of) the
+/// supplied error string.
+/// Note:  Once ErrorOr<> is updated to work with errors other than error_code,
+/// this can be updated to return some other kind of error.
+std::error_code make_dynamic_error_code(StringRef msg);
+
+/// Generic error.
+///
+/// For errors that don't require their own specific sub-error (most errors)
+/// this class can be used to describe the error via a string message.
+class GenericError : public llvm::ErrorInfo<GenericError> {
+public:
+  static char ID;
+  GenericError(Twine Msg);
+  const std::string &getMessage() const { return Msg; }
+  void log(llvm::raw_ostream &OS) const override;
+
+  std::error_code convertToErrorCode() const override {
+    return make_dynamic_error_code(getMessage());
+  }
+
+private:
+  std::string Msg;
+};
+
+} // end namespace lld
+
+namespace std {
+template <> struct is_error_code_enum<lld::YamlReaderError> : std::true_type {};
+}
+
+#endif
diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h
new file mode 100644 (file)
index 0000000..2041868
--- /dev/null
@@ -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 <functional>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace lld {
+
+class LinkingContext;
+
+/// Every Atom is owned by some File. A common scenario is for a single
+/// object file (.o) to be parsed by some reader and produce a single
+/// File object that represents the content of that object file.
+///
+/// To iterate through the Atoms in a File there are four methods that
+/// return collections.  For instance to iterate through all the DefinedAtoms
+/// in a File object use:
+///      for (const DefinedAtoms *atom : file->defined()) {
+///      }
+///
+/// The Atom objects in a File are owned by the File object.  The Atom objects
+/// are destroyed when the File object is destroyed.
+class File {
+public:
+  virtual ~File();
+
+  /// \brief Kinds of files that are supported.
+  enum Kind {
+    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 <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>;
+
+  /// The range type for the atoms.
+  template <typename T> class AtomRange {
+  public:
+    AtomRange(AtomVector<T> &v) : _v(v) {}
+    AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
+
+    typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&,
+                                           const T*> ConstDerefFn;
+
+    typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn;
+
+    typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
+                                  ConstDerefFn> ConstItTy;
+    typedef llvm::mapped_iterator<typename AtomVector<T>::iterator,
+                                  DerefFn> ItTy;
+
+    static const T* DerefConst(const OwningAtomPtr<T> &p) {
+      return p.get();
+    }
+
+    static T* Deref(OwningAtomPtr<T> &p) {
+      return p.get();
+    }
+
+    ConstItTy begin() const {
+      return ConstItTy(_v.begin(), ConstDerefFn(DerefConst));
+    }
+    ConstItTy end() const {
+      return ConstItTy(_v.end(), ConstDerefFn(DerefConst));
+    }
+
+    ItTy begin() {
+      return ItTy(_v.begin(), DerefFn(Deref));
+    }
+    ItTy end() {
+      return ItTy(_v.end(), DerefFn(Deref));
+    }
+
+    llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() {
+      return llvm::make_range(_v.begin(), _v.end());
+    }
+
+    llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const {
+      return llvm::make_range(_v.begin(), _v.end());
+    }
+
+    bool empty() const {
+      return _v.empty();
+    }
+
+    size_t size() const {
+      return _v.size();
+    }
+
+    const OwningAtomPtr<T> &operator[](size_t idx) const {
+      return _v[idx];
+    }
+
+    OwningAtomPtr<T> &operator[](size_t idx) {
+      return _v[idx];
+    }
+
+  private:
+    AtomVector<T> &_v;
+  };
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all DefinedAtoms in this File.
+  virtual const AtomRange<DefinedAtom> defined() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all UndefinedAtomw in this File.
+  virtual const AtomRange<UndefinedAtom> undefined() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all SharedLibraryAtoms in this File.
+  virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all AbsoluteAtoms in this File.
+  virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
+
+  /// Drop all of the atoms owned by this file.  This will result in all of
+  /// the atoms running their destructors.
+  /// This is required because atoms may be allocated on a BumpPtrAllocator
+  /// of a different file.  We need to destruct all atoms before any files.
+  virtual void clearAtoms() = 0;
+
+  /// \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<MemoryBuffer>.
+  // However, there's one special case. If a file is an archive file,
+  // the archive file and its children all shares the same memory buffer.
+  // This method is used by the ArchiveFile to give its children
+  // co-ownership of the buffer.
+  void setSharedMemoryBuffer(std::shared_ptr<MemoryBuffer> mb) {
+    _sharedMemoryBuffer = mb;
+  }
+
+protected:
+  /// \brief only subclasses of File can be instantiated
+  File(StringRef p, Kind kind)
+    : _path(p), _kind(kind), _ordinal(UINT64_MAX),
+      _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<DefinedAtom> _noDefinedAtoms;
+  static AtomVector<UndefinedAtom> _noUndefinedAtoms;
+  static AtomVector<SharedLibraryAtom> _noSharedLibraryAtoms;
+  static AtomVector<AbsoluteAtom> _noAbsoluteAtoms;
+  mutable llvm::BumpPtrAllocator _allocator;
+
+private:
+  StringRef _path;
+  std::string _archivePath;
+  mutable std::string _archiveMemberPath;
+  Kind              _kind;
+  mutable uint64_t  _ordinal;
+  mutable uint64_t _nextAtomOrdinal;
+  std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
+  llvm::Optional<std::error_code> _lastError;
+  std::mutex _parseMutex;
+};
+
+/// An ErrorFile represents a file that doesn't exist.
+/// If you try to parse a file which doesn't exist, an instance of this
+/// class will be returned. That's parse method always returns an error.
+/// This is useful to delay erroring on non-existent files, so that we
+/// can do unit testing a driver using non-existing file paths.
+class ErrorFile : public File {
+public:
+  ErrorFile(StringRef path, std::error_code ec)
+      : File(path, kindErrorObject), _ec(ec) {}
+
+  std::error_code doParse() override { return _ec; }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    llvm_unreachable("internal error");
+  }
+
+  void clearAtoms() override {
+  }
+
+private:
+  std::error_code _ec;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h
new file mode 100644 (file)
index 0000000..1623759
--- /dev/null
@@ -0,0 +1,132 @@
+//===- include/Core/Instrumentation.h - Instrumentation API ---------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_INSTRUMENTATION_H
+#define LLD_CORE_INSTRUMENTATION_H
+
+#include "llvm/Support/Compiler.h"
+#include <utility>
+
+#ifdef LLD_HAS_VTUNE
+# include <ittnotify.h>
+#endif
+
+namespace lld {
+#ifdef LLD_HAS_VTUNE
+/// \brief A unique global scope for instrumentation data.
+///
+/// Domains last for the lifetime of the application and cannot be destroyed.
+/// Multiple Domains created with the same name represent the same domain.
+class Domain {
+  __itt_domain *_domain;
+
+public:
+  explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {}
+
+  operator __itt_domain *() const { return _domain; }
+  __itt_domain *operator->() const { return _domain; }
+};
+
+/// \brief A global reference to a string constant.
+///
+/// These are uniqued by the ITT runtime and cannot be deleted. They are not
+/// specific to a domain.
+///
+/// Prefer reusing a single StringHandle over passing a ntbs when the same
+/// string will be used often.
+class StringHandle {
+  __itt_string_handle *_handle;
+
+public:
+  StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {}
+
+  operator __itt_string_handle *() const { return _handle; }
+};
+
+/// \brief A task on a single thread. Nests within other tasks.
+///
+/// Each thread has its own task stack and tasks nest recursively on that stack.
+/// A task cannot transfer threads.
+///
+/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of
+/// a task is either the lifetime of this object, or until end is called.
+class ScopedTask {
+  __itt_domain *_domain;
+
+  ScopedTask(const ScopedTask &) = delete;
+  ScopedTask &operator=(const ScopedTask &) = delete;
+
+public:
+  /// \brief Create a task in Domain \p d named \p s.
+  ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
+    __itt_task_begin(d, __itt_null, __itt_null, s);
+  }
+
+  ScopedTask(ScopedTask &&other) {
+    *this = std::move(other);
+  }
+
+  ScopedTask &operator=(ScopedTask &&other) {
+    _domain = other._domain;
+    other._domain = nullptr;
+    return *this;
+  }
+
+  /// \brief Prematurely end this task.
+  void end() {
+    if (_domain)
+      __itt_task_end(_domain);
+    _domain = nullptr;
+  }
+
+  ~ScopedTask() { end(); }
+};
+
+/// \brief A specific point in time. Allows metadata to be associated.
+class Marker {
+public:
+  Marker(const Domain &d, const StringHandle &s) {
+    __itt_marker(d, __itt_null, s, __itt_scope_global);
+  }
+};
+#else
+class Domain {
+public:
+  Domain(const char *name) {}
+};
+
+class StringHandle {
+public:
+  StringHandle(const char *name) {}
+};
+
+class ScopedTask {
+public:
+  ScopedTask(const Domain &d, const StringHandle &s) {}
+  void end() {}
+};
+
+class Marker {
+public:
+  Marker(const Domain &d, const StringHandle &s) {}
+};
+#endif
+
+inline const Domain &getDefaultDomain() {
+  static Domain domain("org.llvm.lld");
+  return domain;
+}
+} // end namespace lld.
+
+#endif
diff --git a/include/lld/Core/LLVM.h b/include/lld/Core/LLVM.h
new file mode 100644 (file)
index 0000000..ccf0885
--- /dev/null
@@ -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 <utility>
+
+namespace llvm {
+  // ADT's.
+  class Error;
+  class StringRef;
+  class Twine;
+  class MemoryBuffer;
+  class MemoryBufferRef;
+  template<typename T> class ArrayRef;
+  template<unsigned InternalLen> class SmallString;
+  template<typename T, unsigned N> class SmallVector;
+  template<typename T> class SmallVectorImpl;
+
+  template<typename T>
+  struct SaveAndRestore;
+
+  template<typename T>
+  class ErrorOr;
+
+  template<typename T>
+  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<llvm::StringRef> {
+public:
+  size_t operator()(const llvm::StringRef &s) const {
+    return llvm::hash_value(s);
+  }
+};
+}
+
+#endif
diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h
new file mode 100644 (file)
index 0000000..7e4edaf
--- /dev/null
@@ -0,0 +1,251 @@
+//===- lld/Core/LinkingContext.h - Linker Target Info Interface -----------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_LINKING_CONTEXT_H
+#define LLD_CORE_LINKING_CONTEXT_H
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Reader.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+namespace lld {
+class PassManager;
+class File;
+class Writer;
+class Node;
+class SharedLibraryFile;
+
+/// \brief The LinkingContext class encapsulates "what and how" to link.
+///
+/// The base class LinkingContext contains the options needed by core linking.
+/// Subclasses of LinkingContext have additional options needed by specific
+/// Writers.
+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<StringRef> &deadStripRoots() const {
+    return _deadStripRoots;
+  }
+
+  /// Add the given symbol name to the dead strip root set. Only used if
+  /// deadStrip() returns true.
+  void addDeadStripRoot(StringRef symbolName) {
+    assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
+    _deadStripRoots.push_back(symbolName);
+  }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking prints out a list of remaining UndefinedAtoms.
+  ///
+  /// \todo This should be a method core linking calls with a list of the
+  /// UndefinedAtoms so that different drivers can format the error message
+  /// as needed.
+  bool printRemainingUndefines() const { return _printRemainingUndefines; }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking considers remaining undefines to be an error.
+  bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking considers remaining undefines from the shared library
+  /// to be an error.
+  bool allowShlibUndefines() const { return _allowShlibUndefines; }
+
+  /// If true, core linking will write the path to each input file to stdout
+  /// (i.e. llvm::outs()) as it is used.  This is used to implement the -t
+  /// linker option.
+  ///
+  /// \todo This should be a method core linking calls so that drivers can
+  /// format the line as needed.
+  bool logInputFiles() const { return _logInputFiles; }
+
+  /// Parts of LLVM use global variables which are bound to command line
+  /// options (see llvm::cl::Options). This method returns "command line"
+  /// options which are used to configure LLVM's command line settings.
+  /// For instance the -debug-only XXX option can be used to dynamically
+  /// trace different parts of LLVM and lld.
+  const std::vector<const char *> &llvmOptions() const { return _llvmOptions; }
+
+  /// \name Methods used by Drivers to configure TargetInfo
+  /// @{
+  void setOutputPath(StringRef str) { _outputPath = str; }
+
+  // Set the entry symbol name. You may also need to call addDeadStripRoot() for
+  // the symbol if your platform supports dead-stripping, so that the symbol
+  // will not be removed from the output.
+  void setEntrySymbolName(StringRef name) {
+    _entrySymbolName = name;
+  }
+
+  void setDeadStripping(bool enable) { _deadStrip = enable; }
+  void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
+  void setPrintRemainingUndefines(bool print) {
+    _printRemainingUndefines = print;
+  }
+  void setAllowRemainingUndefines(bool allow) {
+    _allowRemainingUndefines = allow;
+  }
+  void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
+  void setLogInputFiles(bool log) { _logInputFiles = log; }
+
+  void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
+
+  std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; }
+  const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; }
+
+  /// This method adds undefined symbols specified by the -u option to the to
+  /// the list of undefined symbols known to the linker. This option essentially
+  /// forces an undefined symbol to be created. You may also need to call
+  /// addDeadStripRoot() for the symbol if your platform supports dead
+  /// stripping, so that the symbol will not be removed from the output.
+  void addInitialUndefinedSymbol(StringRef symbolName) {
+    _initialUndefinedSymbols.push_back(symbolName);
+  }
+
+  /// Iterators for symbols that appear on the command line.
+  typedef std::vector<StringRef> StringRefVector;
+  typedef StringRefVector::iterator StringRefVectorIter;
+  typedef StringRefVector::const_iterator StringRefVectorConstIter;
+
+  /// Create linker internal files containing atoms for the linker to include
+  /// during link. Flavors can override this function in their LinkingContext
+  /// to add more internal files. These internal files are positioned before
+  /// the actual input files.
+  virtual void createInternalFiles(std::vector<std::unique_ptr<File> > &) const;
+
+  /// Return the list of undefined symbols that are specified in the
+  /// linker command line, using the -u option.
+  ArrayRef<StringRef> initialUndefinedSymbols() const {
+    return _initialUndefinedSymbols;
+  }
+
+  /// After all set* methods are called, the Driver calls this method
+  /// to validate that there are no missing options or invalid combinations
+  /// of options.  If there is a problem, a description of the problem
+  /// is written to the 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 &registry() const { return _registry; }
+  Registry &registry() { return _registry; }
+
+  /// This method is called by core linking to give the Writer a chance
+  /// to add file format specific "files" to set of files to be linked. This is
+  /// how file format specific atoms can be added to the link.
+  virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) = 0;
+
+  /// This method is called by core linking to build the list of Passes to be
+  /// run on the merged/linked graph of all input files.
+  virtual void addPasses(PassManager &pm) = 0;
+
+  /// Calls through to the writeFile() method on the specified Writer.
+  ///
+  /// \param linkedFile This is the merged/linked graph of all input file Atoms.
+  virtual llvm::Error writeFile(const File &linkedFile) const;
+
+  /// Return the next ordinal and Increment it.
+  virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
+
+  // This function is called just before the Resolver kicks in.
+  // Derived classes may use it to change the list of input files.
+  virtual void finalizeInputFiles() = 0;
+
+  /// Callback invoked for each file the Resolver decides we are going to load.
+  /// This can be used to update context state based on the file, and emit
+  /// errors for any differences between the context state and a loaded file.
+  /// For example, we can error if we try to load a file which is a different
+  /// arch from that being linked.
+  virtual llvm::Error handleLoadedFile(File &file) = 0;
+
+  /// @}
+protected:
+  LinkingContext(); // Must be subclassed
+
+  /// Abstract method to lazily instantiate the Writer.
+  virtual Writer &writer() const = 0;
+
+  /// Method to create an internal file for the entry symbol
+  virtual std::unique_ptr<File> createEntrySymbolFile() const;
+  std::unique_ptr<File> createEntrySymbolFile(StringRef filename) const;
+
+  /// Method to create an internal file for an undefined symbol
+  virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
+  std::unique_ptr<File> createUndefinedSymbolFile(StringRef filename) const;
+
+  StringRef _outputPath;
+  StringRef _entrySymbolName;
+  bool _deadStrip = false;
+  bool _globalsAreDeadStripRoots = false;
+  bool _printRemainingUndefines = true;
+  bool _allowRemainingUndefines = false;
+  bool _logInputFiles = false;
+  bool _allowShlibUndefines = false;
+  std::vector<StringRef> _deadStripRoots;
+  std::vector<const char *> _llvmOptions;
+  StringRefVector _initialUndefinedSymbols;
+  std::vector<std::unique_ptr<Node>> _nodes;
+  mutable llvm::BumpPtrAllocator _allocator;
+  mutable uint64_t _nextOrdinal = 0;
+  Registry _registry;
+
+private:
+  /// Validate the subclass bits. Only called by validate.
+  virtual bool validateImpl(raw_ostream &diagnostics) = 0;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h
new file mode 100644 (file)
index 0000000..8de0ecd
--- /dev/null
@@ -0,0 +1,74 @@
+//===- lld/Core/Node.h - Input file class ---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// The classes in this file represents inputs to the linker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_NODE_H
+#define LLD_CORE_NODE_H
+
+#include "lld/Core/File.h"
+#include "llvm/Option/ArgList.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+
+// A Node represents a FileNode or other type of Node. In the latter case,
+// the node contains meta information about the input file list.
+// Currently only GroupEnd node is defined as a meta node.
+class Node {
+public:
+  enum class Kind { File, GroupEnd };
+  explicit Node(Kind type) : _kind(type) {}
+  virtual ~Node() {}
+  virtual Kind kind() const { return _kind; }
+
+private:
+  Kind _kind;
+};
+
+// This is a marker for --end-group. getSize() returns the number of
+// files between the corresponding --start-group and this marker.
+class GroupEnd : public Node {
+public:
+  explicit GroupEnd(int size) : Node(Kind::GroupEnd), _size(size) {}
+
+  int getSize() const { return _size; }
+
+  static bool classof(const Node *a) {
+    return a->kind() == Kind::GroupEnd;
+  }
+
+private:
+  int _size;
+};
+
+// A container of File.
+class FileNode : public Node {
+public:
+  explicit FileNode(std::unique_ptr<File> f)
+      : Node(Node::Kind::File), _file(std::move(f)) {}
+
+  static bool classof(const Node *a) {
+    return a->kind() == Node::Kind::File;
+  }
+
+  File *getFile() { return _file.get(); }
+
+protected:
+  std::unique_ptr<File> _file;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_NODE_H
diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h
new file mode 100644 (file)
index 0000000..2dde97d
--- /dev/null
@@ -0,0 +1,297 @@
+//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PARALLEL_H
+#define LLD_CORE_PARALLEL_H
+
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/thread.h"
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <stack>
+
+#if defined(_MSC_VER) && LLVM_ENABLE_THREADS
+#include <concrt.h>
+#include <ppl.h>
+#endif
+
+namespace lld {
+/// \brief Allows one or more threads to wait on a potentially unknown number of
+///   events.
+///
+/// A latch starts at \p count. inc() increments this, and dec() decrements it.
+/// All calls to sync() will block while the count is not 0.
+///
+/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
+class Latch {
+  uint32_t _count;
+  mutable std::mutex _condMut;
+  mutable std::condition_variable _cond;
+
+public:
+  explicit Latch(uint32_t count = 0) : _count(count) {}
+  ~Latch() { sync(); }
+
+  void inc() {
+    std::unique_lock<std::mutex> lock(_condMut);
+    ++_count;
+  }
+
+  void dec() {
+    std::unique_lock<std::mutex> lock(_condMut);
+    if (--_count == 0)
+      _cond.notify_all();
+  }
+
+  void sync() const {
+    std::unique_lock<std::mutex> lock(_condMut);
+    _cond.wait(lock, [&] {
+      return _count == 0;
+    });
+  }
+};
+
+// Classes in this namespace are implementation details of this header.
+namespace internal {
+
+/// \brief An abstract class that takes closures and runs them asynchronously.
+class Executor {
+public:
+  virtual ~Executor() = default;
+  virtual void add(std::function<void()> func) = 0;
+};
+
+#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
+class SyncExecutor : public Executor {
+public:
+  virtual void add(std::function<void()> func) {
+    func();
+  }
+};
+
+inline Executor *getDefaultExecutor() {
+  static SyncExecutor exec;
+  return &exec;
+}
+#elif defined(_MSC_VER)
+/// \brief An Executor that runs tasks via ConcRT.
+class ConcRTExecutor : public Executor {
+  struct Taskish {
+    Taskish(std::function<void()> task) : _task(task) {}
+
+    std::function<void()> _task;
+
+    static void run(void *p) {
+      Taskish *self = static_cast<Taskish *>(p);
+      self->_task();
+      concurrency::Free(self);
+    }
+  };
+
+public:
+  virtual void add(std::function<void()> func) {
+    Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
+        new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
+  }
+};
+
+inline Executor *getDefaultExecutor() {
+  static ConcRTExecutor exec;
+  return &exec;
+}
+#else
+/// \brief An implementation of an Executor that runs closures on a thread pool
+///   in filo order.
+class ThreadPoolExecutor : public Executor {
+public:
+  explicit ThreadPoolExecutor(unsigned threadCount =
+                                  std::thread::hardware_concurrency())
+      : _stop(false), _done(threadCount) {
+    // Spawn all but one of the threads in another thread as spawning threads
+    // can take a while.
+    std::thread([&, threadCount] {
+      for (std::size_t i = 1; i < threadCount; ++i) {
+        std::thread([=] {
+          work();
+        }).detach();
+      }
+      work();
+    }).detach();
+  }
+
+  ~ThreadPoolExecutor() override {
+    std::unique_lock<std::mutex> lock(_mutex);
+    _stop = true;
+    lock.unlock();
+    _cond.notify_all();
+    // Wait for ~Latch.
+  }
+
+  void add(std::function<void()> f) override {
+    std::unique_lock<std::mutex> lock(_mutex);
+    _workStack.push(f);
+    lock.unlock();
+    _cond.notify_one();
+  }
+
+private:
+  void work() {
+    while (true) {
+      std::unique_lock<std::mutex> lock(_mutex);
+      _cond.wait(lock, [&] {
+        return _stop || !_workStack.empty();
+      });
+      if (_stop)
+        break;
+      auto task = _workStack.top();
+      _workStack.pop();
+      lock.unlock();
+      task();
+    }
+    _done.dec();
+  }
+
+  std::atomic<bool> _stop;
+  std::stack<std::function<void()>> _workStack;
+  std::mutex _mutex;
+  std::condition_variable _cond;
+  Latch _done;
+};
+
+inline Executor *getDefaultExecutor() {
+  static ThreadPoolExecutor exec;
+  return &exec;
+}
+#endif
+
+}  // namespace internal
+
+/// \brief Allows launching a number of tasks and waiting for them to finish
+///   either explicitly via sync() or implicitly on destruction.
+class TaskGroup {
+  Latch _latch;
+
+public:
+  void spawn(std::function<void()> f) {
+    _latch.inc();
+    internal::getDefaultExecutor()->add([&, f] {
+      f();
+      _latch.dec();
+    });
+  }
+
+  void sync() const { _latch.sync(); }
+};
+
+#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
+template <class RandomAccessIterator, class Comp>
+void parallel_sort(
+    RandomAccessIterator start, RandomAccessIterator end,
+    const Comp &comp = std::less<
+        typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
+  std::sort(start, end, comp);
+}
+#elif defined(_MSC_VER)
+// Use ppl parallel_sort on Windows.
+template <class RandomAccessIterator, class Comp>
+void parallel_sort(
+    RandomAccessIterator start, RandomAccessIterator end,
+    const Comp &comp = std::less<
+        typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
+  concurrency::parallel_sort(start, end, comp);
+}
+#else
+namespace detail {
+const ptrdiff_t minParallelSize = 1024;
+
+/// \brief Inclusive median.
+template <class RandomAccessIterator, class Comp>
+RandomAccessIterator medianOf3(RandomAccessIterator start,
+                               RandomAccessIterator end, const Comp &comp) {
+  RandomAccessIterator mid = start + (std::distance(start, end) / 2);
+  return comp(*start, *(end - 1))
+         ? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
+                                   : end - 1)
+         : (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
+                               : start);
+}
+
+template <class RandomAccessIterator, class Comp>
+void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end,
+                         const Comp &comp, TaskGroup &tg, size_t depth) {
+  // Do a sequential sort for small inputs.
+  if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
+    std::sort(start, end, comp);
+    return;
+  }
+
+  // Partition.
+  auto pivot = medianOf3(start, end, comp);
+  // Move pivot to end.
+  std::swap(*(end - 1), *pivot);
+  pivot = std::partition(start, end - 1, [&comp, end](decltype(*start) v) {
+    return comp(v, *(end - 1));
+  });
+  // Move pivot to middle of partition.
+  std::swap(*pivot, *(end - 1));
+
+  // Recurse.
+  tg.spawn([=, &comp, &tg] {
+    parallel_quick_sort(start, pivot, comp, tg, depth - 1);
+  });
+  parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
+}
+}
+
+template <class RandomAccessIterator, class Comp>
+void parallel_sort(
+    RandomAccessIterator start, RandomAccessIterator end,
+    const Comp &comp = std::less<
+        typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
+  TaskGroup tg;
+  detail::parallel_quick_sort(start, end, comp, tg,
+                              llvm::Log2_64(std::distance(start, end)) + 1);
+}
+#endif
+
+template <class T> void parallel_sort(T *start, T *end) {
+  parallel_sort(start, end, std::less<T>());
+}
+
+#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
+template <class Iterator, class Func>
+void parallel_for_each(Iterator begin, Iterator end, Func func) {
+  std::for_each(begin, end, func);
+}
+#elif defined(_MSC_VER)
+// Use ppl parallel_for_each on Windows.
+template <class Iterator, class Func>
+void parallel_for_each(Iterator begin, Iterator end, Func func) {
+  concurrency::parallel_for_each(begin, end, func);
+}
+#else
+template <class Iterator, class Func>
+void parallel_for_each(Iterator begin, Iterator end, Func func) {
+  TaskGroup tg;
+  ptrdiff_t taskSize = 1024;
+  while (taskSize <= std::distance(begin, end)) {
+    tg.spawn([=, &func] { std::for_each(begin, begin + taskSize, func); });
+    begin += taskSize;
+  }
+  std::for_each(begin, end, func);
+}
+#endif
+} // end namespace lld
+
+#endif // LLD_CORE_PARALLEL_H
diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h
new file mode 100644 (file)
index 0000000..0527f02
--- /dev/null
@@ -0,0 +1,46 @@
+//===------ Core/Pass.h - Base class for linker passes --------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PASS_H
+#define LLD_CORE_PASS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+
+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() { }
+
+  /// Do the actual work of the Pass.
+  virtual llvm::Error perform(SimpleFile &mergedFile) = 0;
+
+protected:
+  // Only subclassess can be instantiated.
+  Pass() { }
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_PASS_H
diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h
new file mode 100644 (file)
index 0000000..71a25cc
--- /dev/null
@@ -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 <memory>
+#include <vector>
+
+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> pass) {
+    _passes.push_back(std::move(pass));
+  }
+
+  llvm::Error runOnFile(SimpleFile &file) {
+    for (std::unique_ptr<Pass> &pass : _passes)
+      if (llvm::Error EC = pass->perform(file))
+        return EC;
+    return llvm::Error();
+  }
+
+private:
+  /// \brief Passes in the order they should run.
+  std::vector<std::unique_ptr<Pass>> _passes;
+};
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h
new file mode 100644 (file)
index 0000000..66df438
--- /dev/null
@@ -0,0 +1,157 @@
+//===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_READER_H
+#define LLD_CORE_READER_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <functional>
+#include <memory>
+#include <vector>
+
+using llvm::sys::fs::file_magic;
+
+namespace llvm {
+namespace yaml {
+class IO;
+}
+}
+
+namespace lld {
+class 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() {}
+
+  /// 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(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<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> 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<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb) const;
+
+  /// Walk the list of registered kind tables to convert a Reference Kind
+  /// name to a value.
+  bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns,
+                               Reference::KindArch &a,
+                               Reference::KindValue &value) const;
+
+  /// Walk the list of registered kind tables to convert a Reference Kind
+  /// value to a string.
+  bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a,
+                             Reference::KindValue value, StringRef &) const;
+
+  /// Walk the list of registered tag handlers and have the one that handles
+  /// the current document type process the yaml into an lld::File*.
+  bool handleTaggedDoc(llvm::yaml::IO &io, const lld::File *&file) const;
+
+  // These methods are called to dynamically add support for various file
+  // formats. The methods are also implemented in the appropriate lib*.a
+  // library, so that the code for handling a format is only linked in, if this
+  // method is used.  Any options that a Reader might need must be passed
+  // as parameters to the addSupport*() method.
+  void addSupportArchives(bool logLoading);
+  void addSupportYamlFiles();
+  void addSupportMachOObjects(MachOLinkingContext &);
+
+  /// To convert between kind values and names, the registry walks the list
+  /// of registered kind tables. Each table is a zero terminated array of
+  /// KindStrings elements.
+  struct KindStrings {
+    Reference::KindValue  value;
+    StringRef             name;
+  };
+
+  /// A Reference Kind value is a tuple of <namespace, arch, value>.  All
+  /// entries in a conversion table have the same <namespace, arch>.  The
+  /// array then contains the value/name pairs.
+  void addKindTable(Reference::KindNamespace ns, Reference::KindArch arch,
+                    const KindStrings array[]);
+
+
+private:
+  struct KindEntry {
+    Reference::KindNamespace  ns;
+    Reference::KindArch       arch;
+    const KindStrings        *array;
+  };
+
+  void add(std::unique_ptr<Reader>);
+  void add(std::unique_ptr<YamlIOTaggedDocumentHandler>);
+
+  std::vector<std::unique_ptr<Reader>>                       _readers;
+  std::vector<std::unique_ptr<YamlIOTaggedDocumentHandler>>  _yamlHandlers;
+  std::vector<KindEntry>                                     _kindEntries;
+};
+
+// Utilities for building a KindString table.  For instance:
+//   static const Registry::KindStrings table[] = {
+//      LLD_KIND_STRING_ENTRY(R_VAX_ADDR16),
+//      LLD_KIND_STRING_ENTRY(R_VAX_DATA16),
+//      LLD_KIND_STRING_END
+//   };
+#define LLD_KIND_STRING_ENTRY(name) { name, #name }
+#define LLD_KIND_STRING_END         { 0,    "" }
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h
new file mode 100644 (file)
index 0000000..86de4f6
--- /dev/null
@@ -0,0 +1,119 @@
+//===- Core/References.h - A Reference to Another Atom --------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_REFERENCES_H
+#define LLD_CORE_REFERENCES_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace lld {
+class Atom;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms.  Each Atom is a node
+/// and each Reference is an edge.
+///
+/// For example if a function contains a call site to "malloc" 40 bytes into
+/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
+/// kind=callsite, target=malloc, addend=0.
+///
+/// Besides supporting traditional "relocations", references are also used
+/// forcing layout (one atom must follow another), marking data-in-code
+/// (jump tables or ARM constants), etc.
+///
+/// The "kind" of a reference is a tuple of <namespace, arch, value>.  This
+/// enable us to re-use existing relocation types definded for various
+/// file formats and architectures.
+///
+/// References and atoms form a directed graph. The dead-stripping pass
+/// traverses them starting from dead-strip root atoms to garbage collect
+/// unreachable ones.
+///
+/// References of any kind are considered as directed edges. In addition to
+/// that, references of some kind is considered as bidirected edges.
+class Reference {
+public:
+  /// Which universe defines the kindValue().
+  enum class KindNamespace {
+    all     = 0,
+    testing = 1,
+    mach_o  = 2,
+  };
+
+  KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; }
+  void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
+
+  // Which architecture the kind value is for.
+  enum class KindArch { all, AArch64, ARM, x86, x86_64};
+
+  KindArch kindArch() const { return (KindArch)_kindArch; }
+  void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }
+
+  typedef uint16_t KindValue;
+
+  KindValue kindValue() const { return _kindValue; }
+
+  /// setKindValue() is needed because during linking, some optimizations may
+  /// change the codegen and hence the reference kind.
+  void setKindValue(KindValue value) {
+    _kindValue = value;
+  }
+
+  /// KindValues used with KindNamespace::all and KindArch::all.
+  enum {
+    // kindLayoutAfter is treated as a bidirected edge by the dead-stripping
+    // pass.
+    kindLayoutAfter = 1,
+    kindAssociate,
+  };
+
+  // A value to be added to the value of a target
+  typedef int64_t Addend;
+
+  /// If the reference is a fixup in the Atom, then this returns the
+  /// byte offset into the Atom's content to do the fix up.
+  virtual uint64_t offsetInAtom() const = 0;
+
+  /// Returns the atom this reference refers to.
+  virtual const Atom *target() const = 0;
+
+  /// During linking, the linker may merge graphs which coalesces some nodes
+  /// (i.e. Atoms).  To switch the target of a reference, this method is called.
+  virtual void setTarget(const Atom *) = 0;
+
+  /// Some relocations require a symbol and a value (e.g. foo + 4).
+  virtual Addend addend() const = 0;
+
+  /// During linking, some optimzations may change addend value.
+  virtual void setAddend(Addend) = 0;
+
+  /// Returns target specific attributes of the reference.
+  virtual uint32_t tag() const { return 0; }
+
+protected:
+  /// Reference is an abstract base class.  Only subclasses can use constructor.
+  Reference(KindNamespace ns, KindArch a, KindValue value)
+      : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {}
+
+  /// The memory for Reference objects is always managed by the owning File
+  /// object.  Therefore, no one but the owning File object should call
+  /// delete on an Reference.  In fact, some File objects may bulk allocate
+  /// an array of References, so they cannot be individually deleted by anyone.
+  virtual ~Reference() {}
+
+  KindValue  _kindValue;
+  uint8_t    _kindNamespace;
+  uint8_t    _kindArch;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_REFERENCES_H
diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h
new file mode 100644 (file)
index 0000000..fb62a77
--- /dev/null
@@ -0,0 +1,106 @@
+//===- Core/Resolver.h - Resolves Atom References -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_RESOLVER_H
+#define LLD_CORE_RESOLVER_H
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/SymbolTable.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/ErrorOr.h"
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace lld {
+
+class Atom;
+class LinkingContext;
+
+/// \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<DefinedAtom> atom);
+  bool doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom);
+  void doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom);
+  void doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom);
+
+  // Handle files, this adds atoms from the current file thats
+  // being processed by the resolver
+  llvm::Expected<bool> handleFile(File &);
+
+  // Handle an archive library file.
+  llvm::Expected<bool> handleArchiveFile(File &);
+
+  // Handle a shared library file.
+  llvm::Error handleSharedLibrary(File &);
+
+  /// @brief do work of merging and resolving and return list
+  bool resolve();
+
+  std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
+
+private:
+  typedef std::function<llvm::Expected<bool>(StringRef)> UndefCallback;
+
+  bool undefinesAdded(int begin, int end);
+  File *getFile(int &index);
+
+  /// \brief The main function that iterates over the files to resolve
+  bool resolveUndefines();
+  void updateReferences();
+  void deadStripOptimize();
+  bool checkUndefines();
+  void removeCoalescedAwayAtoms();
+  llvm::Expected<bool> forEachUndefines(File &file, UndefCallback callback);
+
+  void markLive(const Atom *atom);
+
+  class MergedFile : public SimpleFile {
+  public:
+    MergedFile() : SimpleFile("<linker-internal>", kindResolverMergedObject) {}
+    void addAtoms(llvm::MutableArrayRef<OwningAtomPtr<Atom>> atoms);
+  };
+
+  LinkingContext &_ctx;
+  SymbolTable _symbolTable;
+  std::vector<OwningAtomPtr<Atom>>     _atoms;
+  std::set<const Atom *>        _deadStripRoots;
+  llvm::DenseSet<const Atom *>  _liveAtoms;
+  llvm::DenseSet<const Atom *>  _deadAtoms;
+  std::unique_ptr<MergedFile>   _result;
+  std::unordered_multimap<const Atom *, const Atom *> _reverseRef;
+
+  // --start-group and --end-group
+  std::vector<File *> _files;
+  std::map<File *, bool> _newUndefinesAdded;
+
+  // List of undefined symbols.
+  std::vector<StringRef> _undefines;
+
+  // Start position in _undefines for each archive/shared library file.
+  // Symbols from index 0 to the start position are already searched before.
+  // Searching them again would never succeed. When we look for undefined
+  // symbols from an archive/shared library file, start from its start
+  // position to save time.
+  std::map<File *, size_t> _undefineIndex;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_RESOLVER_H
diff --git a/include/lld/Core/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h
new file mode 100644 (file)
index 0000000..7fec7a3
--- /dev/null
@@ -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 (file)
index 0000000..53bf967
--- /dev/null
@@ -0,0 +1,70 @@
+//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H
+#define LLD_CORE_SHARED_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+
+namespace lld {
+
+///
+/// The SharedLibraryFile subclass of File is used to represent dynamic
+/// shared libraries being linked against.
+///
+class SharedLibraryFile : public File {
+public:
+  static bool classof(const File *f) {
+    return f->kind() == kindSharedLibrary;
+  }
+
+  /// Check if the shared library exports a symbol with the specified name.
+  /// If so, return a SharedLibraryAtom which represents that exported
+  /// symbol.  Otherwise return nullptr.
+  virtual OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const = 0;
+
+  // Returns the install name.
+  virtual StringRef getDSOName() const = 0;
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _undefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _sharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _absoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _undefinedAtoms.clear();
+    _sharedLibraryAtoms.clear();
+    _absoluteAtoms.clear();
+  }
+
+protected:
+  /// only subclasses of SharedLibraryFile can be instantiated
+  explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
+
+  AtomVector<DefinedAtom> _definedAtoms;
+  AtomVector<UndefinedAtom> _undefinedAtoms;
+  AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+  AtomVector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_FILE_H
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
new file mode 100644 (file)
index 0000000..f75b403
--- /dev/null
@@ -0,0 +1,324 @@
+//===- 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/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <functional>
+
+namespace lld {
+
+class SimpleFile : public File {
+public:
+  SimpleFile(StringRef path, File::Kind kind)
+    : File(path, kind) {}
+
+  ~SimpleFile() override {
+    _defined.clear();
+    _undefined.clear();
+    _shared.clear();
+    _absolute.clear();
+  }
+
+  void addAtom(DefinedAtom &a) {
+    _defined.push_back(OwningAtomPtr<DefinedAtom>(&a));
+  }
+  void addAtom(UndefinedAtom &a) {
+    _undefined.push_back(OwningAtomPtr<UndefinedAtom>(&a));
+  }
+  void addAtom(SharedLibraryAtom &a) {
+    _shared.push_back(OwningAtomPtr<SharedLibraryAtom>(&a));
+  }
+  void addAtom(AbsoluteAtom &a) {
+    _absolute.push_back(OwningAtomPtr<AbsoluteAtom>(&a));
+  }
+
+  void addAtom(const Atom &atom) {
+    if (auto *p = dyn_cast<DefinedAtom>(&atom)) {
+      addAtom(const_cast<DefinedAtom &>(*p));
+    } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) {
+      addAtom(const_cast<UndefinedAtom &>(*p));
+    } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) {
+      addAtom(const_cast<SharedLibraryAtom &>(*p));
+    } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) {
+      addAtom(const_cast<AbsoluteAtom &>(*p));
+    } else {
+      llvm_unreachable("atom has unknown definition kind");
+    }
+  }
+
+  void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) {
+    auto &atoms = _defined;
+    auto newEnd = std::remove_if(atoms.begin(), atoms.end(),
+                                 [&pred](OwningAtomPtr<DefinedAtom> &p) {
+                                   return pred(p.get());
+                                 });
+    atoms.erase(newEnd, atoms.end());
+  }
+
+  const AtomRange<DefinedAtom> defined() const override { return _defined; }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _undefined;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _shared;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _absolute;
+  }
+
+  void clearAtoms() override {
+    _defined.clear();
+    _undefined.clear();
+    _shared.clear();
+    _absolute.clear();
+  }
+
+private:
+  AtomVector<DefinedAtom> _defined;
+  AtomVector<UndefinedAtom> _undefined;
+  AtomVector<SharedLibraryAtom> _shared;
+  AtomVector<AbsoluteAtom> _absolute;
+};
+
+class SimpleReference : public Reference {
+public:
+  SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch,
+                  Reference::KindValue value, uint64_t off, const Atom *t,
+                  Reference::Addend a)
+      : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a),
+        _next(nullptr), _prev(nullptr) {
+  }
+  SimpleReference()
+      : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0),
+        _target(nullptr), _offsetInAtom(0), _addend(0), _next(nullptr),
+        _prev(nullptr) {
+  }
+
+  uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+  const Atom *target() const override {
+    assert(_target);
+    return _target;
+  }
+
+  Addend addend() const override { return _addend; }
+  void setAddend(Addend a) override { _addend = a; }
+  void setTarget(const Atom *newAtom) override { _target = newAtom; }
+  SimpleReference *getNext() const { return _next; }
+  SimpleReference *getPrev() const { return _prev; }
+  void setNext(SimpleReference *n) { _next = n; }
+  void setPrev(SimpleReference *p) { _prev = p; }
+
+private:
+  const Atom *_target;
+  uint64_t _offsetInAtom;
+  Addend _addend;
+  SimpleReference *_next;
+  SimpleReference *_prev;
+};
+
+} // end namespace lld
+
+// ilist will lazily create a sentinal (so end() can return a node past the
+// end of the list). We need this trait so that the sentinal is allocated
+// via the BumpPtrAllocator.
+namespace llvm {
+
+template<>
+struct ilist_sentinel_traits<lld::SimpleReference> {
+
+  ilist_sentinel_traits() : _allocator(nullptr) { }
+
+  void setAllocator(llvm::BumpPtrAllocator *alloc) {
+    _allocator = alloc;
+  }
+
+  lld::SimpleReference *createSentinel() const {
+    return new (*_allocator) lld::SimpleReference();
+  }
+
+  static void destroySentinel(lld::SimpleReference*) {}
+
+  static lld::SimpleReference *provideInitialHead() { return nullptr; }
+
+  lld::SimpleReference *ensureHead(lld::SimpleReference *&head) const {
+    if (!head) {
+      head = createSentinel();
+      noteHead(head, head);
+      ilist_traits<lld::SimpleReference>::setNext(head, nullptr);
+      return head;
+    }
+    return ilist_traits<lld::SimpleReference>::getPrev(head);
+  }
+
+  void noteHead(lld::SimpleReference *newHead,
+                lld::SimpleReference *sentinel) const {
+    ilist_traits<lld::SimpleReference>::setPrev(newHead, sentinel);
+  }
+
+private:
+  mutable llvm::BumpPtrAllocator *_allocator;
+};
+
+} // end namespace llvm
+
+namespace lld {
+
+class SimpleDefinedAtom : public DefinedAtom {
+public:
+  explicit SimpleDefinedAtom(const File &f)
+    : _file(f), _ordinal(f.getNextAtomOrdinalAndIncrement()) {
+    _references.setAllocator(&f.allocator());
+  }
+
+  ~SimpleDefinedAtom() override {
+    _references.clearAndLeakNodesUnsafely();
+  }
+
+  const File &file() const override { return _file; }
+
+  StringRef name() const override { return StringRef(); }
+
+  uint64_t ordinal() const override { return _ordinal; }
+
+  Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+  Interposable interposable() const override {
+    return DefinedAtom::interposeNo;
+  }
+
+  Merge merge() const override { return DefinedAtom::mergeNo; }
+
+  Alignment alignment() const override { return 1; }
+
+  SectionChoice sectionChoice() const override {
+    return DefinedAtom::sectionBasedOnContent;
+  }
+
+  StringRef customSectionName() const override { return StringRef(); }
+  DeadStripKind deadStrip() const override {
+    return DefinedAtom::deadStripNormal;
+  }
+
+  DefinedAtom::reference_iterator begin() const override {
+    const void *it = reinterpret_cast<const void *>(&*_references.begin());
+    return reference_iterator(*this, it);
+  }
+
+  DefinedAtom::reference_iterator end() const override {
+    const void *it = reinterpret_cast<const void *>(&*_references.end());
+    return reference_iterator(*this, it);
+  }
+
+  const Reference *derefIterator(const void *it) const override {
+    return reinterpret_cast<const Reference*>(it);
+  }
+
+  void incrementIterator(const void *&it) const override {
+    const SimpleReference* node = reinterpret_cast<const SimpleReference*>(it);
+    const SimpleReference* next = node->getNext();
+    it = reinterpret_cast<const void*>(next);
+  }
+
+  void addReference(Reference::KindNamespace ns,
+                    Reference::KindArch arch,
+                    Reference::KindValue kindValue, uint64_t off,
+                    const Atom *target, Reference::Addend a) override {
+    assert(target && "trying to create reference to nothing");
+    auto node = new (_file.allocator())
+        SimpleReference(ns, arch, kindValue, off, target, a);
+    _references.push_back(node);
+  }
+
+  /// Sort references in a canonical order (by offset, then by kind).
+  void sortReferences() const {
+    // Cannot sort a linked  list, so move elements into a temporary vector,
+    // sort the vector, then reconstruct the list.
+    llvm::SmallVector<SimpleReference *, 16> elements;
+    for (SimpleReference &node : _references) {
+      elements.push_back(&node);
+    }
+    std::sort(elements.begin(), elements.end(),
+        [] (const SimpleReference *lhs, const SimpleReference *rhs) -> bool {
+          uint64_t lhsOffset = lhs->offsetInAtom();
+          uint64_t rhsOffset = rhs->offsetInAtom();
+          if (rhsOffset != lhsOffset)
+            return (lhsOffset < rhsOffset);
+          if (rhs->kindNamespace() != lhs->kindNamespace())
+            return (lhs->kindNamespace() < rhs->kindNamespace());
+          if (rhs->kindArch() != lhs->kindArch())
+            return (lhs->kindArch() < rhs->kindArch());
+          return (lhs->kindValue() < rhs->kindValue());
+        });
+    _references.clearAndLeakNodesUnsafely();
+    for (SimpleReference *node : elements) {
+      _references.push_back(node);
+    }
+  }
+
+  void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+private:
+  typedef llvm::ilist<SimpleReference> RefList;
+
+  const File &_file;
+  uint64_t _ordinal;
+  mutable RefList _references;
+};
+
+class SimpleUndefinedAtom : public UndefinedAtom {
+public:
+  SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {
+    assert(!name.empty() && "UndefinedAtoms must have a name");
+  }
+
+  ~SimpleUndefinedAtom() override = default;
+
+  /// file - returns the File that produced/owns this Atom
+  const File &file() const override { return _file; }
+
+  /// name - The name of the atom. For a function atom, it is the (mangled)
+  /// name of the function.
+  StringRef name() const override { return _name; }
+
+  CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; }
+
+private:
+  const File &_file;
+  StringRef _name;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_SIMPLE_H
diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h
new file mode 100644 (file)
index 0000000..db610ad
--- /dev/null
@@ -0,0 +1,106 @@
+//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SYMBOL_TABLE_H
+#define LLD_CORE_SYMBOL_TABLE_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include <cstring>
+#include <map>
+#include <vector>
+
+namespace lld {
+
+class AbsoluteAtom;
+class Atom;
+class DefinedAtom;
+class LinkingContext;
+class ResolverOptions;
+class SharedLibraryAtom;
+class UndefinedAtom;
+
+/// \brief The SymbolTable class is responsible for coalescing atoms.
+///
+/// All atoms coalescable by-name or by-content should be added.
+/// The method replacement() can be used to find the replacement atom
+/// if an atom has been coalesced away.
+class SymbolTable {
+public:
+  /// @brief add atom to symbol table
+  bool add(const DefinedAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const UndefinedAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const SharedLibraryAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const AbsoluteAtom &);
+
+  /// @brief checks if name is in symbol table and if so atom is not
+  ///        UndefinedAtom
+  bool isDefined(StringRef sym);
+
+  /// @brief returns atom in symbol table for specified name (or nullptr)
+  const Atom *findByName(StringRef sym);
+
+  /// @brief returns vector of remaining UndefinedAtoms
+  std::vector<const UndefinedAtom *> undefines();
+
+  /// returns vector of tentative definitions
+  std::vector<StringRef> tentativeDefinitions();
+
+  /// @brief add atom to replacement table
+  void addReplacement(const Atom *replaced, const Atom *replacement);
+
+  /// @brief if atom has been coalesced away, return replacement, else return atom
+  const Atom *replacement(const Atom *);
+
+  /// @brief if atom has been coalesced away, return true
+  bool isCoalescedAway(const Atom *);
+
+private:
+  typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom;
+
+  struct StringRefMappingInfo {
+    static StringRef getEmptyKey() { return StringRef(); }
+    static StringRef getTombstoneKey() { return StringRef(" ", 1); }
+    static unsigned getHashValue(StringRef const val) {
+      return llvm::HashString(val);
+    }
+    static bool isEqual(StringRef const lhs, StringRef const rhs) {
+      return lhs.equals(rhs);
+    }
+  };
+  typedef llvm::DenseMap<StringRef, const Atom *,
+                                           StringRefMappingInfo> NameToAtom;
+
+  struct AtomMappingInfo {
+    static const DefinedAtom * getEmptyKey() { return nullptr; }
+    static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
+    static unsigned getHashValue(const DefinedAtom * const Val);
+    static bool isEqual(const DefinedAtom * const LHS,
+                        const DefinedAtom * const RHS);
+  };
+  typedef llvm::DenseSet<const DefinedAtom*, AtomMappingInfo> AtomContentSet;
+
+  bool addByName(const Atom &);
+  bool addByContent(const DefinedAtom &);
+
+  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 (file)
index 0000000..8b52304
--- /dev/null
@@ -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/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h
new file mode 100644 (file)
index 0000000..f45d6ec
--- /dev/null
@@ -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 (file)
index 0000000..216f934
--- /dev/null
@@ -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 <memory>
+#include <vector>
+
+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<std::unique_ptr<File>> &) {}
+
+protected:
+  // only concrete subclasses can be instantiated
+  Writer();
+};
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &);
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &);
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h
new file mode 100644 (file)
index 0000000..312f4f8
--- /dev/null
@@ -0,0 +1,32 @@
+//===- 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<const char *> Args);
+}
+
+namespace elf {
+bool link(llvm::ArrayRef<const char *> Args,
+          llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace mach_o {
+bool link(llvm::ArrayRef<const char *> 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 (file)
index 0000000..7b673f0
--- /dev/null
@@ -0,0 +1,504 @@
+//===- 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/Support/ErrorHandling.h"
+#include "llvm/Support/MachO.h"
+#include <set>
+
+using llvm::MachO::HeaderFileType;
+
+namespace lld {
+
+namespace mach_o {
+class ArchHandler;
+class MachODylibFile;
+class MachOFile;
+class 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<std::unique_ptr<File>> &) override;
+
+  /// Creates a new file which is owned by the context.  Returns a pointer to
+  /// the new file.
+  template <class T, class... Args>
+  typename std::enable_if<!std::is_array<T>::value, T *>::type
+  make_file(Args &&... args) const {
+    auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+    auto *filePtr = file.get();
+    auto *ctx = const_cast<MachOLinkingContext *>(this);
+    ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+    return filePtr;
+  }
+
+  uint32_t getCPUType() const;
+  uint32_t getCPUSubType() const;
+
+  bool addEntryPointLoadCommand() const;
+  bool addUnixThreadLoadCommand() const;
+  bool outputTypeHasEntry() const;
+  bool is64Bit() const;
+
+  virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
+  virtual uint64_t pageSize() const { return _pageSize; }
+
+  mach_o::ArchHandler &archHandler() const;
+
+  HeaderFileType outputMachOType() const { return _outputMachOType; }
+
+  Arch arch() const { return _arch; }
+  StringRef archName() const { return nameFromArch(_arch); }
+  OS os() const { return _os; }
+
+  ExportMode exportMode() const { return _exportMode; }
+  void setExportMode(ExportMode mode) { _exportMode = mode; }
+  void addExportSymbol(StringRef sym);
+  bool exportRestrictMode() const { return _exportMode != ExportMode::globals; }
+  bool exportSymbolNamed(StringRef sym) const;
+
+  DebugInfoMode debugInfoMode() const { return _debugInfoMode; }
+  void setDebugInfoMode(DebugInfoMode mode) {
+    _debugInfoMode = mode;
+  }
+
+  void appendOrderedSymbol(StringRef symbol, StringRef filename);
+
+  bool keepPrivateExterns() const { return _keepPrivateExterns; }
+  void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
+  bool demangleSymbols() const { return _demangle; }
+  void setDemangleSymbols(bool d) { _demangle = d; }
+  bool mergeObjCCategories() const { return _mergeObjCCategories; }
+  void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; }
+  /// Create file at specified path which will contain a binary encoding
+  /// of all input and output file paths.
+  std::error_code createDependencyFile(StringRef path);
+  void addInputFileDependency(StringRef path) const;
+  void addInputFileNotFound(StringRef path) const;
+  void addOutputFileDependency(StringRef path) const;
+
+  bool minOS(StringRef mac, StringRef iOS) const;
+  void setDoNothing(bool value) { _doNothing = value; }
+  bool doNothing() const { return _doNothing; }
+  bool printAtoms() const { return _printAtoms; }
+  bool testingFileUsage() const { return _testingFileUsage; }
+  const StringRefVector &searchDirs() const { return _searchDirs; }
+  const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
+  void setSysLibRoots(const StringRefVector &paths);
+  const StringRefVector &sysLibRoots() const { return _syslibRoots; }
+  bool PIE() const { return _pie; }
+  void setPIE(bool pie) { _pie = pie; }
+  bool generateVersionLoadCommand() const {
+    return _generateVersionLoadCommand;
+  }
+  void setGenerateVersionLoadCommand(bool v) {
+    _generateVersionLoadCommand = v;
+  }
+
+  bool generateFunctionStartsLoadCommand() const {
+    return _generateFunctionStartsLoadCommand;
+  }
+  void setGenerateFunctionStartsLoadCommand(bool v) {
+    _generateFunctionStartsLoadCommand = v;
+  }
+
+  bool generateDataInCodeLoadCommand() const {
+    return _generateDataInCodeLoadCommand;
+  }
+  void setGenerateDataInCodeLoadCommand(bool v) {
+    _generateDataInCodeLoadCommand = v;
+  }
+
+  uint64_t stackSize() const { return _stackSize; }
+  void setStackSize(uint64_t stackSize) { _stackSize = stackSize; }
+
+  uint64_t baseAddress() const { return _baseAddress; }
+  void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; }
+
+  ObjCConstraint objcConstraint() const { return _objcConstraint; }
+
+  uint32_t osMinVersion() const { return _osMinVersion; }
+
+  uint32_t sdkVersion() const { return _sdkVersion; }
+  void setSdkVersion(uint64_t v) { _sdkVersion = v; }
+
+  uint64_t sourceVersion() const { return _sourceVersion; }
+  void setSourceVersion(uint64_t v) { _sourceVersion = v; }
+
+  uint32_t swiftVersion() const { return _swiftVersion; }
+
+  /// \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<StringRef> searchDirForLibrary(StringRef path,
+                                                StringRef libName) const;
+
+  /// \brief Iterates through all search path entries looking for libName (as
+  /// specified by -lFoo).
+  llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
+
+  /// Add a framework search path.  Internally, this method may be prepended
+  /// the path with syslibroot.
+  void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
+
+  /// \brief Iterates through all framework directories looking for
+  /// Foo.framework/Foo (when fwName = "Foo").
+  llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
+
+  /// \brief The dylib's binary compatibility version, in the raw uint32 format.
+  ///
+  /// When building a dynamic library, this is the compatibility version that
+  /// gets embedded into the result. Other Mach-O binaries that link against
+  /// this library will store the compatibility version in its load command. At
+  /// runtime, the loader will verify that the binary is compatible with the
+  /// installed dynamic library.
+  uint32_t compatibilityVersion() const { return _compatibilityVersion; }
+
+  /// \brief The dylib's current version, in the the raw uint32 format.
+  ///
+  /// When building a dynamic library, this is the current version that gets
+  /// embedded into the result. Other Mach-O binaries that link against
+  /// this library will store the compatibility version in its load command.
+  uint32_t currentVersion() const { return _currentVersion; }
+
+  /// \brief The dylib's install name.
+  ///
+  /// Binaries that link against the dylib will embed this path into the dylib
+  /// load command. When loading the binaries at runtime, this is the location
+  /// on disk that the loader will look for the dylib.
+  StringRef installName() const { return _installName; }
+
+  /// \brief Whether or not the dylib has side effects during initialization.
+  ///
+  /// Dylibs marked as being dead strippable provide the guarantee that loading
+  /// the dylib has no side effects, allowing the linker to strip out the dylib
+  /// when linking a binary that does not use any of its symbols.
+  bool deadStrippableDylib() const { return _deadStrippableDylib; }
+
+  /// \brief 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<MemoryBuffer> content);
+
+  /// Returns true if specified section had alignment constraints.
+  bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const;
+
+  StringRef dyldPath() const { return "/usr/lib/dyld"; }
+
+  /// Stub creation Pass should be run.
+  bool needsStubsPass() const;
+
+  // GOT creation Pass should be run.
+  bool needsGOTPass() const;
+
+  /// Pass to add TLV sections.
+  bool needsTLVPass() const;
+
+  /// Pass to transform __compact_unwind into __unwind_info should be run.
+  bool needsCompactUnwindPass() const;
+
+  /// Pass to add shims switching between thumb and arm mode.
+  bool needsShimPass() const;
+
+  /// Pass to add objc image info and optimized objc data.
+  bool needsObjCPass() const;
+
+  /// Magic symbol name stubs will need to help lazy bind.
+  StringRef binderSymbolName() const;
+
+  /// Used to keep track of direct and indirect dylibs.
+  void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const;
+
+  // Reads a file from disk to memory. Returns only a needed chunk
+  // if a fat binary.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> getMemoryBuffer(StringRef path);
+
+  /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
+  /// has not already been made for the requested dylib.  Uses -L and -F
+  /// search paths to allow indirect dylibs to be overridden.
+  mach_o::MachODylibFile* findIndirectDylib(StringRef path);
+
+  uint32_t dylibCurrentVersion(StringRef installName) const;
+
+  uint32_t dylibCompatVersion(StringRef installName) const;
+
+  /// Creates a copy (owned by this MachOLinkingContext) of a string.
+  StringRef copy(StringRef str) { return str.copy(_allocator); }
+
+  /// If the memoryBuffer is a fat file with a slice for the current arch,
+  /// this method will return the offset and size of that slice.
+  bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size);
+
+  /// Returns if a command line option specified dylib is an upward link.
+  bool isUpwardDylib(StringRef installName) const;
+
+  static bool isThinObjectFile(StringRef path, Arch &arch);
+  static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
+  static Arch archFromName(StringRef archName);
+  static StringRef nameFromArch(Arch arch);
+  static uint32_t cpuTypeFromArch(Arch arch);
+  static uint32_t cpuSubtypeFromArch(Arch arch);
+  static bool is64Bit(Arch arch);
+  static bool isHostEndian(Arch arch);
+  static bool isBigEndian(Arch arch);
+
+  /// Construct 32-bit value from string "X.Y.Z" where
+  /// bits are xxxx.yy.zz.  Largest number is 65535.255.255
+  static bool parsePackedVersion(StringRef str, uint32_t &result);
+
+  /// Construct 64-bit value from string "A.B.C.D.E" where
+  /// bits are aaaa.bb.cc.dd.ee.  Largest number is 16777215.1023.1023.1023.1023
+  static bool parsePackedVersion(StringRef str, uint64_t &result);
+
+  void finalizeInputFiles() override;
+
+  llvm::Error handleLoadedFile(File &file) override;
+
+  bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
+                         bool &leftBeforeRight) const;
+
+  /// Return the 'flat namespace' file. This is the file that supplies
+  /// atoms for otherwise undefined symbols when the -flat_namespace or
+  /// -undefined dynamic_lookup options are used.
+  File* flatNamespaceFile() const { return _flatNamespaceFile; }
+
+private:
+  Writer &writer() const override;
+  mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
+  void checkExportWhiteList(const DefinedAtom *atom) const;
+  void checkExportBlackList(const DefinedAtom *atom) const;
+  struct ArchInfo {
+    StringRef                 archName;
+    MachOLinkingContext::Arch arch;
+    bool                      littleEndian;
+    uint32_t                  cputype;
+    uint32_t                  cpusubtype;
+  };
+
+  struct SectionAlign {
+    StringRef segmentName;
+    StringRef sectionName;
+    uint16_t  align;
+  };
+
+  struct OrderFileNode {
+    StringRef fileFilter;
+    unsigned  order;
+  };
+
+  static bool findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+                             const DefinedAtom *atom, unsigned &ordinal);
+
+  static ArchInfo _s_archInfos[];
+
+  std::set<StringRef> _existingPaths; // For testing only.
+  StringRefVector _searchDirs;
+  StringRefVector _syslibRoots;
+  StringRefVector _frameworkDirs;
+  HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE;
+  bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog
+  bool _doNothing = false;             // for -help and -v which just print info
+  bool _pie = false;
+  Arch _arch = arch_unknown;
+  OS _os = OS::macOSX;
+  uint32_t _osMinVersion = 0;
+  uint32_t _sdkVersion = 0;
+  uint64_t _sourceVersion = 0;
+  uint64_t _pageZeroSize = 0;
+  uint64_t _pageSize = 4096;
+  uint64_t _baseAddress = 0;
+  uint64_t _stackSize = 0;
+  uint32_t _compatibilityVersion = 0;
+  uint32_t _currentVersion = 0;
+  ObjCConstraint _objcConstraint = objc_unknown;
+  uint32_t _swiftVersion = 0;
+  StringRef _installName;
+  StringRefVector _rpaths;
+  bool _flatNamespace = false;
+  UndefinedMode _undefinedMode = UndefinedMode::error;
+  bool _deadStrippableDylib = false;
+  bool _printAtoms = false;
+  bool _testingFileUsage = false;
+  bool _keepPrivateExterns = false;
+  bool _demangle = false;
+  bool _mergeObjCCategories = true;
+  bool _generateVersionLoadCommand = false;
+  bool _generateFunctionStartsLoadCommand = false;
+  bool _generateDataInCodeLoadCommand = false;
+  StringRef _bundleLoader;
+  mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
+  mutable std::unique_ptr<Writer> _writer;
+  std::vector<SectionAlign> _sectAligns;
+  mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
+  mutable std::set<mach_o::MachODylibFile*> _allDylibs;
+  mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
+  mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
+  mutable std::mutex _dylibsMutex;
+  ExportMode _exportMode = ExportMode::globals;
+  llvm::StringSet<> _exportedSymbols;
+  DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap;
+  std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
+  llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
+  unsigned _orderFileEntries = 0;
+  File *_flatNamespaceFile = nullptr;
+  mach_o::SectCreateFile *_sectCreateFile = nullptr;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h
new file mode 100644 (file)
index 0000000..b26161a
--- /dev/null
@@ -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 <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+namespace mach_o {
+namespace normalized {
+struct NormalizedFile;
+}
+}
+
+using lld::mach_o::normalized::NormalizedFile;
+
+/// When YAML I/O is used in lld, the yaml context always holds a YamlContext
+/// object.  We need to support hetergenous yaml documents which each require
+/// different context info.  This struct supports all clients.
+struct YamlContext {
+  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 (file)
index 0000000..699f5e9
--- /dev/null
@@ -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 (file)
index 0000000..e971b0b
--- /dev/null
@@ -0,0 +1,9 @@
+add_lld_library(lldConfig
+  Version.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/Config
+
+  LINK_LIBS
+    LLVMSupport
+  )
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp
new file mode 100644 (file)
index 0000000..60687b9
--- /dev/null
@@ -0,0 +1,57 @@
+//===- lib/Config/Version.cpp - LLD Version Number ---------------*- C++-=====//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several version-related utility functions for LLD.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Config/Version.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace lld {
+
+StringRef getLLDRepositoryPath() {
+#ifdef LLD_REPOSITORY_STRING
+  return LLD_REPOSITORY_STRING;
+#else
+  return "";
+#endif
+}
+
+StringRef getLLDRevision() {
+#ifdef LLD_REVISION_STRING
+  return LLD_REVISION_STRING;
+#else
+  return "";
+#endif
+}
+
+std::string getLLDRepositoryVersion() {
+  std::string S = getLLDRepositoryPath();
+  std::string T = getLLDRevision();
+  if (S.empty() && T.empty())
+    return "";
+  if (!S.empty() && !T.empty())
+    return "(" + S + " " + T + ")";
+  if (!S.empty())
+    return "(" + S + ")";
+  return "(" + T + ")";
+}
+
+StringRef getLLDVersion() {
+#ifdef LLD_VERSION_STRING
+  return LLD_VERSION_STRING;
+#else
+  return "";
+#endif
+}
+
+} // end namespace lld
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..41e0e76
--- /dev/null
@@ -0,0 +1,16 @@
+add_lld_library(lldCore
+  DefinedAtom.cpp
+  Error.cpp
+  File.cpp
+  LinkingContext.cpp
+  Reader.cpp
+  Resolver.cpp
+  SymbolTable.cpp
+  Writer.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/Core
+
+  LINK_LIBS
+    LLVMSupport
+  )
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
new file mode 100644 (file)
index 0000000..8dc4d4a
--- /dev/null
@@ -0,0 +1,94 @@
+//===- 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");
+}
+
+bool DefinedAtom::compareByPosition(const DefinedAtom *lhs,
+                                    const DefinedAtom *rhs) {
+  if (lhs == rhs)
+    return false;
+  const File *lhsFile = &lhs->file();
+  const File *rhsFile = &rhs->file();
+  if (lhsFile->ordinal() != rhsFile->ordinal())
+    return lhsFile->ordinal() < rhsFile->ordinal();
+  assert(lhs->ordinal() != rhs->ordinal());
+  return lhs->ordinal() < rhs->ordinal();
+}
+
+} // namespace
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
new file mode 100644 (file)
index 0000000..4df1ce1
--- /dev/null
@@ -0,0 +1,91 @@
+//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+using namespace lld;
+
+class _YamlReaderErrorCategory : public std::error_category {
+public:
+  const char* name() const LLVM_NOEXCEPT override {
+    return "lld.yaml.reader";
+  }
+
+  std::string message(int ev) const override {
+    switch (static_cast<YamlReaderError>(ev)) {
+    case YamlReaderError::unknown_keyword:
+      return "Unknown keyword found in yaml file";
+    case YamlReaderError::illegal_value:
+      return "Bad value found in yaml file";
+    }
+    llvm_unreachable("An enumerator of YamlReaderError does not have a "
+                     "message defined.");
+  }
+};
+
+const std::error_category &lld::YamlReaderCategory() {
+  static _YamlReaderErrorCategory o;
+  return o;
+}
+
+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 LLVM_NOEXCEPT override {
+    return "lld.dynamic_error";
+  }
+
+  std::string message(int ev) const override {
+    assert(ev >= 0);
+    assert(ev < (int)_messages.size());
+    // The value is an index into the string vector.
+    return _messages[ev];
+  }
+
+  int add(std::string msg) {
+    std::lock_guard<std::recursive_mutex> lock(_mutex);
+    // Value zero is always the successs value.
+    if (_messages.empty())
+      _messages.push_back("Success");
+    _messages.push_back(msg);
+    // Return the index of the string just appended.
+    return _messages.size() - 1;
+  }
+
+private:
+  std::vector<std::string> _messages;
+  std::recursive_mutex _mutex;
+};
+
+static dynamic_error_category categorySingleton;
+
+std::error_code make_dynamic_error_code(StringRef msg) {
+  return std::error_code(categorySingleton.add(msg), categorySingleton);
+}
+
+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 (file)
index 0000000..b84132b
--- /dev/null
@@ -0,0 +1,30 @@
+//===- Core/File.cpp - A Container of Atoms -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include <mutex>
+
+namespace lld {
+
+File::~File() { }
+
+File::AtomVector<DefinedAtom> File::_noDefinedAtoms;
+File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms;
+File::AtomVector<SharedLibraryAtom> File::_noSharedLibraryAtoms;
+File::AtomVector<AbsoluteAtom> File::_noAbsoluteAtoms;
+
+std::error_code File::parse() {
+  std::lock_guard<std::mutex> lock(_parseMutex);
+  if (!_lastError.hasValue())
+    _lastError = doParse();
+  return _lastError.getValue();
+}
+
+} // namespace lld
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
new file mode 100644 (file)
index 0000000..2732543
--- /dev/null
@@ -0,0 +1,69 @@
+//===- 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/Resolver.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+
+LinkingContext::LinkingContext() {}
+
+LinkingContext::~LinkingContext() {}
+
+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<File> LinkingContext::createEntrySymbolFile() const {
+  return createEntrySymbolFile("<command line option -e>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createEntrySymbolFile(StringRef filename) const {
+  if (entrySymbolName().empty())
+    return nullptr;
+  std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename,
+                                                       File::kindEntryObject));
+  entryFile->addAtom(
+      *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
+  return std::move(entryFile);
+}
+
+std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
+  return createUndefinedSymbolFile("<command line option -u or --defsym>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
+  if (_initialUndefinedSymbols.empty())
+    return nullptr;
+  std::unique_ptr<SimpleFile> undefinedSymFile(
+    new SimpleFile(filename, File::kindUndefinedSymsObject));
+  for (StringRef undefSym : _initialUndefinedSymbols)
+    undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
+                                   *undefinedSymFile, undefSym)));
+  return std::move(undefinedSymFile);
+}
+
+void LinkingContext::createInternalFiles(
+    std::vector<std::unique_ptr<File> > &result) const {
+  if (std::unique_ptr<File> file = createEntrySymbolFile())
+    result.push_back(std::move(file));
+  if (std::unique_ptr<File> file = createUndefinedSymbolFile())
+    result.push_back(std::move(file));
+}
+
+} // end namespace lld
diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp
new file mode 100644 (file)
index 0000000..107db07
--- /dev/null
@@ -0,0 +1,110 @@
+//===- lib/Core/Reader.cpp ------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <system_error>
+
+namespace lld {
+
+YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {}
+
+void Registry::add(std::unique_ptr<Reader> reader) {
+  _readers.push_back(std::move(reader));
+}
+
+void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
+  _yamlHandlers.push_back(std::move(handler));
+}
+
+ErrorOr<std::unique_ptr<File>>
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
+  // Get file magic.
+  StringRef content(mb->getBufferStart(), mb->getBufferSize());
+  llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
+
+  // Ask each registered reader if it can handle this file type or extension.
+  for (const std::unique_ptr<Reader> &reader : _readers) {
+    if (!reader->canParse(fileType, mb->getMemBufferRef()))
+      continue;
+    return reader->loadFile(std::move(mb), *this);
+  }
+
+  // No Reader could parse this file.
+  return make_error_code(llvm::errc::executable_format_error);
+}
+
+static const Registry::KindStrings kindStrings[] = {
+    {Reference::kindLayoutAfter, "layout-after"},
+    {Reference::kindAssociate, "associate"},
+    LLD_KIND_STRING_END};
+
+Registry::Registry() {
+  addKindTable(Reference::KindNamespace::all, Reference::KindArch::all,
+               kindStrings);
+}
+
+bool Registry::handleTaggedDoc(llvm::yaml::IO &io,
+                               const lld::File *&file) const {
+  for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers)
+    if (h->handledDocTag(io, file))
+      return true;
+  return false;
+}
+
+
+void Registry::addKindTable(Reference::KindNamespace ns,
+                            Reference::KindArch arch,
+                            const KindStrings array[]) {
+  KindEntry entry = { ns, arch, array };
+  _kindEntries.push_back(entry);
+}
+
+bool Registry::referenceKindFromString(StringRef inputStr,
+                                       Reference::KindNamespace &ns,
+                                       Reference::KindArch &arch,
+                                       Reference::KindValue &value) const {
+  for (const KindEntry &entry : _kindEntries) {
+    for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+      if (!inputStr.equals(pair->name))
+        continue;
+      ns = entry.ns;
+      arch = entry.arch;
+      value = pair->value;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Registry::referenceKindToString(Reference::KindNamespace ns,
+                                     Reference::KindArch arch,
+                                     Reference::KindValue value,
+                                     StringRef &str) const {
+  for (const KindEntry &entry : _kindEntries) {
+    if (entry.ns != ns)
+      continue;
+    if (entry.arch != arch)
+      continue;
+    for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+      if (pair->value != value)
+        continue;
+      str = pair->name;
+      return true;
+    }
+  }
+  return false;
+}
+
+} // end namespace lld
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
new file mode 100644 (file)
index 0000000..ef694fd
--- /dev/null
@@ -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 <algorithm>
+#include <cassert>
+#include <utility>
+#include <vector>
+
+namespace lld {
+
+llvm::Expected<bool> Resolver::handleFile(File &file) {
+  if (auto ec = _ctx.handleLoadedFile(file))
+    return std::move(ec);
+  bool undefAdded = false;
+  for (auto &atom : file.defined().owning_ptrs())
+    doDefinedAtom(std::move(atom));
+  for (auto &atom : file.undefined().owning_ptrs()) {
+    if (doUndefinedAtom(std::move(atom)))
+      undefAdded = true;
+  }
+  for (auto &atom : file.sharedLibrary().owning_ptrs())
+    doSharedLibraryAtom(std::move(atom));
+  for (auto &atom : file.absolute().owning_ptrs())
+    doAbsoluteAtom(std::move(atom));
+  return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::forEachUndefines(File &file,
+                                                UndefCallback callback) {
+  size_t i = _undefineIndex[&file];
+  bool undefAdded = false;
+  do {
+    for (; i < _undefines.size(); ++i) {
+      StringRef undefName = _undefines[i];
+      if (undefName.empty())
+        continue;
+      const Atom *atom = _symbolTable.findByName(undefName);
+      if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) {
+        // The symbol was resolved by some other file. Cache the result.
+        _undefines[i] = "";
+        continue;
+      }
+      auto undefAddedOrError = callback(undefName);
+      if (auto ec = undefAddedOrError.takeError())
+        return std::move(ec);
+      undefAdded |= undefAddedOrError.get();
+    }
+  } while (i < _undefines.size());
+  _undefineIndex[&file] = i;
+  return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::handleArchiveFile(File &file) {
+  ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
+  return forEachUndefines(file,
+                          [&](StringRef undefName) -> llvm::Expected<bool> {
+    if (File *member = archiveFile->find(undefName)) {
+      member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      return handleFile(*member);
+    }
+    return false;
+  });
+}
+
+llvm::Error Resolver::handleSharedLibrary(File &file) {
+  // Add all the atoms from the shared library
+  SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
+  auto undefAddedOrError = handleFile(*sharedLibrary);
+  if (auto ec = undefAddedOrError.takeError())
+    return ec;
+  undefAddedOrError =
+      forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> {
+        auto atom = sharedLibrary->exports(undefName);
+        if (atom.get())
+          doSharedLibraryAtom(std::move(atom));
+        return false;
+      });
+
+  if (auto ec = undefAddedOrError.takeError())
+    return ec;
+  return llvm::Error();
+}
+
+bool Resolver::doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "       UndefinedAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name=" << atom.get()->name() << "\n");
+
+  // tell symbol table
+  bool newUndefAdded = _symbolTable.add(*atom.get());
+  if (newUndefAdded)
+    _undefines.push_back(atom.get()->name());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+
+  return newUndefAdded;
+}
+
+// Called on each atom when a file is added. Returns true if a given
+// atom is added to the symbol table.
+void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "         DefinedAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", file=#"
+                    << atom.get()->file().ordinal()
+                    << ", atom=#"
+                    << atom.get()->ordinal()
+                    << ", name="
+                    << atom.get()->name()
+                    << ", type="
+                    << atom.get()->contentType()
+                    << "\n");
+
+  // An atom that should never be dead-stripped is a dead-strip root.
+  if (_ctx.deadStrip() &&
+      atom.get()->deadStrip() == DefinedAtom::deadStripNever) {
+    _deadStripRoots.insert(atom.get());
+  }
+
+  // add to list of known atoms
+  _symbolTable.add(*atom.get());
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "   SharedLibraryAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name="
+                    << atom.get()->name()
+                    << "\n");
+
+  // tell symbol table
+  _symbolTable.add(*atom.get());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "       AbsoluteAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name="
+                    << atom.get()->name()
+                    << "\n");
+
+  // tell symbol table
+  if (atom.get()->scope() != Atom::scopeTranslationUnit)
+    _symbolTable.add(*atom.get());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int begin, int end) {
+  std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+  for (int i = begin; i < end; ++i)
+    if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
+      if (_newUndefinesAdded[node->getFile()])
+        return true;
+  return false;
+}
+
+File *Resolver::getFile(int &index) {
+  std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+  if ((size_t)index >= inputs.size())
+    return nullptr;
+  if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
+    // We are at the end of the current group. If one or more new
+    // undefined atom has been added in the last groupSize files, we
+    // reiterate over the files.
+    int size = group->getSize();
+    if (undefinesAdded(index - size, index)) {
+      index -= size;
+      return getFile(index);
+    }
+    ++index;
+    return getFile(index);
+  }
+  return cast<FileNode>(inputs[index++].get())->getFile();
+}
+
+// Keep adding atoms until _ctx.getNextFile() returns an error. This
+// function is where undefined atoms are resolved.
+bool Resolver::resolveUndefines() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Resolving undefines:\n");
+  ScopedTask task(getDefaultDomain(), "resolveUndefines");
+  int index = 0;
+  std::set<File *> seen;
+  for (;;) {
+    bool undefAdded = false;
+    DEBUG_WITH_TYPE("resolver",
+                    llvm::dbgs() << "Loading file #" << index << "\n");
+    File *file = getFile(index);
+    if (!file)
+      return true;
+    if (std::error_code ec = file->parse()) {
+      llvm::errs() << "Cannot open " + file->path()
+                   << ": " << ec.message() << "\n";
+      return false;
+    }
+    DEBUG_WITH_TYPE("resolver",
+                    llvm::dbgs() << "Loaded file: " << file->path() << "\n");
+    switch (file->kind()) {
+    case File::kindErrorObject:
+    case File::kindNormalizedObject:
+    case File::kindMachObject:
+    case File::kindCEntryObject:
+    case File::kindHeaderObject:
+    case File::kindEntryObject:
+    case File::kindUndefinedSymsObject:
+    case File::kindStubHelperObject:
+    case File::kindResolverMergedObject:
+    case File::kindSectCreateObject: {
+      // The same file may be visited more than once if the file is
+      // in --start-group and --end-group. Only library files should
+      // be processed more than once.
+      if (seen.count(file))
+        break;
+      seen.insert(file);
+      assert(!file->hasOrdinal());
+      file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      auto undefAddedOrError = handleFile(*file);
+      if (auto EC = undefAddedOrError.takeError()) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      undefAdded = undefAddedOrError.get();
+      break;
+    }
+    case File::kindArchiveLibrary: {
+      if (!file->hasOrdinal())
+        file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      auto undefAddedOrError = handleArchiveFile(*file);
+      if (auto EC = undefAddedOrError.takeError()) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      undefAdded = undefAddedOrError.get();
+      break;
+    }
+    case File::kindSharedLibrary:
+      if (!file->hasOrdinal())
+        file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      if (auto EC = handleSharedLibrary(*file)) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      break;
+    }
+    _newUndefinesAdded[file] = undefAdded;
+  }
+}
+
+// switch all references to undefined or coalesced away atoms
+// to the new defined atom
+void Resolver::updateReferences() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Updating references:\n");
+  ScopedTask task(getDefaultDomain(), "updateReferences");
+  for (const OwningAtomPtr<Atom> &atom : _atoms) {
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) {
+      for (const Reference *ref : *defAtom) {
+        // A reference of type kindAssociate should't be updated.
+        // Instead, an atom having such reference will be removed
+        // if the target atom is coalesced away, so that they will
+        // go away as a group.
+        if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+            ref->kindValue() == lld::Reference::kindAssociate) {
+          if (_symbolTable.isCoalescedAway(atom.get()))
+            _deadAtoms.insert(ref->target());
+          continue;
+        }
+        const Atom *newTarget = _symbolTable.replacement(ref->target());
+        const_cast<Reference *>(ref)->setTarget(newTarget);
+      }
+    }
+  }
+}
+
+// For dead code stripping, recursively mark atoms "live"
+void Resolver::markLive(const Atom *atom) {
+  // Mark the atom is live. If it's already marked live, then stop recursion.
+  auto exists = _liveAtoms.insert(atom);
+  if (!exists.second)
+    return;
+
+  // Mark all atoms it references as live
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+    for (const Reference *ref : *defAtom)
+      markLive(ref->target());
+    for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) {
+      const Atom *target = p.second;
+      markLive(target);
+    }
+  }
+}
+
+static bool isBackref(const Reference *ref) {
+  if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
+    return false;
+  return (ref->kindValue() == lld::Reference::kindLayoutAfter);
+}
+
+// remove all atoms not actually used
+void Resolver::deadStripOptimize() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Dead stripping unused atoms:\n");
+  ScopedTask task(getDefaultDomain(), "deadStripOptimize");
+  // only do this optimization with -dead_strip
+  if (!_ctx.deadStrip())
+    return;
+
+  // Some type of references prevent referring atoms to be dead-striped.
+  // Make a reverse map of such references before traversing the graph.
+  // While traversing the list of atoms, mark AbsoluteAtoms as live
+  // in order to avoid reclaim.
+  for (const OwningAtomPtr<Atom> &atom : _atoms) {
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+      for (const Reference *ref : *defAtom)
+        if (isBackref(ref))
+          _reverseRef.insert(std::make_pair(ref->target(), atom.get()));
+    if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get()))
+      markLive(absAtom);
+  }
+
+  // By default, shared libraries are built with all globals as dead strip roots
+  if (_ctx.globalsAreDeadStripRoots())
+    for (const OwningAtomPtr<Atom> &atom : _atoms)
+      if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+        if (defAtom->scope() == DefinedAtom::scopeGlobal)
+          _deadStripRoots.insert(defAtom);
+
+  // Or, use list of names that are dead strip roots.
+  for (const StringRef &name : _ctx.deadStripRoots()) {
+    const Atom *symAtom = _symbolTable.findByName(name);
+    assert(symAtom);
+    _deadStripRoots.insert(symAtom);
+  }
+
+  // mark all roots as live, and recursively all atoms they reference
+  for (const Atom *dsrAtom : _deadStripRoots)
+    markLive(dsrAtom);
+
+  // now remove all non-live atoms from _atoms
+  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+                              [&](OwningAtomPtr<Atom> &a) {
+                 return _liveAtoms.count(a.get()) == 0;
+               }),
+               _atoms.end());
+}
+
+// error out if some undefines remain
+bool Resolver::checkUndefines() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Checking for undefines:\n");
+
+  // build vector of remaining undefined symbols
+  std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
+  if (_ctx.deadStrip()) {
+    // When dead code stripping, we don't care if dead atoms are undefined.
+    undefinedAtoms.erase(
+        std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
+                       [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
+        undefinedAtoms.end());
+  }
+
+  if (undefinedAtoms.empty())
+    return false;
+
+  // Warn about unresolved symbols.
+  bool foundUndefines = false;
+  for (const UndefinedAtom *undef : undefinedAtoms) {
+    // Skip over a weak symbol.
+    if (undef->canBeNull() != UndefinedAtom::canBeNullNever)
+      continue;
+
+    // If this is a library and undefined symbols are allowed on the
+    // target platform, skip over it.
+    if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines())
+      continue;
+
+    // If the undefine is coalesced away, skip over it.
+    if (_symbolTable.isCoalescedAway(undef))
+      continue;
+
+    // Seems like this symbol is undefined. Warn that.
+    foundUndefines = true;
+    if (_ctx.printRemainingUndefines()) {
+      llvm::errs() << "Undefined symbol: " << undef->file().path()
+                   << ": " << _ctx.demangle(undef->name())
+                   << "\n";
+    }
+  }
+  if (!foundUndefines)
+    return false;
+  if (_ctx.printRemainingUndefines())
+    llvm::errs() << "symbol(s) not found\n";
+  return true;
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Removing coalesced away atoms:\n");
+  ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
+  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+                              [&](OwningAtomPtr<Atom> &a) {
+                 return _symbolTable.isCoalescedAway(a.get()) ||
+                        _deadAtoms.count(a.get());
+               }),
+               _atoms.end());
+}
+
+bool Resolver::resolve() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Resolving atom references:\n");
+  if (!resolveUndefines())
+    return false;
+  updateReferences();
+  deadStripOptimize();
+  if (checkUndefines()) {
+    DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Found undefines... ");
+    if (!_ctx.allowRemainingUndefines()) {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we don't allow\n");
+      return false;
+    }
+    DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we are ok with\n");
+  }
+  removeCoalescedAwayAtoms();
+  _result->addAtoms(_atoms);
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Finished resolver\n");
+  return true;
+}
+
+void Resolver::MergedFile::addAtoms(
+                              llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) {
+  ScopedTask task(getDefaultDomain(), "addAtoms");
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+
+  for (OwningAtomPtr<Atom> &atom : all) {
+#ifndef NDEBUG
+    if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                      << llvm::format("    0x%09lX", definedAtom)
+                      << ", file=#"
+                      << definedAtom->file().ordinal()
+                      << ", atom=#"
+                      << definedAtom->ordinal()
+                      << ", name="
+                      << definedAtom->name()
+                      << ", type="
+                      << definedAtom->contentType()
+                      << "\n");
+    } else {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                      << llvm::format("    0x%09lX", atom.get())
+                      << ", name="
+                      << atom.get()->name()
+                      << "\n");
+    }
+#endif
+    addAtom(*atom.release());
+  }
+}
+
+} // namespace lld
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..44631a5
--- /dev/null
@@ -0,0 +1,319 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace lld {
+bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const DefinedAtom &atom) {
+  if (!atom.name().empty() &&
+      atom.scope() != DefinedAtom::scopeTranslationUnit) {
+    // Named atoms cannot be merged by content.
+    assert(atom.merge() != DefinedAtom::mergeByContent);
+    // Track named atoms that are not scoped to file (static).
+    return addByName(atom);
+  }
+  if (atom.merge() == DefinedAtom::mergeByContent) {
+    // Named atoms cannot be merged by content.
+    assert(atom.name().empty());
+    // Currently only read-only constants can be merged.
+    if (atom.permissions() == DefinedAtom::permR__)
+      return addByContent(atom);
+    // TODO: support mergeByContent of data atoms by comparing content & fixups.
+  }
+  return false;
+}
+
+enum NameCollisionResolution {
+  NCR_First,
+  NCR_Second,
+  NCR_DupDef,
+  NCR_DupUndef,
+  NCR_DupShLib,
+  NCR_Error
+};
+
+static NameCollisionResolution cases[4][4] = {
+  //regular     absolute    undef      sharedLib
+  {
+    // first is regular
+    NCR_DupDef, NCR_Error,   NCR_First, NCR_First
+  },
+  {
+    // first is absolute
+    NCR_Error,  NCR_Error,  NCR_First, NCR_First
+  },
+  {
+    // first is undef
+    NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
+  },
+  {
+    // first is sharedLib
+    NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
+  }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+                                       Atom::Definition second) {
+  return cases[first][second];
+}
+
+enum MergeResolution {
+  MCR_First,
+  MCR_Second,
+  MCR_Largest,
+  MCR_SameSize,
+  MCR_Error
+};
+
+static MergeResolution mergeCases[][6] = {
+  // no          tentative      weak          weakAddress   sameNameAndSize largest
+  {MCR_Error,    MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // no
+  {MCR_Second,   MCR_Largest,   MCR_Second,   MCR_Second,   MCR_SameSize,   MCR_Largest},  // tentative
+  {MCR_Second,   MCR_First,     MCR_First,    MCR_Second,   MCR_SameSize,   MCR_Largest},  // weak
+  {MCR_Second,   MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // weakAddress
+  {MCR_SameSize, MCR_SameSize,  MCR_SameSize, MCR_SameSize, MCR_SameSize,   MCR_SameSize}, // sameSize
+  {MCR_Largest,  MCR_Largest,   MCR_Largest,  MCR_Largest,  MCR_SameSize,   MCR_Largest},  // largest
+};
+
+static MergeResolution mergeSelect(DefinedAtom::Merge first,
+                                   DefinedAtom::Merge second) {
+  assert(first != DefinedAtom::mergeByContent);
+  assert(second != DefinedAtom::mergeByContent);
+  return mergeCases[first][second];
+}
+
+bool SymbolTable::addByName(const Atom &newAtom) {
+  StringRef name = newAtom.name();
+  assert(!name.empty());
+  const Atom *existing = findByName(name);
+  if (existing == nullptr) {
+    // Name is not in symbol table yet, add it associate with this atom.
+    _nameTable[name] = &newAtom;
+    return true;
+  }
+
+  // Do nothing if the same object is added more than once.
+  if (existing == &newAtom)
+    return false;
+
+  // Name is already in symbol table and associated with another atom.
+  bool useNew = true;
+  switch (collide(existing->definition(), newAtom.definition())) {
+  case NCR_First:
+    useNew = false;
+    break;
+  case NCR_Second:
+    useNew = true;
+    break;
+  case NCR_DupDef: {
+    const auto *existingDef = cast<DefinedAtom>(existing);
+    const auto *newDef = cast<DefinedAtom>(&newAtom);
+    switch (mergeSelect(existingDef->merge(), newDef->merge())) {
+    case MCR_First:
+      useNew = false;
+      break;
+    case MCR_Second:
+      useNew = true;
+      break;
+    case MCR_Largest: {
+      uint64_t existingSize = existingDef->sectionSize();
+      uint64_t newSize = newDef->sectionSize();
+      useNew = (newSize >= existingSize);
+      break;
+    }
+    case MCR_SameSize: {
+      uint64_t existingSize = existingDef->sectionSize();
+      uint64_t newSize = newDef->sectionSize();
+      if (existingSize == newSize) {
+        useNew = true;
+        break;
+      }
+      llvm::errs() << "Size mismatch: "
+                   << existing->name() << " (" << existingSize << ") "
+                   << newAtom.name() << " (" << newSize << ")\n";
+      // fallthrough
+    }
+    case MCR_Error:
+      llvm::errs() << "Duplicate symbols: "
+                   << existing->name()
+                   << ":"
+                   << existing->file().path()
+                   << " and "
+                   << newAtom.name()
+                   << ":"
+                   << newAtom.file().path()
+                   << "\n";
+      llvm::report_fatal_error("duplicate symbol error");
+      break;
+    }
+    break;
+  }
+  case NCR_DupUndef: {
+    const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing);
+    const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
+
+    bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
+    if (sameCanBeNull)
+      useNew = false;
+    else
+      useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
+    break;
+  }
+  case NCR_DupShLib: {
+    useNew = false;
+    break;
+  }
+  case NCR_Error:
+    llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+    llvm::report_fatal_error("duplicate symbol error");
+    break;
+  }
+
+  if (useNew) {
+    // Update name table to use new atom.
+    _nameTable[name] = &newAtom;
+    // Add existing atom to replacement table.
+    _replacedAtoms[existing] = &newAtom;
+  } else {
+    // New atom is not being used.  Add it to replacement table.
+    _replacedAtoms[&newAtom] = existing;
+  }
+  return false;
+}
+
+unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
+  auto content = atom->rawContent();
+  return llvm::hash_combine(atom->size(),
+                            atom->contentType(),
+                            llvm::hash_combine_range(content.begin(),
+                                                     content.end()));
+}
+
+bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
+                                           const DefinedAtom * const r) {
+  if (l == r)
+    return true;
+  if (l == getEmptyKey())
+    return false;
+  if (r == getEmptyKey())
+    return false;
+  if (l == getTombstoneKey())
+    return false;
+  if (r == getTombstoneKey())
+    return false;
+  if (l->contentType() != r->contentType())
+    return false;
+  if (l->size() != r->size())
+    return false;
+  if (l->sectionChoice() != r->sectionChoice())
+    return false;
+  if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+    if (!l->customSectionName().equals(r->customSectionName()))
+      return false;
+  }
+  ArrayRef<uint8_t> lc = l->rawContent();
+  ArrayRef<uint8_t> rc = r->rawContent();
+  return memcmp(lc.data(), rc.data(), lc.size()) == 0;
+}
+
+bool SymbolTable::addByContent(const DefinedAtom &newAtom) {
+  AtomContentSet::iterator pos = _contentTable.find(&newAtom);
+  if (pos == _contentTable.end()) {
+    _contentTable.insert(&newAtom);
+    return true;
+  }
+  const Atom* existing = *pos;
+  // New atom is not being used.  Add it to replacement table.
+  _replacedAtoms[&newAtom] = existing;
+  return false;
+}
+
+const Atom *SymbolTable::findByName(StringRef sym) {
+  NameToAtom::iterator pos = _nameTable.find(sym);
+  if (pos == _nameTable.end())
+    return nullptr;
+  return pos->second;
+}
+
+bool SymbolTable::isDefined(StringRef sym) {
+  if (const Atom *atom = findByName(sym))
+    return !isa<UndefinedAtom>(atom);
+  return false;
+}
+
+void SymbolTable::addReplacement(const Atom *replaced,
+                                 const Atom *replacement) {
+  _replacedAtoms[replaced] = replacement;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+  // Find the replacement for a given atom. Atoms in _replacedAtoms
+  // may be chained, so find the last one.
+  for (;;) {
+    AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+    if (pos == _replacedAtoms.end())
+      return atom;
+    atom = pos->second;
+  }
+}
+
+bool SymbolTable::isCoalescedAway(const Atom *atom) {
+  return _replacedAtoms.count(atom) > 0;
+}
+
+std::vector<const UndefinedAtom *> SymbolTable::undefines() {
+  std::vector<const UndefinedAtom *> ret;
+  for (auto it : _nameTable) {
+    const Atom *atom = it.second;
+    assert(atom != nullptr);
+    if (const auto *undef = dyn_cast<const UndefinedAtom>(atom))
+      if (_replacedAtoms.count(undef) == 0)
+        ret.push_back(undef);
+  }
+  return ret;
+}
+
+std::vector<StringRef> SymbolTable::tentativeDefinitions() {
+  std::vector<StringRef> ret;
+  for (auto entry : _nameTable) {
+    const Atom *atom = entry.second;
+    StringRef name   = entry.first;
+    assert(atom != nullptr);
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+      if (defAtom->merge() == DefinedAtom::mergeAsTentative)
+        ret.push_back(name);
+  }
+  return ret;
+}
+
+} // namespace lld
diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp
new file mode 100644 (file)
index 0000000..93e6438
--- /dev/null
@@ -0,0 +1,19 @@
+//===- lib/Core/Writer.cpp ------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+
+namespace lld {
+Writer::Writer() {
+}
+
+Writer::~Writer() {
+}
+} // end namespace lld
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1bd1f21
--- /dev/null
@@ -0,0 +1,22 @@
+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_LIBS
+    lldConfig
+    lldMachO
+    lldCore
+    lldReaderWriter
+    lldYAML
+    LLVMObject
+    LLVMOption
+    LLVMSupport
+  )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
new file mode 100644 (file)
index 0000000..496b651
--- /dev/null
@@ -0,0 +1,1215 @@
+//===- 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/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+               HELP, META) \
+          OPT_##ID,
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+               HELPTEXT, METAVAR)   \
+  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+    PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+  DarwinLdOptTable() : OptTable(infoTable) {}
+};
+
+static std::vector<std::unique_ptr<File>>
+makeErrorFile(StringRef path, std::error_code ec) {
+  std::vector<std::unique_ptr<File>> result;
+  result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+  return result;
+}
+
+static std::vector<std::unique_ptr<File>>
+parseMemberFiles(std::unique_ptr<File> file) {
+  std::vector<std::unique_ptr<File>> members;
+  if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+    if (std::error_code ec = archive->parseAllMembers(members))
+      return makeErrorFile(file->path(), ec);
+  } else {
+    members.push_back(std::move(file));
+  }
+  return members;
+}
+
+std::vector<std::unique_ptr<File>>
+loadFile(MachOLinkingContext &ctx, StringRef path,
+         raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+  if (ctx.logInputFiles())
+    diag << path << "\n";
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
+  if (std::error_code ec = mbOrErr.getError())
+    return makeErrorFile(path, ec);
+  ErrorOr<std::unique_ptr<File>> fileOrErr =
+      ctx.registry().loadFile(std::move(mbOrErr.get()));
+  if (std::error_code ec = fileOrErr.getError())
+    return makeErrorFile(path, ec);
+  std::unique_ptr<File> &file = fileOrErr.get();
+
+  // If file is a dylib, inform LinkingContext about it.
+  if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(file.get())) {
+    if (std::error_code ec = shl->parse())
+      return makeErrorFile(path, ec);
+    ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile *>(shl),
+                      upwardDylib);
+  }
+  if (wholeArchive)
+    return parseMemberFiles(std::move(file));
+  std::vector<std::unique_ptr<File>> files;
+  files.push_back(std::move(file));
+  return files;
+}
+
+} // anonymous namespace
+
+// Test may be running on Windows. Canonicalize the path
+// separator to '/' to get consistent outputs for tests.
+static std::string canonicalizePath(StringRef path) {
+  char sep = llvm::sys::path::get_separator().front();
+  if (sep != '/') {
+    std::string fixedPath = path;
+    std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
+    return fixedPath;
+  } else {
+    return path;
+  }
+}
+
+static void addFile(StringRef path, MachOLinkingContext &ctx,
+                    bool loadWholeArchive,
+                    bool upwardDylib, raw_ostream &diag) {
+  std::vector<std::unique_ptr<File>> files =
+      loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+  for (std::unique_ptr<File> &file : files)
+    ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+}
+
+// Export lists are one symbol per line.  Blank lines are ignored.
+// Trailing comments start with #.
+static std::error_code parseExportsList(StringRef exportFilePath,
+                                        MachOLinkingContext &ctx,
+                                        raw_ostream &diagnostics) {
+  // Map in export list file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                   MemoryBuffer::getFileOrSTDIN(exportFilePath);
+  if (std::error_code ec = mb.getError())
+    return ec;
+  ctx.addInputFileDependency(exportFilePath);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    // Ignore trailing # comments.
+    std::pair<StringRef, StringRef> symAndComment = line.split('#');
+    StringRef sym = symAndComment.first.trim();
+    if (!sym.empty())
+      ctx.addExportSymbol(sym);
+    buffer = lineAndRest.second;
+  }
+  return std::error_code();
+}
+
+
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name.  Examples:
+///     _foo
+///     bar.o:_bar
+///     libfrob.a(bar.o):_bar
+///     x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+                                      MachOLinkingContext &ctx,
+                                      raw_ostream &diagnostics) {
+  // Map in order file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                   MemoryBuffer::getFileOrSTDIN(orderFilePath);
+  if (std::error_code ec = mb.getError())
+    return ec;
+  ctx.addInputFileDependency(orderFilePath);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    buffer = lineAndRest.second;
+    // Ignore trailing # comments.
+    std::pair<StringRef, StringRef> symAndComment = line.split('#');
+    if (symAndComment.first.empty())
+      continue;
+    StringRef sym = symAndComment.first.trim();
+    if (sym.empty())
+      continue;
+    // Check for prefix.
+    StringRef prefix;
+    std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+    if (!prefixAndSym.second.empty()) {
+      sym = prefixAndSym.second;
+      prefix = prefixAndSym.first;
+      if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+        // If arch name prefix does not match arch being linked, ignore symbol.
+        if (!ctx.archName().equals(prefix))
+          continue;
+        prefix = "";
+      }
+    } else
+     sym = prefixAndSym.first;
+    if (!sym.empty()) {
+      ctx.appendOrderedSymbol(sym, prefix);
+      //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+    }
+  }
+  return std::error_code();
+}
+
+//
+// There are two variants of the  -filelist option:
+//
+//   -filelist <path>
+// In this variant, the path is to a text file which contains one file path
+// per line.  There are no comments or trimming of whitespace.
+//
+//   -fileList <path>,<dir>
+// In this variant, the path is to a text file which contains a partial path
+// per line. The <dir> prefix is prepended to each partial path.
+//
+static llvm::Error loadFileList(StringRef fileListPath,
+                                MachOLinkingContext &ctx, bool forceLoad,
+                                raw_ostream &diagnostics) {
+  // If there is a comma, split off <dir>.
+  std::pair<StringRef, StringRef> opt = fileListPath.split(',');
+  StringRef filePath = opt.first;
+  StringRef dirName = opt.second;
+  ctx.addInputFileDependency(filePath);
+  // Map in file list file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                        MemoryBuffer::getFileOrSTDIN(filePath);
+  if (std::error_code ec = mb.getError())
+    return llvm::errorCodeToError(ec);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    StringRef path;
+    if (!dirName.empty()) {
+      // If there is a <dir> then prepend dir to each line.
+      SmallString<256> fullPath;
+      fullPath.assign(dirName);
+      llvm::sys::path::append(fullPath, Twine(line));
+      path = ctx.copy(fullPath.str());
+    } else {
+      // No <dir> use whole line as input file path.
+      path = ctx.copy(line);
+    }
+    if (!ctx.pathExists(path)) {
+      return llvm::make_error<GenericError>(Twine("File not found '")
+                                            + path
+                                            + "'");
+    }
+    if (ctx.testingFileUsage()) {
+      diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+    }
+    addFile(path, ctx, forceLoad, false, diagnostics);
+    buffer = lineAndRest.second;
+  }
+  return llvm::Error();
+}
+
+/// Parse number assuming it is base 16, but allow 0x prefix.
+static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
+  if (numStr.startswith_lower("0x"))
+    numStr = numStr.drop_front(2);
+  return numStr.getAsInteger(16, baseAddress);
+}
+
+static void parseLLVMOptions(const LinkingContext &ctx) {
+  // Honor -mllvm
+  if (!ctx.llvmOptions().empty()) {
+    unsigned numArgs = ctx.llvmOptions().size();
+    auto **args = new const char *[numArgs + 2];
+    args[0] = "lld (LLVM option parsing)";
+    for (unsigned i = 0; i != numArgs; ++i)
+      args[i + 1] = ctx.llvmOptions()[i];
+    args[numArgs + 1] = nullptr;
+    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+  }
+}
+
+namespace lld {
+namespace mach_o {
+
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
+           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 <path> used by Xcode.
+  if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) {
+    if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
+      diagnostics << "warning: " << ec.message()
+                  << ", processing '-dependency_info "
+                  << depInfo->getValue()
+                  << "'\n";
+    }
+  }
+
+  // In -test_file_usage mode, we'll be given an explicit list of paths that
+  // exist. We'll also be expected to print out information about how we located
+  // libraries and so on that the user specified, but not to actually do any
+  // linking.
+  if (parsedArgs.getLastArg(OPT_test_file_usage)) {
+    ctx.setTestingFileUsage();
+
+    // With paths existing by fiat, linking is not going to end well.
+    ctx.setDoNothing(true);
+
+    // Only bother looking for an existence override if we're going to use it.
+    for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) {
+      ctx.addExistingPathForDebug(existingPath->getValue());
+    }
+  }
+
+  // Register possible input file parsers.
+  if (!ctx.doNothing()) {
+    ctx.registry().addSupportMachOObjects(ctx);
+    ctx.registry().addSupportArchives(ctx.logInputFiles());
+    ctx.registry().addSupportYamlFiles();
+  }
+
+  // Now construct the set of library search directories, following ld64's
+  // baroque set of accumulated hacks. Mostly, the algorithm constructs
+  //     { syslibroots } x { libpaths }
+  //
+  // Unfortunately, there are numerous exceptions:
+  //   1. Only absolute paths get modified by syslibroot options.
+  //   2. If there is just 1 -syslibroot, system paths not found in it are
+  //      skipped.
+  //   3. If the last -syslibroot is "/", all of them are ignored entirely.
+  //   4. If { syslibroots } x path ==  {}, the original path is kept.
+  std::vector<StringRef> sysLibRoots;
+  for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) {
+    sysLibRoots.push_back(syslibRoot->getValue());
+  }
+  if (!sysLibRoots.empty()) {
+    // Ignore all if last -syslibroot is "/".
+    if (sysLibRoots.back() != "/")
+      ctx.setSysLibRoots(sysLibRoots);
+  }
+
+  // Paths specified with -L come first, and are not considered system paths for
+  // the case where there is precisely 1 -syslibroot.
+  for (auto libPath : parsedArgs.filtered(OPT_L)) {
+    ctx.addModifiedSearchDir(libPath->getValue());
+  }
+
+  // Process -F directories (where to look for frameworks).
+  for (auto fwPath : parsedArgs.filtered(OPT_F)) {
+    ctx.addFrameworkSearchDir(fwPath->getValue());
+  }
+
+  // -Z suppresses the standard search paths.
+  if (!parsedArgs.hasArg(OPT_Z)) {
+    ctx.addModifiedSearchDir("/usr/lib", true);
+    ctx.addModifiedSearchDir("/usr/local/lib", true);
+    ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+    ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
+  }
+
+  // Now that we've constructed the final set of search paths, print out those
+  // search paths in verbose mode.
+  if (parsedArgs.getLastArg(OPT_v)) {
+    diagnostics << "Library search paths:\n";
+    for (auto path : ctx.searchDirs()) {
+      diagnostics << "    " << path << '\n';
+    }
+    diagnostics << "Framework search paths:\n";
+    for (auto path : ctx.frameworkDirs()) {
+      diagnostics << "    " << path << '\n';
+    }
+  }
+
+  // Handle -exported_symbols_list <file>
+  for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+      diagnostics << "error: -exported_symbols_list cannot be combined "
+                  << "with -unexported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+    if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+                                              diagnostics)) {
+      diagnostics << "error: " << ec.message()
+                  << ", processing '-exported_symbols_list "
+                  << expFile->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+
+  // Handle -exported_symbol <symbol>
+  for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+      diagnostics << "error: -exported_symbol cannot be combined "
+                  << "with -unexported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+    ctx.addExportSymbol(symbol->getValue());
+  }
+
+  // Handle -unexported_symbols_list <file>
+  for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+      diagnostics << "error: -unexported_symbols_list cannot be combined "
+                  << "with -exported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+    if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+                                              diagnostics)) {
+      diagnostics << "error: " << ec.message()
+                  << ", processing '-unexported_symbols_list "
+                  << expFile->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+
+  // Handle -unexported_symbol <symbol>
+  for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+      diagnostics << "error: -unexported_symbol cannot be combined "
+                  << "with -exported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+    ctx.addExportSymbol(symbol->getValue());
+  }
+
+  // Handle obosolete -multi_module and -single_module
+  if (llvm::opt::Arg *mod =
+          parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) {
+    if (mod->getOption().getID() == OPT_multi_module) {
+      diagnostics << "warning: -multi_module is obsolete and being ignored\n";
+    }
+    else {
+      if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+        diagnostics << "warning: -single_module being ignored. "
+                       "It is only for use when producing a dylib\n";
+      }
+    }
+  }
+
+  // Handle 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;
+      break;
+    }
+  }
+
+  // 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 <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 <path>
+  if (parsedArgs.hasArg(OPT_rpath)) {
+    switch (ctx.outputMachOType()) {
+      case llvm::MachO::MH_EXECUTE:
+      case llvm::MachO::MH_DYLIB:
+      case llvm::MachO::MH_BUNDLE:
+        if (!ctx.minOS("10.5", "2.0")) {
+          if (ctx.os() == MachOLinkingContext::OS::macOSX) {
+            diagnostics << "error: -rpath can only be used when targeting "
+                           "OS X 10.5 or later\n";
+          } else {
+            diagnostics << "error: -rpath can only be used when targeting "
+                           "iOS 2.0 or later\n";
+          }
+          return false;
+        }
+        break;
+      default:
+        diagnostics << "error: -rpath can only be used when creating "
+                       "a dynamic final linked image\n";
+        return false;
+    }
+
+    for (auto rPath : parsedArgs.filtered(OPT_rpath)) {
+      ctx.addRpath(rPath->getValue());
+    }
+  }
+
+  // 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<StringRef> 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<std::unique_ptr<MemoryBuffer>> 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);
+}
+
+/// This is where the link is actually performed.
+bool link(llvm::ArrayRef<const char *> 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<Node> &ie : ctx.getNodes())
+    if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+      node->getFile()->parse();
+
+  std::vector<std::unique_ptr<File>> internalFiles;
+  ctx.createInternalFiles(internalFiles);
+  for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
+    auto &members = ctx.getNodes();
+    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+  }
+
+  // Give target a chance to add files.
+  std::vector<std::unique_ptr<File>> implicitFiles;
+  ctx.createImplicitFiles(implicitFiles);
+  for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
+    auto &members = ctx.getNodes();
+    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+  }
+
+  // Give target a chance to postprocess input files.
+  // Mach-O uses this chance to move all object files before library files.
+  ctx.finalizeInputFiles();
+
+  // Do core linking.
+  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+  Resolver resolver(ctx);
+  if (!resolver.resolve())
+    return false;
+  SimpleFile *merged = nullptr;
+  {
+    std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile();
+    merged = mergedFile.get();
+    auto &members = ctx.getNodes();
+    members.insert(members.begin(),
+                   llvm::make_unique<FileNode>(std::move(mergedFile)));
+  }
+  resolveTask.end();
+
+  // Run passes on linked atoms.
+  ScopedTask passTask(getDefaultDomain(), "Passes");
+  PassManager pm;
+  ctx.addPasses(pm);
+  if (auto ec = pm.runOnFile(*merged)) {
+    // FIXME: This should be passed to logAllUnhandledErrors but it needs
+    // to be passed a Twine instead of a string.
+    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;
+}
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
new file mode 100644 (file)
index 0000000..fa07f33
--- /dev/null
@@ -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<grp_kind>;
+def static : Flag<["-"], "static">,
+     HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+     HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def dylib : Flag<["-"], "dylib">,
+     HelpText<"Create dynamic library">, Group<grp_kind>;
+def bundle : Flag<["-"], "bundle">,
+     HelpText<"Create dynamic bundle">, Group<grp_kind>;
+def execute : Flag<["-"], "execute">,
+     HelpText<"Create main executable (default)">, Group<grp_kind>;
+def preload : Flag<["-"], "preload">,
+     HelpText<"Create binary for use with embedded systems">, Group<grp_kind>;
+
+// optimizations
+def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
+def dead_strip : Flag<["-"], "dead_strip">,
+     HelpText<"Remove unreference code and data">, Group<grp_opts>;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum iOS version">, Group<grp_opts>;
+def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
+     Alias<ios_version_min>;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def sdk_version : Separate<["-"], "sdk_version">,
+     MetaVarName<"<version>">,
+     HelpText<"SDK version">, Group<grp_opts>;
+def source_version : Separate<["-"], "source_version">,
+     MetaVarName<"<version>">,
+     HelpText<"Source version">, Group<grp_opts>;
+def version_load_command : Flag<["-"], "version_load_command">,
+     HelpText<"Force generation of a version load command">, Group<grp_opts>;
+def no_version_load_command : Flag<["-"], "no_version_load_command">,
+     HelpText<"Disable generation of a version load command">, Group<grp_opts>;
+def function_starts : Flag<["-"], "function_starts">,
+     HelpText<"Force generation of a function starts load command">,
+     Group<grp_opts>;
+def no_function_starts : Flag<["-"], "no_function_starts">,
+     HelpText<"Disable generation of a function starts load command">,
+     Group<grp_opts>;
+def data_in_code_info : Flag<["-"], "data_in_code_info">,
+     HelpText<"Force generation of a data in code load command">,
+     Group<grp_opts>;
+def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">,
+     HelpText<"Disable generation of a data in code load command">,
+     Group<grp_opts>;
+def mllvm : Separate<["-"], "mllvm">,
+     MetaVarName<"<option>">,
+     HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
+def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
+     MetaVarName<"<file-path>">,
+     HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def exported_symbol : Separate<["-"], "exported_symbol">,
+     MetaVarName<"<symbol>">,
+     HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
+     MetaVarName<"<file-path>">,
+     HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
+def unexported_symbol : Separate<["-"], "unexported_symbol">,
+     MetaVarName<"<symbol>">,
+     HelpText<"A symbol which should not be exported">, Group<grp_opts>;
+def keep_private_externs : Flag<["-"], "keep_private_externs">,
+     HelpText<"Private extern (hidden) symbols should not be transformed "
+              "into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+     MetaVarName<"<file-path>">,
+     HelpText<"re-order and move specified symbols to start of their section">,
+     Group<grp_opts>;
+def flat_namespace : Flag<["-"], "flat_namespace">,
+     HelpText<"Resolves symbols in any (transitively) linked dynamic libraries. "
+              "Source libraries are not recorded: dyld will re-search all "
+              "images at runtime and use the first definition found.">,
+     Group<grp_opts>;
+def twolevel_namespace : Flag<["-"], "twolevel_namespace">,
+     HelpText<"Resolves symbols in listed libraries only. Source libraries are "
+              "recorded in the symbol table.">,
+     Group<grp_opts>;
+def undefined : Separate<["-"], "undefined">,
+                MetaVarName<"<undefined>">,
+                HelpText<"Determines how undefined symbols are handled.">,
+                Group<grp_opts>;
+def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
+     HelpText<"Disables the optimisation which merges Objective-C categories "
+              "on a class in to the class itself.">,
+     Group<grp_opts>;
+
+// main executable options
+def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
+def entry : Separate<["-"], "e">,
+     MetaVarName<"<entry-name>">,
+     HelpText<"entry symbol name">,Group<grp_main>;
+def pie : Flag<["-"], "pie">,
+     HelpText<"Create Position Independent Executable (for ASLR)">,
+     Group<grp_main>;
+def no_pie : Flag<["-"], "no_pie">,
+     HelpText<"Do not create Position Independent Executable">,
+     Group<grp_main>;
+def stack_size : Separate<["-"], "stack_size">,
+     HelpText<"Specifies the maximum stack size for the main thread in a program. "
+              "Must be a page-size multiple. (default=8Mb)">,
+     Group<grp_main>;
+def export_dynamic : Flag<["-"], "export_dynamic">,
+     HelpText<"Preserves all global symbols in main executables during LTO">,
+     Group<grp_main>;
+
+// dylib executable options
+def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
+def install_name : Separate<["-"], "install_name">,
+     MetaVarName<"<path>">,
+     HelpText<"The dylib's install name">, Group<grp_dylib>;
+def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
+     HelpText<"Marks the dylib as having no side effects during initialization">,
+     Group<grp_dylib>;
+def compatibility_version : Separate<["-"], "compatibility_version">,
+     MetaVarName<"<version>">,
+     HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
+def current_version : Separate<["-"], "current_version">,
+     MetaVarName<"<version>">,
+     HelpText<"The dylib's current version">, Group<grp_dylib>;
+
+// dylib executable options - compatibility aliases
+def dylib_install_name : Separate<["-"], "dylib_install_name">,
+     Alias<install_name>;
+def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
+     MetaVarName<"<version>">, Alias<compatibility_version>;
+def dylib_current_version : Separate<["-"], "dylib_current_version">,
+     MetaVarName<"<version>">, Alias<current_version>;
+
+// bundle executable options
+def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
+def bundle_loader : Separate<["-"], "bundle_loader">,
+     MetaVarName<"<path>">,
+     HelpText<"The executable that will be loading this Mach-O bundle">,
+     Group<grp_bundle>;
+
+// library options
+def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
+def L : JoinedOrSeparate<["-"], "L">,
+     MetaVarName<"<dir>">,
+     HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+     MetaVarName<"<dir>">,
+     HelpText<"Add directory to framework search path">, Group<grp_libs>;
+def Z : Flag<["-"], "Z">,
+     HelpText<"Do not search standard directories for libraries or frameworks">;
+def all_load : Flag<["-"], "all_load">,
+     HelpText<"Forces all members of all static libraries to be loaded">,
+     Group<grp_libs>;
+def force_load : Separate<["-"], "force_load">,
+     MetaVarName<"<library-path>">,
+     HelpText<"Forces all members of specified static libraries to be loaded">,
+     Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">, MetaVarName<"<dir>">,
+     HelpText<"Add path to SDK to all absolute library search paths">,
+     Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+     MetaVarName<"<libname>">,
+     HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+     MetaVarName<"<libname>">,
+     HelpText<"Base name of upward library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+     MetaVarName<"<name>">,
+     HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+     MetaVarName<"<name>">,
+     HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+     MetaVarName<"<path>">,
+     HelpText<"path to upward dylib to link with">;
+def filelist : Separate<["-"], "filelist">,
+     MetaVarName<"<path>">,
+     HelpText<"file containing paths to input files">;
+
+
+// test case options
+def print_atoms : Flag<["-"], "print_atoms">,
+     HelpText<"Emit output as yaml atoms">;
+def test_file_usage : Flag<["-"], "test_file_usage">,
+     HelpText<"Only files specified by -file_exists are considered to exist. "
+              "Print which files would be used">;
+def path_exists : Separate<["-"], "path_exists">,
+     MetaVarName<"<path>">,
+     HelpText<"Used with -test_file_usage to declare a path">;
+
+
+// general options
+def output : Separate<["-"], "o">,
+     MetaVarName<"<path>">,
+     HelpText<"Output file path">;
+def arch : Separate<["-"], "arch">,
+     MetaVarName<"<arch-name>">,
+     HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+     MetaVarName<"<segname> <sectname> <alignment>">,
+     HelpText<"Alignment for segment/section">;
+def sectcreate : MultiArg<["-"], "sectcreate", 3>,
+     MetaVarName<"<segname> <sectname> <file>">,
+     HelpText<"Create section <segname>/<sectname> from contents of <file>">;
+def image_base : Separate<["-"], "image_base">;
+def seg1addr : Separate<["-"], "seg1addr">, Alias<image_base>;
+def demangle : Flag<["-"], "demangle">,
+     HelpText<"Demangles symbol names in errors and warnings">;
+def dependency_info : Separate<["-"], "dependency_info">,
+     MetaVarName<"<file>">,
+     HelpText<"Write binary list of files used during link">;
+def S : Flag<["-"], "S">,
+     HelpText<"Remove debug information (STABS or DWARF) from the output file">;
+def rpath : Separate<["-"], "rpath">,
+     MetaVarName<"<path>">,
+     HelpText<"Add path to the runpath search path list for image being created">;
+
+def t : Flag<["-"], "t">,
+     HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+     HelpText<"Print linker information">;
+
+// Obsolete options
+def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
+def single_module : Flag<["-"], "single_module">,
+     HelpText<"Default for dylibs">, Group<grp_obsolete>;
+def multi_module : Flag<["-"], "multi_module">,
+     HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>;
+def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc : Flag<["-"], "objc_gc">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc_only : Flag<["-"], "objc_gc_only">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4408d9c
--- /dev/null
@@ -0,0 +1,19 @@
+add_subdirectory(MachO)
+add_subdirectory(YAML)
+
+if (MSVC)
+  add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
+endif()
+
+add_lld_library(lldReaderWriter
+  FileArchive.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/ReaderWriter
+
+  LINK_LIBS
+    lldCore
+    lldYAML
+    LLVMObject
+    LLVMSupport
+  )
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
new file mode 100644 (file)
index 0000000..eb7e7fb
--- /dev/null
@@ -0,0 +1,222 @@
+//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+using llvm::object::Archive;
+
+namespace lld {
+
+namespace {
+
+/// \brief The FileArchive class represents an Archive Library file
+class FileArchive : public lld::ArchiveLibraryFile {
+public:
+  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
+              StringRef path, bool logLoading)
+      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
+        _registry(reg), _logLoading(logLoading) {}
+
+  /// \brief Check if any member of the archive contains an Atom with the
+  /// specified name and return the File object for that member, or nullptr.
+  File *find(StringRef name) override {
+    auto member = _symbolMemberMap.find(name);
+    if (member == _symbolMemberMap.end())
+      return nullptr;
+    Archive::Child c = member->second;
+
+    // Don't return a member already returned
+    ErrorOr<StringRef> buf = c.getBuffer();
+    if (!buf)
+      return nullptr;
+    const char *memberStart = buf->data();
+    if (_membersInstantiated.count(memberStart))
+      return nullptr;
+    _membersInstantiated.insert(memberStart);
+
+    std::unique_ptr<File> result;
+    if (instantiateMember(c, result))
+      return nullptr;
+
+    File *file = result.get();
+    _filesReturned.push_back(std::move(result));
+
+    // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive
+    return file;
+  }
+
+  /// \brief parse each member
+  std::error_code
+  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+    if (std::error_code ec = parse())
+      return ec;
+    llvm::Error err;
+    for (auto mf = _archive->child_begin(err), me = _archive->child_end();
+         mf != me; ++mf) {
+      std::unique_ptr<File> file;
+      if (std::error_code ec = instantiateMember(*mf, file)) {
+        // err is Success (or we wouldn't be in the loop body) but we can't
+        // return without testing or consuming it.
+        consumeError(std::move(err));
+        return ec;
+      }
+      result.push_back(std::move(file));
+    }
+    if (err)
+      return errorToErrorCode(std::move(err));
+    return std::error_code();
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _noDefinedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _noDefinedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+protected:
+  std::error_code doParse() override {
+    // Make Archive object which will be owned by FileArchive object.
+    llvm::Error Err;
+    _archive.reset(new Archive(_mb->getMemBufferRef(), Err));
+    if (Err)
+      return errorToErrorCode(std::move(Err));
+    std::error_code ec;
+    if ((ec = buildTableOfContents()))
+      return ec;
+    return std::error_code();
+  }
+
+private:
+  std::error_code instantiateMember(Archive::Child member,
+                                    std::unique_ptr<File> &result) const {
+    ErrorOr<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef();
+    if (std::error_code ec = mbOrErr.getError())
+      return ec;
+    llvm::MemoryBufferRef mb = mbOrErr.get();
+    std::string memberPath = (_archive->getFileName() + "("
+                           + mb.getBufferIdentifier() + ")").str();
+
+    if (_logLoading)
+      llvm::errs() << memberPath << "\n";
+
+    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
+        mb.getBuffer(), mb.getBufferIdentifier(), false));
+
+    ErrorOr<std::unique_ptr<File>> fileOrErr =
+        _registry.loadFile(std::move(memberMB));
+    if (std::error_code ec = fileOrErr.getError())
+      return ec;
+    result = std::move(fileOrErr.get());
+    if (std::error_code ec = result->parse())
+      return ec;
+    result->setArchivePath(_archive->getFileName());
+
+    // The memory buffer is co-owned by the archive file and the children,
+    // so that the bufffer is deallocated when all the members are destructed.
+    result->setSharedMemoryBuffer(_mb);
+    return std::error_code();
+  }
+
+  std::error_code buildTableOfContents() {
+    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
+                                       << "Table of contents for archive '"
+                                       << _archive->getFileName() << "':\n");
+    for (const Archive::Symbol &sym : _archive->symbols()) {
+      StringRef name = sym.getName();
+      ErrorOr<Archive::Child> memberOrErr = sym.getMember();
+      if (std::error_code ec = memberOrErr.getError())
+        return ec;
+      Archive::Child member = memberOrErr.get();
+      DEBUG_WITH_TYPE("FileArchive",
+                      llvm::dbgs()
+                          << llvm::format("0x%08llX ",
+                                          member.getBuffer()->data())
+                          << "'" << name << "'\n");
+      _symbolMemberMap.insert(std::make_pair(name, member));
+    }
+    return std::error_code();
+  }
+
+  typedef std::unordered_map<StringRef, Archive::Child> MemberMap;
+  typedef std::set<const char *> InstantiatedSet;
+
+  std::shared_ptr<MemoryBuffer> _mb;
+  const Registry &_registry;
+  std::unique_ptr<Archive> _archive;
+  MemberMap _symbolMemberMap;
+  InstantiatedSet _membersInstantiated;
+  bool _logLoading;
+  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
+  std::vector<std::unique_ptr<File>> _filesReturned;
+};
+
+class ArchiveReader : public Reader {
+public:
+  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef) const override {
+    return magic == llvm::sys::fs::file_magic::archive;
+  }
+
+  ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
+                                          const Registry &reg) const override {
+    StringRef path = mb->getBufferIdentifier();
+    std::unique_ptr<File> ret =
+        llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
+    return std::move(ret);
+  }
+
+private:
+  bool _logLoading;
+};
+
+} // anonymous namespace
+
+void Registry::addSupportArchives(bool logLoading) {
+  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler.cpp b/lib/ReaderWriter/MachO/ArchHandler.cpp
new file mode 100644 (file)
index 0000000..cb20907
--- /dev/null
@@ -0,0 +1,172 @@
+//===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+
+ArchHandler::ArchHandler() {
+}
+
+ArchHandler::~ArchHandler() {
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
+                                               MachOLinkingContext::Arch arch) {
+  switch (arch) {
+  case MachOLinkingContext::arch_x86_64:
+    return create_x86_64();
+  case MachOLinkingContext::arch_x86:
+    return create_x86();
+  case MachOLinkingContext::arch_armv6:
+  case MachOLinkingContext::arch_armv7:
+  case MachOLinkingContext::arch_armv7s:
+    return create_arm();
+  case MachOLinkingContext::arch_arm64:
+    return create_arm64();
+  default:
+    llvm_unreachable("Unknown arch");
+  }
+}
+
+
+bool ArchHandler::isLazyPointer(const Reference &ref) {
+  // A lazy bind entry is needed for a lazy pointer.
+  const StubInfo &info = stubInfo();
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
+    return false;
+  return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
+}
+
+
+ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
+  assert((reloc.type & 0xFFF0) == 0);
+  uint16_t result = reloc.type;
+  if (reloc.scattered)
+    result |= rScattered;
+  if (reloc.pcRel)
+    result |= rPcRel;
+  if (reloc.isExtern)
+    result |= rExtern;
+  switch(reloc.length) {
+  case 0:
+    break;
+  case 1:
+    result |= rLength2;
+    break;
+  case 2:
+    result |= rLength4;
+    break;
+  case 3:
+    result |= rLength8;
+    break;
+  default:
+    llvm_unreachable("bad r_length");
+  }
+  return result;
+}
+
+normalized::Relocation
+ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) {
+  normalized::Relocation result;
+  result.offset    = 0;
+  result.scattered = (pattern & rScattered);
+  result.type     = (RelocationInfoType)(pattern & 0xF);
+  result.pcRel    = (pattern & rPcRel);
+  result.isExtern = (pattern & rExtern);
+  result.value    = 0;
+  result.symbol    = 0;
+  switch (pattern & 0x300) {
+  case rLength1:
+    result.length = 0;
+    break;
+  case rLength2:
+    result.length = 1;
+    break;
+  case rLength4:
+    result.length = 2;
+    break;
+  case rLength8:
+    result.length = 3;
+    break;
+  }
+  return result;
+}
+
+void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset,
+                              uint32_t symbol, uint32_t value,
+                              RelocPattern pattern) {
+  normalized::Relocation reloc = relocFromPattern(pattern);
+  reloc.offset = offset;
+  reloc.symbol = symbol;
+  reloc.value  = value;
+  relocs.push_back(reloc);
+}
+
+
+int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) {
+    return read16(addr, isBig);
+}
+
+int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) {
+  return read32(addr, isBig);
+}
+
+uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) {
+  return read32(addr, isBig);
+}
+
+  int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) {
+  return read64(addr, isBig);
+}
+
+bool ArchHandler::isDwarfCIE(bool isBig, const DefinedAtom *atom) {
+  assert(atom->contentType() == DefinedAtom::typeCFI);
+  if (atom->rawContent().size() < sizeof(uint32_t))
+    return false;
+  uint32_t size = read32(atom->rawContent().data(), isBig);
+
+  uint32_t idOffset = sizeof(uint32_t);
+  if (size == 0xffffffffU)
+    idOffset += sizeof(uint64_t);
+
+  return read32(atom->rawContent().data() + idOffset, isBig) == 0;
+}
+
+const Atom *ArchHandler::fdeTargetFunction(const DefinedAtom *fde) {
+  for (auto ref : *fde) {
+    if (ref->kindNamespace() == Reference::KindNamespace::mach_o &&
+        ref->kindValue() == unwindRefToFunctionKind()) {
+      assert(ref->kindArch() == kindArch() && "unexpected Reference arch");
+      return ref->target();
+    }
+  }
+
+  return nullptr;
+}
+
+} // namespace mach_o
+} // namespace lld
+
+
+
diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
new file mode 100644 (file)
index 0000000..70a63bd
--- /dev/null
@@ -0,0 +1,319 @@
+//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// The ArchHandler class handles all architecture specific aspects of
+/// mach-o linking.
+///
+class ArchHandler {
+public:
+  virtual ~ArchHandler();
+
+  /// There is no public interface to subclasses of ArchHandler, so this
+  /// is the only way to instantiate an ArchHandler.
+  static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch);
+
+  /// Get (arch specific) kind strings used by Registry.
+  virtual const Registry::KindStrings *kindStrings() = 0;
+
+  /// Convert mach-o Arch to Reference::KindArch.
+  virtual Reference::KindArch kindArch() = 0;
+
+  /// Used by StubPass to update References to shared library functions
+  /// to be references to a stub.
+  virtual bool isCallSite(const Reference &) = 0;
+
+  /// Used by GOTPass to locate GOT References
+  virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) {
+    return false;
+  }
+
+  /// Used by TLVPass to locate TLV References.
+  virtual bool isTLVAccess(const Reference &) const { return false; }
+
+  /// Used by the TLVPass to update TLV References.
+  virtual void updateReferenceToTLV(const Reference *) {}
+
+  /// Used by ShimPass to insert shims in branches that switch mode.
+  virtual bool isNonCallBranch(const Reference &) = 0;
+
+  /// Used by GOTPass to update GOT References
+  virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
+
+  /// Does this architecture make use of __unwind_info sections for exception
+  /// handling? If so, it will need a separate pass to create them.
+  virtual bool needsCompactUnwind() = 0;
+
+  /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+  /// value, used in the __unwind_info section.
+  virtual Reference::KindValue imageOffsetKind() = 0;
+
+  /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+  /// indirect value. Used for personality functions in the __unwind_info
+  /// section.
+  virtual Reference::KindValue imageOffsetKindIndirect() = 0;
+
+  /// Architecture specific compact unwind type that signals __eh_frame should
+  /// actually be used.
+  virtual uint32_t dwarfCompactUnwindType() = 0;
+
+  /// Reference from an __eh_frame CIE atom to its personality function it's
+  /// describing. Usually pointer-sized and PC-relative, but differs in whether
+  /// it needs to be in relocatable objects.
+  virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0;
+
+  /// Reference from an __eh_frame FDE to the CIE it's based on.
+  virtual Reference::KindValue unwindRefToCIEKind() = 0;
+
+  /// Reference from an __eh_frame FDE atom to the function it's
+  /// describing. Usually pointer-sized and PC-relative, but differs in whether
+  /// it needs to be in relocatable objects.
+  virtual Reference::KindValue unwindRefToFunctionKind() = 0;
+
+  /// Reference from an __unwind_info entry of dwarfCompactUnwindType to the
+  /// required __eh_frame entry. On current architectures, the low 24 bits
+  /// represent the offset of the function's FDE entry from the start of
+  /// __eh_frame.
+  virtual Reference::KindValue unwindRefToEhFrameKind() = 0;
+
+  /// Returns a pointer sized reference kind.  On 64-bit targets this will
+  /// likely be something like pointer64, and pointer32 on 32-bit targets.
+  virtual Reference::KindValue pointerKind() = 0;
+
+  virtual const Atom *fdeTargetFunction(const DefinedAtom *fde);
+
+  /// Used by normalizedFromAtoms() to know where to generated rebasing and
+  /// binding info in final executables.
+  virtual bool isPointer(const Reference &) = 0;
+
+  /// Used by normalizedFromAtoms() to know where to generated lazy binding
+  /// info in final executables.
+  virtual bool isLazyPointer(const Reference &);
+
+  /// Returns true if the specified relocation is paired to the next relocation.
+  virtual bool isPairedReloc(const normalized::Relocation &) = 0;
+
+  /// Prototype for a helper function.  Given a sectionIndex and address,
+  /// finds the atom and offset with that atom of that address.
+  typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr,
+                        const lld::Atom **, Reference::Addend *)>
+                        FindAtomBySectionAndAddress;
+
+  /// Prototype for a helper function.  Given a symbolIndex, finds the atom
+  /// representing that symbol.
+  typedef std::function<llvm::Error (uint32_t symbolIndex,
+                        const lld::Atom **)> FindAtomBySymbolIndex;
+
+  /// Analyzes a relocation from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual llvm::Error
+          getReferenceInfo(const normalized::Relocation &reloc,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBigEndian,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) = 0;
+
+  /// Analyzes a pair of relocations from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBig, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) = 0;
+
+  /// Prototype for a helper function.  Given an atom, finds the symbol table
+  /// index for it in the output file.
+  typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom;
+
+  /// Prototype for a helper function.  Given an atom, finds the index
+  /// of the section that will contain the atom.
+  typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom;
+
+  /// Prototype for a helper function.  Given an atom, finds the address
+  /// assigned to it in the output file.
+  typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom;
+
+  /// Some architectures require local symbols on anonymous atoms.
+  virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
+    return false;
+  }
+
+  /// Copy raw content then apply all fixup References on an Atom.
+  virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                                   FindAddressForAtom findAddress,
+                                   FindAddressForAtom findSectionAddress,
+                                   uint64_t imageBaseAddress,
+                          llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0;
+
+  /// Used in -r mode to convert a Reference to a mach-o relocation.
+  virtual void appendSectionRelocations(const DefinedAtom &atom,
+                                        uint64_t atomSectionOffset,
+                                        const Reference &ref,
+                                        FindSymbolIndexForAtom,
+                                        FindSectionIndexForAtom,
+                                        FindAddressForAtom,
+                                        normalized::Relocations&) = 0;
+
+  /// Add arch-specific References.
+  virtual void addAdditionalReferences(MachODefinedAtom &atom) { }
+
+  // Add Reference for data-in-code marker.
+  virtual void addDataInCodeReference(MachODefinedAtom &atom, uint32_t atomOff,
+                                      uint16_t length, uint16_t kind) { }
+
+  /// Returns true if the specificed Reference value marks the start or end
+  /// of a data-in-code range in an atom.
+  virtual bool isDataInCodeTransition(Reference::KindValue refKind) {
+    return false;
+  }
+
+  /// Returns the Reference value for a Reference that marks that start of
+  /// a data-in-code range.
+  virtual Reference::KindValue dataInCodeTransitionStart(
+                                                const MachODefinedAtom &atom) {
+    return 0;
+  }
+
+  /// Returns the Reference value for a Reference that marks that end of
+  /// a data-in-code range.
+  virtual Reference::KindValue dataInCodeTransitionEnd(
+                                                const MachODefinedAtom &atom) {
+    return 0;
+  }
+
+  /// Only relevant for 32-bit arm archs.
+  virtual bool isThumbFunction(const DefinedAtom &atom) { return false; }
+
+  /// Only relevant for 32-bit arm archs.
+  virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+                                        const DefinedAtom &) {
+    llvm_unreachable("shims only support on arm");
+  }
+
+  /// Does a given unwind-cfi atom represent a CIE (as opposed to an FDE).
+  static bool isDwarfCIE(bool isBig, const DefinedAtom *atom);
+
+  struct ReferenceInfo {
+    Reference::KindArch arch;
+    uint16_t            kind;
+    uint32_t            offset;
+    int32_t             addend;
+  };
+
+  struct OptionalRefInfo {
+    bool                used;
+    uint16_t            kind;
+    uint32_t            offset;
+    int32_t             addend;
+  };
+
+  /// Table of architecture specific information for creating stubs.
+  struct StubInfo {
+    const char*     binderSymbolName;
+    ReferenceInfo   lazyPointerReferenceToHelper;
+    ReferenceInfo   lazyPointerReferenceToFinal;
+    ReferenceInfo   nonLazyPointerReferenceToBinder;
+    uint8_t         codeAlignment;
+
+    uint32_t        stubSize;
+    uint8_t         stubBytes[16];
+    ReferenceInfo   stubReferenceToLP;
+    OptionalRefInfo optStubReferenceToLP;
+
+    uint32_t        stubHelperSize;
+    uint8_t         stubHelperBytes[16];
+    ReferenceInfo   stubHelperReferenceToImm;
+    ReferenceInfo   stubHelperReferenceToHelperCommon;
+
+    DefinedAtom::ContentType stubHelperImageCacheContentType;
+
+    uint32_t        stubHelperCommonSize;
+    uint8_t         stubHelperCommonAlignment;
+    uint8_t         stubHelperCommonBytes[36];
+    ReferenceInfo   stubHelperCommonReferenceToCache;
+    OptionalRefInfo optStubHelperCommonReferenceToCache;
+    ReferenceInfo   stubHelperCommonReferenceToBinder;
+    OptionalRefInfo optStubHelperCommonReferenceToBinder;
+  };
+
+  virtual const StubInfo &stubInfo() = 0;
+
+protected:
+  ArchHandler();
+
+  static std::unique_ptr<mach_o::ArchHandler> create_x86_64();
+  static std::unique_ptr<mach_o::ArchHandler> create_x86();
+  static std::unique_ptr<mach_o::ArchHandler> create_arm();
+  static std::unique_ptr<mach_o::ArchHandler> create_arm64();
+
+  // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+  typedef uint16_t RelocPattern;
+  enum {
+    rScattered = 0x8000,
+    rPcRel     = 0x4000,
+    rExtern    = 0x2000,
+    rLength1   = 0x0000,
+    rLength2   = 0x0100,
+    rLength4   = 0x0200,
+    rLength8   = 0x0300,
+    rLenArmLo  = rLength1,
+    rLenArmHi  = rLength2,
+    rLenThmbLo = rLength4,
+    rLenThmbHi = rLength8
+  };
+  /// Extract RelocPattern from normalized mach-o relocation.
+  static RelocPattern relocPattern(const normalized::Relocation &reloc);
+  /// Create normalized Relocation initialized from pattern.
+  static normalized::Relocation relocFromPattern(RelocPattern pattern);
+  /// One liner to add a relocation.
+  static void appendReloc(normalized::Relocations &relocs, uint32_t offset,
+                          uint32_t symbol, uint32_t value,
+                          RelocPattern pattern);
+
+
+  static int16_t  readS16(const uint8_t *addr, bool isBig);
+  static int32_t  readS32(const uint8_t *addr, bool isBig);
+  static uint32_t readU32(const uint8_t *addr, bool isBig);
+  static int64_t  readS64(const uint8_t *addr, bool isBig);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
new file mode 100644 (file)
index 0000000..3286fe0
--- /dev/null
@@ -0,0 +1,1519 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::little32_t;
+
+
+class ArchHandler_arm : public ArchHandler {
+public:
+  ArchHandler_arm() = default;
+  ~ArchHandler_arm() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
+
+  const ArchHandler::StubInfo &stubInfo() override;
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+  bool isNonCallBranch(const Reference &) override;
+
+  bool needsCompactUnwind() override {
+    return false;
+  }
+  Reference::KindValue imageOffsetKind() override {
+    return invalid;
+  }
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return invalid;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    // FIXME
+    return -1;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                           llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom,
+                                FindSectionIndexForAtom,
+                                FindAddressForAtom,
+                                normalized::Relocations &) override;
+
+  void addAdditionalReferences(MachODefinedAtom &atom) override;
+
+  bool isDataInCodeTransition(Reference::KindValue refKind) override {
+    switch (refKind) {
+    case modeThumbCode:
+    case modeArmCode:
+    case modeData:
+      return true;
+    default:
+      return false;
+      break;
+    }
+  }
+
+  Reference::KindValue dataInCodeTransitionStart(
+                                        const MachODefinedAtom &atom) override {
+    return modeData;
+  }
+
+  Reference::KindValue dataInCodeTransitionEnd(
+                                        const MachODefinedAtom &atom) override {
+    return atom.isThumb() ? modeThumbCode : modeArmCode;
+  }
+
+  bool isThumbFunction(const DefinedAtom &atom) override;
+  const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+                                const DefinedAtom &) override;
+
+private:
+  friend class Thumb2ToArmShimAtom;
+  friend class ArmToThumbShimAtom;
+
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfoArmPIC;
+
+  enum ArmKind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    modeThumbCode,         /// Content starting at this offset is thumb.
+    modeArmCode,           /// Content starting at this offset is arm.
+    modeData,              /// Content starting at this offset is data.
+
+    // Kinds found in mach-o .o files:
+    thumb_bl22,            /// ex: bl _foo
+    thumb_b22,             /// ex: b _foo
+    thumb_movw,            /// ex: movw        r1, :lower16:_foo
+    thumb_movt,            /// ex: movt        r1, :lower16:_foo
+    thumb_movw_funcRel,    /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    thumb_movt_funcRel,    /// ex: movt r1, :upper16:(_foo-(L1+4))
+    arm_bl24,              /// ex: bl _foo
+    arm_b24,               /// ex: b _foo
+    arm_movw,              /// ex: movw        r1, :lower16:_foo
+    arm_movt,              /// ex: movt        r1, :lower16:_foo
+    arm_movw_funcRel,      /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    arm_movt_funcRel,      /// ex: movt r1, :upper16:(_foo-(L1+4))
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  // Utility functions for inspecting/updating instructions.
+  static bool isThumbMovw(uint32_t instruction);
+  static bool isThumbMovt(uint32_t instruction);
+  static bool isArmMovw(uint32_t instruction);
+  static bool isArmMovt(uint32_t instruction);
+  static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
+  static int32_t getDisplacementFromArmBranch(uint32_t instruction);
+  static uint16_t getWordFromThumbMov(uint32_t instruction);
+  static uint16_t getWordFromArmMov(uint32_t instruction);
+  static uint32_t clearThumbBit(uint32_t value, const Atom *target);
+  static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
+                                             bool targetIsThumb);
+  static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
+                                               int32_t disp, bool targetThumb);
+  static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
+  static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
+
+  StringRef stubName(const DefinedAtom &);
+  bool useExternalRelocationTo(const Atom &target);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, bool &thumbMode,
+                       bool targetIsThumb);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress, bool &thumbMode,
+                             bool targetIsThumb);
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_arm
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(modeThumbCode),
+  LLD_KIND_STRING_ENTRY(modeArmCode),
+  LLD_KIND_STRING_ENTRY(modeData),
+  LLD_KIND_STRING_ENTRY(thumb_bl22),
+  LLD_KIND_STRING_ENTRY(thumb_b22),
+  LLD_KIND_STRING_ENTRY(thumb_movw),
+  LLD_KIND_STRING_ENTRY(thumb_movt),
+  LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_bl24),
+  LLD_KIND_STRING_ENTRY(arm_b24),
+  LLD_KIND_STRING_ENTRY(arm_movw),
+  LLD_KIND_STRING_ENTRY(arm_movt),
+  LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
+  "dyld_stub_binder",
+
+  // References in lazy pointer
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+  { Reference::KindArch::ARM, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+
+  // arm code alignment 2^2
+  2,
+
+  // Stub size and code
+  16,
+  { 0x04, 0xC0, 0x9F, 0xE5,       //   ldr ip, pc + 12
+    0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       //   ldr pc, [ip]
+    0x00, 0x00, 0x00, 0x00 },     //   .long L_foo$lazy_ptr - (L1$scv + 8)
+  { Reference::KindArch::ARM, delta32, 12, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  12,
+  { 0x00, 0xC0, 0x9F, 0xE5,       // ldr   ip, [pc, #0]
+    0x00, 0x00, 0x00, 0xEA,       // b      _helperhelper
+    0x00, 0x00, 0x00, 0x00 },     // .long  lazy-info-offset
+  { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
+  { Reference::KindArch::ARM, arm_b24, 4, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeGOT,
+
+  // Stub Helper-Common size and code
+  36,
+  // Stub helper alignment
+  2,
+       { // push lazy-info-offset
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // push address of dyld_mageLoaderCache
+    0x10, 0xC0, 0x9F, 0xE5,       // ldr       ip, L1
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // jump through dyld_stub_binder
+    0x08, 0xC0, 0x9F, 0xE5,       // ldr       ip, L2
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       // ldr       pc, [ip]
+    0x00, 0x00, 0x00, 0x00,       // L1: .long fFastStubGOTAtom - (helper+16)
+    0x00, 0x00, 0x00, 0x00 },     // L2: .long dyld_stub_binder - (helper+28)
+  { Reference::KindArch::ARM, delta32, 28, 0xC },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::ARM, delta32, 32, 0x04 },
+  { false, 0, 0, 0 }
+};
+
+const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
+  // If multiple kinds of stubs are supported, select which StubInfo here.
+  return _sStubInfoArmPIC;
+}
+
+bool ArchHandler_arm::isCallSite(const Reference &ref) {
+  switch (ref.kindValue()) {
+  case thumb_b22:
+  case thumb_bl22:
+  case arm_b24:
+  case arm_bl24:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool ArchHandler_arm::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
+  switch (ref.kindValue()) {
+  case thumb_b22:
+  case arm_b24:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
+  switch (reloc.type) {
+  case ARM_RELOC_SECTDIFF:
+  case ARM_RELOC_LOCAL_SECTDIFF:
+  case ARM_RELOC_HALF_SECTDIFF:
+  case ARM_RELOC_HALF:
+    return true;
+  default:
+    return false;
+  }
+}
+
+/// Trace references from stub atom to lazy pointer to target and get its name.
+StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
+  assert(stubAtom.contentType() == DefinedAtom::typeStub);
+  for (const Reference *ref : stubAtom) {
+    if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
+      if (lp->contentType() != DefinedAtom::typeLazyPointer)
+        continue;
+      for (const Reference *ref2 : *lp) {
+        if (ref2->kindValue() != lazyPointer)
+          continue;
+        return ref2->target()->name();
+      }
+    }
+  }
+  return "stub";
+}
+
+/// Extract displacement from an ARM b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
+  // Sign-extend imm24
+  int32_t displacement = (instruction & 0x00FFFFFF) << 2;
+  if ((displacement & 0x02000000) != 0)
+    displacement |= 0xFC000000;
+  // If this is BLX and H bit set, add 2.
+  if ((instruction & 0xFF000000) == 0xFB000000)
+    displacement += 2;
+  return displacement;
+}
+
+/// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
+                                                     int32_t displacement,
+                                                     bool targetIsThumb) {
+  assert((displacement <= 33554428) && (displacement > (-33554432))
+                                              && "arm branch out of range");
+  bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
+  uint32_t newInstruction = (instruction & 0xFF000000);
+  uint32_t h = 0;
+  if (targetIsThumb) {
+    // Force use of BLX.
+    newInstruction = 0xFA000000;
+    if (!is_blx) {
+      assert(((instruction & 0xF0000000) == 0xE0000000)
+                                                   && "no conditional arm blx");
+      assert(((instruction & 0xFF000000) == 0xEB000000)
+                                             && "no arm pc-rel BX instruction");
+    }
+    if (displacement & 2)
+      h = 1;
+  }
+  else {
+    // Force use of B/BL.
+    if (is_blx)
+      newInstruction = 0xEB000000;
+  }
+  newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
+  return newInstruction;
+}
+
+/// Extract displacement from a thumb b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
+                                                        uint32_t instrAddr) {
+  bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+  uint32_t s = (instruction >> 10) & 0x1;
+  uint32_t j1 = (instruction >> 29) & 0x1;
+  uint32_t j2 = (instruction >> 27) & 0x1;
+  uint32_t imm10 = instruction & 0x3FF;
+  uint32_t imm11 = (instruction >> 16) & 0x7FF;
+  uint32_t i1 = (j1 == s);
+  uint32_t i2 = (j2 == s);
+  uint32_t dis =
+      (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+  int32_t sdis = dis;
+  int32_t result = s ? (sdis | 0xFE000000) : sdis;
+  if (is_blx && (instrAddr & 0x2)) {
+    // The thumb blx instruction always has low bit of imm11 as zero.  The way
+    // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
+    // the blx instruction always 4-byte aligns the pc before adding the
+    // displacement from the blx.  We must emulate that when decoding this.
+    result -= 2;
+  }
+  return result;
+}
+
+/// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
+                                                       uint32_t instrAddr,
+                                                       int32_t displacement,
+                                                       bool targetIsThumb) {
+  assert((displacement <= 16777214) && (displacement > (-16777216))
+                                              && "thumb branch out of range");
+       bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
+       bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+       bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+  uint32_t newInstruction = (instruction & 0xD000F800);
+  if (is_bl || is_blx) {
+    if (targetIsThumb) {
+      newInstruction = 0xD000F000; // Use bl
+    } else {
+      newInstruction = 0xC000F000; // Use blx
+      // See note in getDisplacementFromThumbBranch() about blx.
+      if (instrAddr & 0x2)
+        displacement += 2;
+    }
+  } else if (is_b) {
+    assert(targetIsThumb && "no pc-rel thumb branch instruction that "
+                             "switches to arm mode");
+  }
+  else {
+    llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
+  }
+  uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+  uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+  uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+  uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+  uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+  uint32_t j1 = (i1 == s);
+  uint32_t j2 = (i2 == s);
+  uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+  uint32_t firstDisp = (s << 10) | imm10;
+  newInstruction |= (nextDisp << 16) | firstDisp;
+  return newInstruction;
+}
+
+bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
+  return (instruction & 0x8000FBF0) == 0x0000F240;
+}
+
+bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
+  return (instruction & 0x8000FBF0) == 0x0000F2C0;
+}
+
+bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
+  return (instruction & 0x0FF00000) == 0x03000000;
+}
+
+bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
+  return (instruction & 0x0FF00000) == 0x03400000;
+}
+
+uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+  assert(isThumbMovw(instruction) || isThumbMovt(instruction));
+  uint32_t i = ((instruction & 0x00000400) >> 10);
+  uint32_t imm4 = (instruction & 0x0000000F);
+  uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+  uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+  return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+}
+
+uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+  assert(isArmMovw(instruction) || isArmMovt(instruction));
+  uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+  uint32_t imm12 = (instruction & 0x00000FFF);
+  return (imm4 << 12) | imm12;
+}
+
+uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
+  assert(isThumbMovw(instr) || isThumbMovt(instr));
+  uint32_t imm4 = (word & 0xF000) >> 12;
+  uint32_t i =    (word & 0x0800) >> 11;
+  uint32_t imm3 = (word & 0x0700) >> 8;
+  uint32_t imm8 =  word & 0x00FF;
+       return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+}
+
+uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
+  assert(isArmMovw(instr) || isArmMovt(instr));
+  uint32_t imm4 = (word & 0xF000) >> 12;
+  uint32_t imm12 = word & 0x0FFF;
+  return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
+}
+
+uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
+  // The assembler often adds one to the address of a thumb function.
+  // We need to undo that so it does not look like an addend.
+  if (value & 1) {
+    if (isa<DefinedAtom>(target)) {
+      const MachODefinedAtom *machoTarget =
+          reinterpret_cast<const MachODefinedAtom *>(target);
+      if (machoTarget->isThumb())
+        value &= -2; // mask off thumb-bit
+    }
+  }
+  return value;
+}
+
+llvm::Error ArchHandler_arm::getReferenceInfo(
+    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+    uint64_t fixupAddress, bool isBig,
+    FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  uint32_t instruction = *(const ulittle32_t *)fixupContent;
+  int32_t displacement;
+  switch (relocPattern(reloc)) {
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    *addend = fixupAddress + 4 + displacement;
+    return llvm::Error();
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    targetAddress = fixupAddress + 4 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    targetAddress = fixupAddress + 4 + displacement;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return llvm::Error();
+  case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromArmBranch(instruction);
+    *addend = fixupAddress + 8 + displacement;
+    return llvm::Error();
+  case ARM_RELOC_BR24 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return llvm::Error();
+  case ARM_RELOC_VANILLA | rExtern | rLength4:
+    // ex: .long _foo (and _foo is undefined)
+    *kind = pointer32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = instruction;
+    return llvm::Error();
+  case ARM_RELOC_VANILLA | rLength4:
+    // ex: .long _foo (and _foo is defined)
+    *kind = pointer32;
+    if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+      return ec;
+    *addend = clearThumbBit((uint32_t) * addend, *target);
+    return llvm::Error();
+  case ARM_RELOC_VANILLA | rScattered | rLength4:
+    // ex: .long _foo+a (and _foo is defined)
+    *kind = pointer32;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend += (clearThumbBit(instruction, *target) - reloc.value);
+    return llvm::Error();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm relocation type");
+  }
+  return llvm::Error();
+}
+
+llvm::Error
+ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                     const normalized::Relocation &reloc2,
+                                     const DefinedAtom *inAtom,
+                                     uint32_t offsetInAtom,
+                                     uint64_t fixupAddress, bool isBig,
+                                     bool scatterable,
+                                     FindAtomBySectionAndAddress atomFromAddr,
+                                     FindAtomBySymbolIndex atomFromSymbolIndex,
+                                     Reference::KindValue *kind,
+                                     const lld::Atom **target,
+                                     Reference::Addend *addend) {
+  bool pointerDiff = false;
+  bool funcRel;
+  bool top;
+  bool thumbReloc;
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenThmbLo):
+    // ex: movw        r1, :lower16:(_x-L1) [thumb mode]
+    *kind = thumb_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenThmbHi):
+    // ex: movt        r1, :upper16:(_x-L1) [thumb mode]
+    *kind = thumb_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenArmLo):
+    // ex: movw        r1, :lower16:(_x-L1) [arm mode]
+    *kind = arm_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenArmHi):
+    // ex: movt        r1, :upper16:(_x-L1) [arm mode]
+    *kind = arm_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR     | rLenThmbLo):
+    // ex: movw        r1, :lower16:_x [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR     | rLenThmbHi):
+    // ex: movt        r1, :upper16:_x [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR     | rLenArmLo):
+    // ex: movw        r1, :lower16:_x [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR     | rLenArmHi):
+    // ex: movt        r1, :upper16:_x [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR               | rLenThmbLo):
+    // ex: movw        r1, :lower16:_x+a [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR               | rLenThmbHi):
+    // ex: movt        r1, :upper16:_x+a [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR               | rLenArmLo):
+    // ex: movw        r1, :lower16:_x+a [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR               | rLenArmHi):
+    // ex: movt        r1, :upper16:_x+a [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR             | rLenThmbLo):
+    // ex: movw        r1, :lower16:_undef [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR             | rLenThmbHi):
+    // ex: movt        r1, :upper16:_undef [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR             | rLenArmLo):
+    // ex: movw        r1, :lower16:_undef [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR             | rLenArmHi):
+    // ex: movt        r1, :upper16:_undef [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+  case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+    // ex: .long _foo - .
+    pointerDiff = true;
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported arm relocation pair");
+  }
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint32_t instruction = *(const ulittle32_t *)fixupContent;
+  uint32_t value;
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint16_t instruction16;
+  uint16_t other16;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  if (pointerDiff) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (scatterable && (fromTarget != inAtom))
+      return llvm::make_error<GenericError>(
+          "SECTDIFF relocation where subtrahend label is not in atom");
+    *kind = delta32;
+    value = clearThumbBit(instruction, *target);
+    *addend = (int32_t)(value - (toAddress - fixupAddress));
+  } else if (funcRel) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
+                                     " where subtrahend label is not in atom");
+    other16 = (reloc2.offset & 0xFFFF);
+    if (thumbReloc) {
+      if (top) {
+        if (!isThumbMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isThumbMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromThumbMov(instruction);
+    }
+    else {
+      if (top) {
+        if (!isArmMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isArmMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromArmMov(instruction);
+    }
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    value = clearThumbBit(value, *target);
+    int64_t ta = (int64_t) value - (toAddress - fromAddress);
+    *addend = ta - offsetInFrom;
+    return llvm::Error();
+  } else {
+    uint32_t sectIndex;
+    if (thumbReloc) {
+      if (top) {
+        if (!isThumbMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isThumbMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromThumbMov(instruction);
+    }
+    else {
+      if (top) {
+        if (!isArmMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isArmMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromArmMov(instruction);
+    }
+    other16 = (reloc2.offset & 0xFFFF);
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    if (reloc1.isExtern) {
+      if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
+        return ec;
+      *addend = value;
+    } else {
+      if (reloc1.scattered) {
+        toAddress = reloc1.value;
+        sectIndex = 0;
+      } else {
+        toAddress = value;
+        sectIndex = reloc1.symbol;
+      }
+      if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
+        return ec;
+      *addend = value - toAddress;
+    }
+  }
+
+  return llvm::Error();
+}
+
+void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                      uint64_t fixupAddress,
+                                      uint64_t targetAddress,
+                                      uint64_t inAtomAddress,
+                                      bool &thumbMode, bool targetIsThumb) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  int32_t displacement;
+  uint16_t value16;
+  uint32_t value32;
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+    thumbMode = true;
+    break;
+  case modeArmCode:
+    thumbMode = false;
+    break;
+  case modeData:
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    assert(thumbMode);
+    displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+                                           displacement, targetIsThumb);
+    *loc32 = value32;
+    break;
+  case thumb_movw:
+    assert(thumbMode);
+    value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt:
+    assert(thumbMode);
+    value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movw_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case arm_b24:
+  case arm_bl24:
+   assert(!thumbMode);
+    displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
+    *loc32 = value32;
+    break;
+  case arm_movw:
+    assert(!thumbMode);
+    value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt:
+    assert(!thumbMode);
+    value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movw_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case pointer32:
+    if (targetIsThumb)
+      *loc32 = targetAddress + ref.addend() + 1;
+    else
+      *loc32 = targetAddress + ref.addend();
+    break;
+  case delta32:
+    if (targetIsThumb)
+      *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
+    else
+      *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case lazyPointer:
+    // do nothing
+    break;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
+                                          bool relocatable,
+                                          FindAddressForAtom findAddress,
+                                          FindAddressForAtom findSectionAddress,
+                                          uint64_t imageBaseAddress,
+                            llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  bool thumbMode = false;
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    bool targetIsThumb = false;
+    if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
+      targetAddress = findAddress(*target);
+      targetIsThumb = isThumbFunction(*defTarg);
+    }
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+                            targetAddress, atomAddress, thumbMode,
+                            targetIsThumb);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+                      targetAddress, atomAddress, thumbMode, targetIsThumb);
+    }
+  }
+}
+
+bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
+  // Undefined symbols are referenced via external relocations.
+  if (isa<UndefinedAtom>(&target))
+    return true;
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+     switch (defAtom->merge()) {
+     case DefinedAtom::mergeAsTentative:
+       // Tentative definitions are referenced via external relocations.
+       return true;
+     case DefinedAtom::mergeAsWeak:
+     case DefinedAtom::mergeAsWeakAndAddressUsed:
+       // Global weak-defs are referenced via external relocations.
+       return (defAtom->scope() == DefinedAtom::scopeGlobal);
+     default:
+       break;
+    }
+  }
+  // Everything else is reference via an internal relocation.
+  return false;
+}
+
+void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
+                                            uint64_t fixupAddress,
+                                            uint64_t targetAddress,
+                                            uint64_t inAtomAddress,
+                                            bool &thumbMode,
+                                            bool targetIsThumb) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  int32_t displacement;
+  uint16_t value16;
+  uint32_t value32;
+  bool targetIsUndef = isa<UndefinedAtom>(ref.target());
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+    thumbMode = true;
+    break;
+  case modeArmCode:
+    thumbMode = false;
+    break;
+  case modeData:
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    assert(thumbMode);
+    if (useExternalReloc)
+      displacement = (ref.addend() - (fixupAddress + 4));
+    else
+      displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+                                           displacement,
+                                           targetIsUndef || targetIsThumb);
+    *loc32 = value32;
+    break;
+  case thumb_movw:
+    assert(thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() & 0xFFFF;
+    else
+      value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt:
+    assert(thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() >> 16;
+    else
+      value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movw_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case arm_b24:
+  case arm_bl24:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      displacement = (ref.addend() - (fixupAddress + 8));
+    else
+      displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    value32 = setDisplacementInArmBranch(*loc32, displacement,
+                                         targetIsThumb);
+    *loc32 = value32;
+    break;
+  case arm_movw:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() & 0xFFFF;
+    else
+      value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() >> 16;
+    else
+      value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movw_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case pointer32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  uint32_t targetAtomAddress;
+  uint32_t fromAtomAddress;
+  uint16_t other16;
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+  case modeArmCode:
+  case modeData:
+    // Do nothing.
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_THUMB_RELOC_BR22 | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_THUMB_RELOC_BR22 |              rPcRel | rLength4);
+    }
+    break;
+  case thumb_movw:
+    if (useExternalReloc) {
+      other16 = ref.addend() >> 16;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenThmbLo);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenThmbLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenThmbLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+      }
+    }
+    break;
+  case thumb_movt:
+    if (useExternalReloc) {
+      other16 = ref.addend() & 0xFFFF;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenThmbHi);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbHi);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                    ARM_RELOC_HALF | rScattered | rLenThmbHi);
+        appendReloc(relocs, other16, 0, 0,
+                    ARM_RELOC_PAIR              | rLenThmbHi);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                    ARM_RELOC_HALF              | rLenThmbHi);
+        appendReloc(relocs, other16, 0, 0,
+                    ARM_RELOC_PAIR              | rLenThmbHi);
+      }
+    }
+    break;
+  case thumb_movw_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenThmbLo);
+    break;
+  case thumb_movt_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenThmbHi);
+    break;
+  case arm_b24:
+  case arm_bl24:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_BR24 | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_BR24 |              rPcRel | rLength4);
+    }
+    break;
+  case arm_movw:
+    if (useExternalReloc) {
+      other16 = ref.addend() >> 16;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenArmLo);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenArmLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenArmLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+      }
+    }
+    break;
+  case arm_movt:
+    if (useExternalReloc) {
+      other16 = ref.addend() & 0xFFFF;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenArmHi);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenArmHi);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenArmHi);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+      }
+    }
+    break;
+  case arm_movw_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenArmLo);
+    break;
+  case arm_movt_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenArmHi);
+    break;
+  case pointer32:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
+                ARM_RELOC_VANILLA |    rExtern     |  rLength4);
+    }
+    else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                ARM_RELOC_VANILLA |    rScattered  |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                ARM_RELOC_VANILLA |                   rLength4);
+    }
+    break;
+  case delta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              ARM_RELOC_SECTDIFF  |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              ARM_RELOC_PAIR      |  rScattered    | rLength4);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
+  if (atom.isThumb()) {
+    atom.addReference(Reference::KindNamespace::mach_o,
+                      Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
+  }
+}
+
+bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
+  for (const Reference *ref : atom) {
+    if (ref->offsetInAtom() != 0)
+      return false;
+    if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+      continue;
+    assert(ref->kindArch() == Reference::KindArch::ARM);
+    if (ref->kindValue() == modeThumbCode)
+      return true;
+  }
+  return false;
+}
+
+class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
+public:
+  Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
+                      const DefinedAtom &target)
+      : SimpleDefinedAtom(file) {
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::modeThumbCode, 0, this, 0);
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::delta32, 8, &target, 0);
+    std::string name = std::string(targetName) + "$shim";
+    StringRef tmp(name);
+    _name = tmp.copy(file.allocator());
+  }
+
+  ~Thumb2ToArmShimAtom() override = default;
+
+  StringRef name() const override {
+    return _name;
+  }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeCode;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override {
+    return 12;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t bytes[] =
+    { 0xDF, 0xF8, 0x04, 0xC0,       //  ldr ip, pc + 4
+      0xFF, 0x44,                   //  add ip, pc, ip
+      0x60, 0x47,                   //  ldr pc, [ip]
+      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
+    assert(sizeof(bytes) == size());
+    return llvm::makeArrayRef(bytes, sizeof(bytes));
+  }
+private:
+  StringRef _name;
+};
+
+class ArmToThumbShimAtom : public SimpleDefinedAtom {
+public:
+  ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
+                     const DefinedAtom &target)
+      : SimpleDefinedAtom(file) {
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::delta32, 12, &target, 0);
+    std::string name = std::string(targetName) + "$shim";
+    StringRef tmp(name);
+    _name = tmp.copy(file.allocator());
+  }
+
+  ~ArmToThumbShimAtom() override = default;
+
+  StringRef name() const override {
+    return _name;
+  }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeCode;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override {
+    return 16;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t bytes[] =
+    { 0x04, 0xC0, 0x9F, 0xE5,       //  ldr ip, pc + 4
+      0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
+      0x1C, 0xFF, 0x2F, 0xE1,       //  ldr pc, [ip]
+      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
+    assert(sizeof(bytes) == size());
+    return llvm::makeArrayRef(bytes, sizeof(bytes));
+  }
+private:
+  StringRef _name;
+};
+
+const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
+                                               bool thumbToArm,
+                                               const DefinedAtom &target) {
+  bool isStub = (target.contentType() == DefinedAtom::typeStub);
+  StringRef targetName = isStub ? stubName(target) : target.name();
+  if (thumbToArm)
+    return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
+  else
+    return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
new file mode 100644 (file)
index 0000000..a61f6aa
--- /dev/null
@@ -0,0 +1,898 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_arm64 : public ArchHandler {
+public:
+  ArchHandler_arm64() = default;
+  ~ArchHandler_arm64() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override {
+    return Reference::KindArch::AArch64;
+  }
+
+  /// Used by GOTPass to locate GOT References
+  bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+    if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+      return false;
+    assert(ref.kindArch() == Reference::KindArch::AArch64);
+    switch (ref.kindValue()) {
+    case gotPage21:
+    case gotOffset12:
+      canBypassGOT = true;
+      return true;
+    case delta32ToGOT:
+      canBypassGOT = false;
+      return true;
+    case unwindCIEToPersonalityFunction:
+      canBypassGOT = false;
+      return true;
+    case imageOffsetGot:
+      canBypassGOT = false;
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /// Used by GOTPass to update GOT References.
+  void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+    // If GOT slot was instanciated, transform:
+    //   gotPage21/gotOffset12 -> page21/offset12scale8
+    // If GOT slot optimized away, transform:
+    //   gotPage21/gotOffset12 -> page21/addOffset12
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::AArch64);
+    switch (ref->kindValue()) {
+    case gotPage21:
+      const_cast<Reference *>(ref)->setKindValue(page21);
+      break;
+    case gotOffset12:
+      const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
+                                                 offset12scale8 : addOffset12);
+      break;
+    case delta32ToGOT:
+      const_cast<Reference *>(ref)->setKindValue(delta32);
+      break;
+    case imageOffsetGot:
+      const_cast<Reference *>(ref)->setKindValue(imageOffset);
+      break;
+    default:
+      llvm_unreachable("Not a GOT reference");
+    }
+  }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+
+  bool isCallSite(const Reference &) override;
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  bool needsCompactUnwind() override {
+    return true;
+  }
+  Reference::KindValue imageOffsetKind() override {
+    return imageOffset;
+  }
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return imageOffsetGot;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return unwindCIEToPersonalityFunction;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return unwindFDEToFunction;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return unwindInfoToEhFrame;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return pointer64;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x03000000;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool isBig,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBig, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+    return (atom->contentType() == DefinedAtom::typeCString);
+  }
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo _sStubInfo;
+
+  enum Arm64Kind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    branch26,              /// ex: bl   _foo
+    page21,                /// ex: adrp x1, _foo@PAGE
+    offset12,              /// ex: ldrb w0, [x1, _foo@PAGEOFF]
+    offset12scale2,        /// ex: ldrs w0, [x1, _foo@PAGEOFF]
+    offset12scale4,        /// ex: ldr  w0, [x1, _foo@PAGEOFF]
+    offset12scale8,        /// ex: ldr  x0, [x1, _foo@PAGEOFF]
+    offset12scale16,       /// ex: ldr  q0, [x1, _foo@PAGEOFF]
+    gotPage21,             /// ex: adrp x1, _foo@GOTPAGE
+    gotOffset12,           /// ex: ldr  w0, [x1, _foo@GOTPAGEOFF]
+    tlvPage21,             /// ex: adrp x1, _foo@TLVPAGE
+    tlvOffset12,           /// ex: ldr  w0, [x1, _foo@TLVPAGEOFF]
+
+    pointer64,             /// ex: .quad _foo
+    delta64,               /// ex: .quad _foo - .
+    delta32,               /// ex: .long _foo - .
+    negDelta32,            /// ex: .long . - _foo
+    pointer64ToGOT,        /// ex: .quad _foo@GOT
+    delta32ToGOT,          /// ex: .long _foo@GOT - .
+
+    // Kinds introduced by Passes:
+    addOffset12,           /// Location contains LDR to change into ADD.
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+    imageOffset,           /// Location contains offset of atom in final image
+    imageOffsetGot,        /// Location contains offset of GOT entry for atom in
+                           /// final image (typically personality function).
+    unwindCIEToPersonalityFunction,   /// Nearly delta32ToGOT, but cannot be
+                           /// rematerialized in relocatable object
+                           /// (yay for implicit contracts!).
+    unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
+                           /// relocatable object (yay for implicit contracts!).
+    unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
+                           /// refer to __eh_frame entry.
+  };
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, uint64_t imageBaseAddress,
+                       FindAddressForAtom findSectionAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress, uint64_t targetAddress,
+                             uint64_t inAtomAddress, bool targetUnnamed);
+
+  // Utility functions for inspecting/updating instructions.
+  static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
+  static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
+  static Arm64Kind offset12KindFromInstruction(uint32_t instr);
+  static uint32_t setImm12(uint32_t instr, uint32_t offset);
+};
+
+const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(branch26),
+  LLD_KIND_STRING_ENTRY(page21),
+  LLD_KIND_STRING_ENTRY(offset12),
+  LLD_KIND_STRING_ENTRY(offset12scale2),
+  LLD_KIND_STRING_ENTRY(offset12scale4),
+  LLD_KIND_STRING_ENTRY(offset12scale8),
+  LLD_KIND_STRING_ENTRY(offset12scale16),
+  LLD_KIND_STRING_ENTRY(gotPage21),
+  LLD_KIND_STRING_ENTRY(gotOffset12),
+  LLD_KIND_STRING_ENTRY(tlvPage21),
+  LLD_KIND_STRING_ENTRY(tlvOffset12),
+  LLD_KIND_STRING_ENTRY(pointer64),
+  LLD_KIND_STRING_ENTRY(delta64),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(pointer64ToGOT),
+  LLD_KIND_STRING_ENTRY(delta32ToGOT),
+
+  LLD_KIND_STRING_ENTRY(addOffset12),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_ENTRY(imageOffset),
+  LLD_KIND_STRING_ENTRY(imageOffsetGot),
+  LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
+  LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+  LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::AArch64, pointer64, 0, 0 },
+  { Reference::KindArch::AArch64, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::AArch64, pointer64, 0, 0 },
+
+  // arm64 code alignment 2^2
+  2,
+
+  // Stub size and code
+  12,
+  { 0x10, 0x00, 0x00, 0x90,   // ADRP  X16, lazy_pointer@page
+    0x10, 0x02, 0x40, 0xF9,   // LDR   X16, [X16, lazy_pointer@pageoff]
+    0x00, 0x02, 0x1F, 0xD6 }, // BR    X16
+  { Reference::KindArch::AArch64, page21, 0, 0 },
+  { true,                         offset12scale8, 4, 0 },
+
+  // Stub Helper size and code
+  12,
+  { 0x50, 0x00, 0x00, 0x18,   //      LDR   W16, L0
+    0x00, 0x00, 0x00, 0x14,   //      LDR   B  helperhelper
+    0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
+  { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
+  { Reference::KindArch::AArch64, branch26, 4, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeGOT,
+
+  // Stub Helper-Common size and code
+  24,
+  // Stub helper alignment
+  2,
+  { 0x11, 0x00, 0x00, 0x90,   //  ADRP  X17, dyld_ImageLoaderCache@page
+    0x31, 0x02, 0x00, 0x91,   //  ADD   X17, X17, dyld_ImageLoaderCache@pageoff
+    0xF0, 0x47, 0xBF, 0xA9,   //  STP   X16/X17, [SP, #-16]!
+    0x10, 0x00, 0x00, 0x90,   //  ADRP  X16, _fast_lazy_bind@page
+    0x10, 0x02, 0x40, 0xF9,   //  LDR   X16, [X16,_fast_lazy_bind@pageoff]
+    0x00, 0x02, 0x1F, 0xD6 }, //  BR    X16
+  { Reference::KindArch::AArch64, page21,   0, 0 },
+  { true,                         offset12, 4, 0 },
+  { Reference::KindArch::AArch64, page21,   12, 0 },
+  { true,                         offset12scale8, 16, 0 }
+};
+
+bool ArchHandler_arm64::isCallSite(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  return (ref.kindValue() == branch26);
+}
+
+bool ArchHandler_arm64::isPointer(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  Reference::KindValue kind = ref.kindValue();
+  return (kind == pointer64);
+}
+
+bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
+  return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
+                                                      int32_t displacement) {
+  assert((displacement <= 134217727) && (displacement > (-134217728)) &&
+         "arm64 branch out of range");
+  return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
+                                                  int64_t displacement) {
+  assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
+         "arm64 ADRP out of range");
+  assert(((instruction & 0x9F000000) == 0x90000000) &&
+         "reloc not on ADRP instruction");
+  uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
+  uint32_t immlo = (displacement << 17) & (0x60000000);
+  return (instruction & 0x9F00001F) | immlo | immhi;
+}
+
+ArchHandler_arm64::Arm64Kind
+ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
+  if (instruction & 0x08000000) {
+    switch ((instruction >> 30) & 0x3) {
+    case 0:
+      if ((instruction & 0x04800000) == 0x04800000)
+        return offset12scale16;
+      return offset12;
+    case 1:
+      return offset12scale2;
+    case 2:
+      return offset12scale4;
+    case 3:
+      return offset12scale8;
+    }
+  }
+  return offset12;
+}
+
+uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
+  assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
+  uint32_t imm12 = offset << 10;
+  return (instruction & 0xFFC003FF) | imm12;
+}
+
+llvm::Error ArchHandler_arm64::getReferenceInfo(
+    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+    uint64_t fixupAddress, bool isBig,
+    FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  switch (relocPattern(reloc)) {
+  case ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4:
+    // ex: bl _foo
+    *kind = branch26;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@PAGE
+    *kind = page21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@PAGEOFF]
+    *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_GOT_LOAD_PAGE21    | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@GOTPAGE
+    *kind = gotPage21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_GOT_LOAD_PAGEOFF12          | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
+    *kind = gotOffset12;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_TLVP_LOAD_PAGE21   | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@TLVPAGE
+    *kind = tlvPage21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_TLVP_LOAD_PAGEOFF12         | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
+    *kind = tlvOffset12;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_UNSIGNED                    | rExtern | rLength8:
+    // ex: .quad _foo + N
+    *kind = pointer64;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little64_t *)fixupContent;
+    return llvm::Error();
+  case ARM64_RELOC_UNSIGNED                              | rLength8:
+     // ex: .quad Lfoo + N
+     *kind = pointer64;
+     return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent,
+                            target, addend);
+  case ARM64_RELOC_POINTER_TO_GOT              | rExtern | rLength8:
+    // ex: .quad _foo@GOT
+    *kind = pointer64ToGOT;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  case ARM64_RELOC_POINTER_TO_GOT     | rPcRel | rExtern | rLength4:
+    // ex: .long _foo@GOT - .
+
+    // If we are in an .eh_frame section, then the kind of the relocation should
+    // not be delta32ToGOT.  It may instead be unwindCIEToPersonalityFunction.
+    if (inAtom->contentType() == DefinedAtom::typeCFI)
+      *kind = unwindCIEToPersonalityFunction;
+    else
+      *kind = delta32ToGOT;
+
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm64 relocation type");
+  }
+}
+
+llvm::Error ArchHandler_arm64::getPairReferenceInfo(
+    const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
+    const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
+    bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4):
+    // ex: bl _foo+8
+    *kind = branch26;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error();
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4):
+    // ex: adrp x1, _foo@PAGE
+    *kind = page21;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error();
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4): {
+    // ex: ldr w0, [x1, _foo@PAGEOFF]
+    uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
+    *kind = offset12KindFromInstruction(cont32);
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error();
+  }
+  case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength8) << 16 |
+         ARM64_RELOC_UNSIGNED                    | rExtern | rLength8):
+    // ex: .quad _foo - .
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+
+    // If we are in an .eh_frame section, then the kind of the relocation should
+    // not be delta64.  It may instead be unwindFDEToFunction.
+    if (inAtom->contentType() == DefinedAtom::typeCFI)
+      *kind = unwindFDEToFunction;
+    else
+      *kind = delta64;
+
+    // The offsets of the 2 relocations must match
+    if (reloc1.offset != reloc2.offset)
+      return llvm::make_error<GenericError>(
+                                    "paired relocs must have the same offset");
+    *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
+    return llvm::Error();
+  case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength4) << 16 |
+         ARM64_RELOC_UNSIGNED                    | rExtern | rLength4):
+    // ex: .quad _foo - .
+    *kind = delta32;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
+    return llvm::Error();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
+  }
+}
+
+void ArchHandler_arm64::generateAtomContent(
+    const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+    FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+    llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+#ifndef NDEBUG
+  if (atom.begin() != atom.end()) {
+    DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
+                    << "Applying fixups to atom:\n"
+                    << "   address="
+                    << llvm::format("    0x%09lX", &atom)
+                    << ", file=#"
+                    << atom.file().ordinal()
+                    << ", atom=#"
+                    << atom.ordinal()
+                    << ", name="
+                    << atom.name()
+                    << ", type="
+                    << atom.contentType()
+                    << "\n");
+  }
+#endif
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    bool targetUnnamed = target->name().empty();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+                            targetAddress, atomAddress, targetUnnamed);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+                      targetAddress, atomAddress, imageBaseAddress,
+                      findSectionAddress);
+    }
+  }
+}
+
+void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                        uint64_t fixupAddress,
+                                        uint64_t targetAddress,
+                                        uint64_t inAtomAddress,
+                                        uint64_t imageBaseAddress,
+                                        FindAddressForAtom findSectionAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  int32_t displacement;
+  uint32_t instruction;
+  uint32_t value32;
+  uint32_t value64;
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    displacement = (targetAddress - fixupAddress) + ref.addend();
+    *loc32 = setDisplacementInBranch26(*loc32, displacement);
+    return;
+  case page21:
+  case gotPage21:
+  case tlvPage21:
+    displacement =
+        ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
+    *loc32 = setDisplacementInADRP(*loc32, displacement);
+    return;
+  case offset12:
+  case gotOffset12:
+  case tlvOffset12:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    *loc32 = setImm12(*loc32, displacement);
+    return;
+  case offset12scale2:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x1) == 0) &&
+           "scaled imm12 not accessing 2-byte aligneds");
+    *loc32 = setImm12(*loc32, displacement >> 1);
+    return;
+  case offset12scale4:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x3) == 0) &&
+           "scaled imm12 not accessing 4-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 2);
+    return;
+  case offset12scale8:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x7) == 0) &&
+           "scaled imm12 not accessing 8-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 3);
+    return;
+  case offset12scale16:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0xF) == 0) &&
+           "scaled imm12 not accessing 16-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 4);
+    return;
+  case addOffset12:
+    instruction = *loc32;
+    assert(((instruction & 0xFFC00000) == 0xF9400000) &&
+           "GOT reloc is not an LDR instruction");
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    value32 = 0x91000000 | (instruction & 0x000003FF);
+    instruction = setImm12(value32, displacement);
+    *loc32 = instruction;
+    return;
+  case pointer64:
+  case pointer64ToGOT:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case delta64:
+  case unwindFDEToFunction:
+    *loc64 = (targetAddress - fixupAddress) + ref.addend();
+    return;
+  case delta32:
+  case delta32ToGOT:
+  case unwindCIEToPersonalityFunction:
+    *loc32 = (targetAddress - fixupAddress) + ref.addend();
+    return;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case lazyPointer:
+    // Do nothing
+    return;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    return;
+  case imageOffset:
+    *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+    return;
+  case imageOffsetGot:
+    llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
+    break;
+  case unwindInfoToEhFrame:
+    value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    assert(value64 < 0xffffffU && "offset in __eh_frame too large");
+    *loc32 = (*loc32 & 0xff000000U) | value64;
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("invalid arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
+                                              uint8_t *loc,
+                                              uint64_t fixupAddress,
+                                              uint64_t targetAddress,
+                                              uint64_t inAtomAddress,
+                                              bool targetUnnamed) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    *loc32 = setDisplacementInBranch26(*loc32, 0);
+    return;
+  case page21:
+  case gotPage21:
+  case tlvPage21:
+    *loc32 = setDisplacementInADRP(*loc32, 0);
+    return;
+  case offset12:
+  case offset12scale2:
+  case offset12scale4:
+  case offset12scale8:
+  case offset12scale16:
+  case gotOffset12:
+  case tlvOffset12:
+    *loc32 = setImm12(*loc32, 0);
+    return;
+  case pointer64:
+    if (targetUnnamed)
+      *loc64 = targetAddress + ref.addend();
+    else
+      *loc64 = ref.addend();
+    return;
+  case delta64:
+    *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case unwindFDEToFunction:
+    // We don't emit unwindFDEToFunction in -r mode as they are implicitly
+    // generated from the data in the __eh_frame section.  So here we need
+    // to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc64 = targetAddress - fixupAddress;
+    return;
+  case delta32:
+    *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case negDelta32:
+    // We don't emit negDelta32 in -r mode as they are implicitly
+    // generated from the data in the __eh_frame section.  So here we need
+    // to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case pointer64ToGOT:
+    *loc64 = 0;
+    return;
+  case delta32ToGOT:
+    *loc32 = inAtomAddress - fixupAddress;
+    return;
+  case unwindCIEToPersonalityFunction:
+    // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
+    // implicitly generated from the data in the __eh_frame section.  So here we
+    // need to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc32 = targetAddress - fixupAddress;
+    return;
+  case addOffset12:
+    llvm_unreachable("lazy reference kind implies GOT pass was run");
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+  case imageOffset:
+  case imageOffsetGot:
+  case unwindInfoToEhFrame:
+    llvm_unreachable("fixup implies __unwind_info");
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::appendSectionRelocations(
+    const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
+    FindSymbolIndexForAtom symbolIndexForAtom,
+    FindSectionIndexForAtom sectionIndexForAtom,
+    FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+    }
+    return;
+  case page21:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+    }
+    return;
+  case offset12:
+  case offset12scale2:
+  case offset12scale4:
+  case offset12scale8:
+  case offset12scale16:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGEOFF12  | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
+    }
+    return;
+  case gotPage21:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+    return;
+  case gotOffset12:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
+    return;
+  case tlvPage21:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+    return;
+  case tlvOffset12:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
+    return;
+  case pointer64:
+    if (ref.target()->name().empty())
+      appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_UNSIGNED           | rLength8);
+    else
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_UNSIGNED | rExtern | rLength8);
+    return;
+  case delta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                ARM64_RELOC_UNSIGNED  | rExtern | rLength8);
+    return;
+  case delta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                ARM64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case pointer64ToGOT:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
+    return;
+  case delta32ToGOT:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
+    return;
+  case addOffset12:
+    llvm_unreachable("lazy reference kind implies GOT pass was run");
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+  case imageOffset:
+  case imageOffsetGot:
+    llvm_unreachable("deltas from mach_header can only be in final images");
+  case unwindCIEToPersonalityFunction:
+  case unwindFDEToFunction:
+  case unwindInfoToEhFrame:
+  case negDelta32:
+    // Do nothing.
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
new file mode 100644 (file)
index 0000000..15f1f79
--- /dev/null
@@ -0,0 +1,647 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+using llvm::support::little16_t;
+using llvm::support::little32_t;
+
+class ArchHandler_x86 : public ArchHandler {
+public:
+  ArchHandler_x86() = default;
+  ~ArchHandler_x86() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+  bool isCallSite(const Reference &) override;
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  bool needsCompactUnwind() override {
+    return false;
+  }
+
+  Reference::KindValue imageOffsetKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return delta32;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return invalid;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x04000000U;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+  bool isDataInCodeTransition(Reference::KindValue refKind) override {
+    switch (refKind) {
+    case modeCode:
+    case modeData:
+      return true;
+    default:
+      return false;
+      break;
+    }
+  }
+
+  Reference::KindValue dataInCodeTransitionStart(
+                                        const MachODefinedAtom &atom) override {
+    return modeData;
+  }
+
+  Reference::KindValue dataInCodeTransitionEnd(
+                                        const MachODefinedAtom &atom) override {
+    return modeCode;
+  }
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum X86Kind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    modeCode,              /// Content starting at this offset is code.
+    modeData,              /// Content starting at this offset is data.
+
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    branch16,              /// ex: callw _foo
+    abs32,                 /// ex: movl _foo, %eax
+    funcRel32,             /// ex: movl _foo-L1(%eax), %eax
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+    negDelta32,            /// ex: .long . - _foo
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  static bool useExternalRelocationTo(const Atom &target);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress);
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_x86
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(modeCode),
+  LLD_KIND_STRING_ENTRY(modeData),
+  LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(branch16),
+  LLD_KIND_STRING_ENTRY(abs32),
+  LLD_KIND_STRING_ENTRY(funcRel32),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+  { Reference::KindArch::x86, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+
+  // x86 code alignment
+  1,
+
+  // Stub size and code
+  6,
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86, abs32, 2, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86, branch32, 6, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeNonLazyPointer,
+
+  // Stub Helper-Common size and code
+  12,
+  // Stub helper alignment
+  2,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $dyld_ImageLoaderCache
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *_fast_lazy_bind
+    0x90 },                                     // nop
+  { Reference::KindArch::x86, abs32, 1, 0 },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::x86, abs32, 7, 0 },
+  { false, 0, 0, 0 }
+};
+
+bool ArchHandler_x86::isCallSite(const Reference &ref) {
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
+  if (!reloc.scattered)
+    return false;
+  return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
+         (reloc.type == GENERIC_RELOC_SECTDIFF);
+}
+
+llvm::Error
+ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
+                                  const DefinedAtom *inAtom,
+                                  uint32_t offsetInAtom,
+                                  uint64_t fixupAddress, bool swap,
+                                  FindAtomBySectionAndAddress atomFromAddress,
+                                  FindAtomBySymbolIndex atomFromSymbolIndex,
+                                  Reference::KindValue *kind,
+                                  const lld::Atom **target,
+                                  Reference::Addend *addend) {
+  DefinedAtom::ContentPermissions perms;
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (relocPattern(reloc)) {
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
+    // ex: call _foo (and _foo undefined)
+    *kind = branch32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
+    // ex: call _foo (and _foo defined)
+    *kind = branch32;
+    targetAddress =
+        fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
+    // ex: call _foo+n (and _foo defined)
+    *kind = branch32;
+    targetAddress =
+        fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = targetAddress - reloc.value;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+    // ex: callw _foo (and _foo undefined)
+    *kind = branch16;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
+    // ex: callw _foo (and _foo defined)
+    *kind = branch16;
+    targetAddress =
+        fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
+    // ex: callw _foo+n (and _foo defined)
+    *kind = branch16;
+    targetAddress =
+        fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = targetAddress - reloc.value;
+    break;
+  case GENERIC_RELOC_VANILLA | rExtern | rLength4:
+    // ex: movl        _foo, %eax   (and _foo undefined)
+    // ex: .long _foo        (and _foo undefined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const ulittle32_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rLength4:
+    // ex: movl        _foo, %eax   (and _foo defined)
+    // ex: .long _foo        (and _foo defined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    targetAddress = *(const ulittle32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rLength4:
+    // ex: .long _foo+n      (and _foo defined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = *(const ulittle32_t *)fixupContent - reloc.value;
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported i386 relocation type");
+  }
+  return llvm::Error();
+}
+
+llvm::Error
+ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                      const normalized::Relocation &reloc2,
+                                      const DefinedAtom *inAtom,
+                                      uint32_t offsetInAtom,
+                                      uint64_t fixupAddress, bool swap,
+                                      bool scatterable,
+                                      FindAtomBySectionAndAddress atomFromAddr,
+                                      FindAtomBySymbolIndex atomFromSymbolIndex,
+                                      Reference::KindValue *kind,
+                                      const lld::Atom **target,
+                                      Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  DefinedAtom::ContentPermissions perms = inAtom->permissions();
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint32_t value;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+         GENERIC_RELOC_PAIR | rScattered | rLength4):
+  case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+         GENERIC_RELOC_PAIR | rScattered | rLength4):
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    value = *(const little32_t *)fixupContent;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (fromTarget != inAtom) {
+      if (*target != inAtom)
+        return llvm::make_error<GenericError>(
+            "SECTDIFF relocation where neither target is in atom");
+      *kind = negDelta32;
+      *addend = toAddress - value - fromAddress;
+      *target = fromTarget;
+    } else {
+      if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
+        // SECTDIFF relocations are used in i386 codegen where the function
+        // prolog does a CALL to the next instruction which POPs the return
+        // address into EBX which becomes the pic-base register.  The POP
+        // instruction is label the used for the subtrahend in expressions.
+        // The funcRel32 kind represents the 32-bit delta to some symbol from
+        // the start of the function (atom) containing the funcRel32.
+        *kind = funcRel32;
+        uint32_t ta = fromAddress + value - toAddress;
+        *addend = ta - offsetInFrom;
+      } else {
+        *kind = delta32;
+        *addend = fromAddress + value - toAddress;
+      }
+    }
+    return llvm::Error();
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported i386 relocation type");
+  }
+}
+
+void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
+                                          bool relocatable,
+                                          FindAddressForAtom findAddress,
+                                          FindAddressForAtom findSectionAddress,
+                                          uint64_t imageBaseAddress,
+                            llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+                                        fixupAddress, targetAddress,
+                                        atomAddress);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset],
+                                  fixupAddress, targetAddress,
+                                  atomAddress);
+    }
+  }
+}
+
+void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                      uint64_t fixupAddress,
+                                      uint64_t targetAddress,
+                                      uint64_t inAtomAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case branch32:
+    *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    break;
+  case branch16:
+    *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
+    break;
+  case pointer32:
+  case abs32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case funcRel32:
+    *loc32 = targetAddress - inAtomAddress + ref.addend();
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    break;
+  case modeCode:
+  case modeData:
+  case lazyPointer:
+    // do nothing
+    break;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    break;
+  case invalid:
+    llvm_unreachable("invalid x86 Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
+                                               uint8_t *loc,
+                                               uint64_t fixupAddress,
+                                               uint64_t targetAddress,
+                                               uint64_t inAtomAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case branch32:
+    if (useExternalReloc)
+      *loc32 = ref.addend() - (fixupAddress + 4);
+    else
+      *loc32  =(targetAddress - (fixupAddress+4)) + ref.addend();
+    break;
+  case branch16:
+    if (useExternalReloc)
+      *loc16 = ref.addend() - (fixupAddress + 2);
+    else
+      *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
+    break;
+  case pointer32:
+  case abs32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case funcRel32:
+    *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    break;
+  case modeCode:
+  case modeData:
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid x86 Reference Kind");
+    break;
+  }
+}
+
+bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
+  // Undefined symbols are referenced via external relocations.
+  if (isa<UndefinedAtom>(&target))
+    return true;
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+     switch (defAtom->merge()) {
+     case DefinedAtom::mergeAsTentative:
+       // Tentative definitions are referenced via external relocations.
+       return true;
+     case DefinedAtom::mergeAsWeak:
+     case DefinedAtom::mergeAsWeakAndAddressUsed:
+       // Global weak-defs are referenced via external relocations.
+       return (defAtom->scope() == DefinedAtom::scopeGlobal);
+     default:
+       break;
+    }
+  }
+  // Everything else is reference via an internal relocation.
+  return false;
+}
+
+void ArchHandler_x86::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case modeCode:
+  case modeData:
+    break;
+  case branch32:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  GENERIC_RELOC_VANILLA |              rPcRel | rLength4);
+    }
+    break;
+  case branch16:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength2);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength2);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  GENERIC_RELOC_VANILLA |              rPcRel | rLength2);
+    }
+    break;
+  case pointer32:
+  case abs32:
+    if (useExternalReloc)
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
+                GENERIC_RELOC_VANILLA |    rExtern     |  rLength4);
+    else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                GENERIC_RELOC_VANILLA |    rScattered  |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                GENERIC_RELOC_VANILLA |                   rLength4);
+    }
+    break;
+  case funcRel32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case delta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case negDelta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    break;
+  case invalid:
+    llvm_unreachable("unknown x86 Reference Kind");
+    break;
+  }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
new file mode 100644 (file)
index 0000000..c36982a
--- /dev/null
@@ -0,0 +1,858 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_x86_64 : public ArchHandler {
+public:
+  ArchHandler_x86_64() = default;
+  ~ArchHandler_x86_64() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override {
+    return Reference::KindArch::x86_64;
+  }
+
+  /// Used by GOTPass to locate GOT References
+  bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+    if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+      return false;
+    assert(ref.kindArch() == Reference::KindArch::x86_64);
+    switch (ref.kindValue()) {
+    case ripRel32GotLoad:
+      canBypassGOT = true;
+      return true;
+    case ripRel32Got:
+      canBypassGOT = false;
+      return true;
+    case imageOffsetGot:
+      canBypassGOT = false;
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  bool isTLVAccess(const Reference &ref) const override {
+    assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref.kindArch() == Reference::KindArch::x86_64);
+    return ref.kindValue() == ripRel32Tlv;
+  }
+
+  void updateReferenceToTLV(const Reference *ref) override {
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::x86_64);
+    assert(ref->kindValue() == ripRel32Tlv);
+    const_cast<Reference*>(ref)->setKindValue(ripRel32);
+  }
+
+  /// Used by GOTPass to update GOT References
+  void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::x86_64);
+
+    switch (ref->kindValue()) {
+    case ripRel32Got:
+      assert(targetNowGOT && "target must be GOT");
+    case ripRel32GotLoad:
+      const_cast<Reference *>(ref)
+        ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
+      break;
+    case imageOffsetGot:
+      const_cast<Reference *>(ref)->setKindValue(imageOffset);
+      break;
+    default:
+      llvm_unreachable("unknown GOT reference kind");
+    }
+  }
+
+  bool needsCompactUnwind() override {
+    return true;
+  }
+
+  Reference::KindValue imageOffsetKind() override {
+    return imageOffset;
+  }
+
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return imageOffsetGot;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return ripRel32Got;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return unwindFDEToFunction;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return unwindInfoToEhFrame;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return pointer64;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x04000000U;
+  }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+    return (atom->contentType() == DefinedAtom::typeCString);
+  }
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBase,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum X86_64Kind: Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    ripRel32,              /// ex: movq _foo(%rip), %rax
+    ripRel32Minus1,        /// ex: movb $0x12, _foo(%rip)
+    ripRel32Minus2,        /// ex: movw $0x1234, _foo(%rip)
+    ripRel32Minus4,        /// ex: movl $0x12345678, _foo(%rip)
+    ripRel32Anon,          /// ex: movq L1(%rip), %rax
+    ripRel32Minus1Anon,    /// ex: movb $0x12, L1(%rip)
+    ripRel32Minus2Anon,    /// ex: movw $0x1234, L1(%rip)
+    ripRel32Minus4Anon,    /// ex: movw $0x12345678, L1(%rip)
+    ripRel32GotLoad,       /// ex: movq  _foo@GOTPCREL(%rip), %rax
+    ripRel32Got,           /// ex: pushq _foo@GOTPCREL(%rip)
+    ripRel32Tlv,           /// ex: movq  _foo@TLVP(%rip), %rdi
+    pointer64,             /// ex: .quad _foo
+    pointer64Anon,         /// ex: .quad L1
+    delta64,               /// ex: .quad _foo - .
+    delta32,               /// ex: .long _foo - .
+    delta64Anon,           /// ex: .quad L1 - .
+    delta32Anon,           /// ex: .long L1 - .
+    negDelta64,            /// ex: .quad . - _foo
+    negDelta32,            /// ex: .long . - _foo
+
+    // Kinds introduced by Passes:
+    ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
+                           ///  "movq  _foo@GOTPCREL(%rip), %rax" can be changed
+                           /// to "leaq _foo(%rip), %rax
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+
+    imageOffset,           /// Location contains offset of atom in final image
+    imageOffsetGot,        /// Location contains offset of GOT entry for atom in
+                           /// final image (typically personality function).
+    unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
+                           /// relocatable object (yay for implicit contracts!).
+    unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
+                           /// refer to __eh_frame entry.
+    tlvInitSectionOffset   /// Location contains offset tlv init-value atom
+                           /// within the __thread_data section.
+  };
+
+  Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, uint64_t imageBaseAddress,
+                       FindAddressForAtom findSectionAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress);
+};
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+  LLD_KIND_STRING_ENTRY(ripRel32Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+  LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+  LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
+  LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
+  LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+  LLD_KIND_STRING_ENTRY(negDelta64),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+  LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+  LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+  LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+  { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+
+  // x86_64 code alignment 2^1
+  1,
+
+  // Stub size and code
+  6,
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86_64, ripRel32, 2, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushq $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86_64, branch32, 6, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeNonLazyPointer,
+
+  // Stub Helper-Common size and code
+  16,
+  // Stub helper alignment
+  2,
+  { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
+    0x41, 0x53,                                 // push %r11
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
+    0x90 },                                     // nop
+  { Reference::KindArch::x86_64, ripRel32, 3, 0 },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::x86_64, ripRel32, 11, 0 },
+  { false, 0, 0, 0 }
+
+};
+
+bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86_64::isPointer(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  Reference::KindValue kind = ref.kindValue();
+  return (kind == pointer64 || kind == pointer64Anon);
+}
+
+bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+  return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+  switch(relocPattern(reloc)) {
+  case X86_64_RELOC_BRANCH   | rPcRel | rExtern | rLength4:
+    return branch32;
+  case X86_64_RELOC_SIGNED   | rPcRel | rExtern | rLength4:
+    return ripRel32;
+  case X86_64_RELOC_SIGNED   | rPcRel |           rLength4:
+    return ripRel32Anon;
+  case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus1;
+  case X86_64_RELOC_SIGNED_1 | rPcRel |           rLength4:
+    return ripRel32Minus1Anon;
+  case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus2;
+  case X86_64_RELOC_SIGNED_2 | rPcRel |           rLength4:
+    return ripRel32Minus2Anon;
+  case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus4;
+  case X86_64_RELOC_SIGNED_4 | rPcRel |           rLength4:
+    return ripRel32Minus4Anon;
+  case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+    return ripRel32GotLoad;
+  case X86_64_RELOC_GOT      | rPcRel | rExtern | rLength4:
+    return ripRel32Got;
+  case X86_64_RELOC_TLV      | rPcRel | rExtern | rLength4:
+    return ripRel32Tlv;
+  case X86_64_RELOC_UNSIGNED          | rExtern | rLength8:
+    return pointer64;
+  case X86_64_RELOC_UNSIGNED                    | rLength8:
+    return pointer64Anon;
+  default:
+    return invalid;
+  }
+}
+
+llvm::Error
+ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+                                    const DefinedAtom *inAtom,
+                                    uint32_t offsetInAtom,
+                                    uint64_t fixupAddress, bool swap,
+                                    FindAtomBySectionAndAddress atomFromAddress,
+                                    FindAtomBySymbolIndex atomFromSymbolIndex,
+                                    Reference::KindValue *kind,
+                                    const lld::Atom **target,
+                                    Reference::Addend *addend) {
+  *kind = kindFromReloc(reloc);
+  if (*kind == invalid)
+    return llvm::make_error<GenericError>("unknown type");
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (*kind) {
+  case branch32:
+  case ripRel32:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little32_t *)fixupContent;
+    return llvm::Error();
+  case ripRel32Minus1:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 1;
+    return llvm::Error();
+  case ripRel32Minus2:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 2;
+    return llvm::Error();
+  case ripRel32Minus4:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 4;
+    return llvm::Error();
+  case ripRel32Anon:
+    targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus1Anon:
+    targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus2Anon:
+    targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus4Anon:
+    targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32GotLoad:
+  case ripRel32Got:
+  case ripRel32Tlv:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little32_t *)fixupContent;
+    return llvm::Error();
+  case tlvInitSectionOffset:
+  case pointer64:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's
+    // initial value) we need to handle it specially.
+    if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
+        offsetInAtom == 16) {
+      *kind = tlvInitSectionOffset;
+      assert(*addend == 0 && "TLV-init has non-zero addend?");
+    } else
+      *addend = *(const little64_t *)fixupContent;
+    return llvm::Error();
+  case pointer64Anon:
+    targetAddress = *(const little64_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  default:
+    llvm_unreachable("bad reloc kind");
+  }
+}
+
+llvm::Error
+ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                   const normalized::Relocation &reloc2,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   bool scatterable,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind,
+                                   const lld::Atom **target,
+                                   Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  const lld::Atom *fromTarget;
+  if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+    return ec;
+
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength8): {
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent;
+    if (inAtom == fromTarget) {
+      *kind = delta64;
+      *addend = encodedAddend + offsetInAtom;
+    } else if (inAtom == *target) {
+      *kind = negDelta64;
+      *addend = encodedAddend - offsetInAtom;
+      *target = fromTarget;
+    } else
+      return llvm::make_error<GenericError>("Invalid pointer diff");
+    return llvm::Error();
+  }
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength4): {
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent;
+    if (inAtom == fromTarget) {
+      *kind = delta32;
+      *addend = encodedAddend + offsetInAtom;
+    } else if (inAtom == *target) {
+      *kind = negDelta32;
+      *addend = encodedAddend - offsetInAtom;
+      *target = fromTarget;
+    } else
+      return llvm::make_error<GenericError>("Invalid pointer diff");
+    return llvm::Error();
+  }
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength8):
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("pointer diff not in base atom");
+    *kind = delta64Anon;
+    targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength4):
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("pointer diff not in base atom");
+    *kind = delta32Anon;
+    targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  default:
+    return llvm::make_error<GenericError>("unknown pair");
+  }
+}
+
+void ArchHandler_x86_64::generateAtomContent(
+    const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+    FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+    llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+                                        fixupAddress, targetAddress,
+                                        atomAddress);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset],
+                      fixupAddress, targetAddress,
+                      atomAddress, imageBaseAddress, findSectionAddress);
+    }
+  }
+}
+
+void ArchHandler_x86_64::applyFixupFinal(
+    const Reference &ref, uint8_t *loc, uint64_t fixupAddress,
+    uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress,
+    FindAddressForAtom findSectionAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+  case ripRel32:
+  case ripRel32Anon:
+  case ripRel32Got:
+  case ripRel32GotLoad:
+  case ripRel32Tlv:
+    *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+    return;
+  case pointer64:
+  case pointer64Anon:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case tlvInitSectionOffset:
+    *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    return;
+  case ripRel32Minus1:
+  case ripRel32Minus1Anon:
+    *loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
+    return;
+  case ripRel32Minus2:
+  case ripRel32Minus2Anon:
+    *loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
+    return;
+  case ripRel32Minus4:
+  case ripRel32Minus4Anon:
+    *loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
+    return;
+  case delta32:
+  case delta32Anon:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    return;
+  case delta64:
+  case delta64Anon:
+  case unwindFDEToFunction:
+    *loc64 = targetAddress - fixupAddress + ref.addend();
+    return;
+  case ripRel32GotLoadNowLea:
+    // Change MOVQ to LEA
+    assert(loc[-2] == 0x8B);
+    loc[-2] = 0x8D;
+    *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+    return;
+  case negDelta64:
+    *loc64 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case lazyPointer:
+    // Do nothing
+    return;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+    *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+    return;
+  case unwindInfoToEhFrame: {
+    uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    assert(val < 0xffffffU && "offset in __eh_frame too large");
+    *loc32 = (*loc32 & 0xff000000U) | val;
+    return;
+  }
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("invalid x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
+                                               uint8_t *loc,
+                                               uint64_t fixupAddress,
+                                               uint64_t targetAddress,
+                                               uint64_t inAtomAddress)  {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+  case ripRel32:
+  case ripRel32Got:
+  case ripRel32GotLoad:
+  case ripRel32Tlv:
+    *loc32 = ref.addend();
+    return;
+  case ripRel32Anon:
+    *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    return;
+  case tlvInitSectionOffset:
+  case pointer64:
+    *loc64 = ref.addend();
+    return;
+  case pointer64Anon:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case ripRel32Minus1:
+    *loc32 = ref.addend() - 1;
+    return;
+  case ripRel32Minus1Anon:
+    *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
+    return;
+  case ripRel32Minus2:
+    *loc32 = ref.addend() - 2;
+    return;
+  case ripRel32Minus2Anon:
+    *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
+    return;
+  case ripRel32Minus4:
+    *loc32 = ref.addend() - 4;
+    return;
+  case ripRel32Minus4Anon:
+    *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    return;
+  case delta32:
+    *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case delta32Anon:
+    // The value we write here should be the the delta to the target
+    // after taking in to account the difference from the fixup back to the
+    // last defined label
+    // ie, if we have:
+    // _base: ...
+    // Lfixup: .quad Ltarget - .
+    // ...
+    // Ltarget:
+    //
+    // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+    *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+    return;
+  case delta64:
+    *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case delta64Anon:
+    // The value we write here should be the the delta to the target
+    // after taking in to account the difference from the fixup back to the
+    // last defined label
+    // ie, if we have:
+    // _base: ...
+    // Lfixup: .quad Ltarget - .
+    // ...
+    // Ltarget:
+    //
+    // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+    *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+    return;
+  case negDelta64:
+    *loc64 = ref.addend() + fixupAddress - inAtomAddress;
+    return;
+  case negDelta32:
+    *loc32 = ref.addend() + fixupAddress - inAtomAddress;
+    return;
+  case ripRel32GotLoadNowLea:
+    llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+    return;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+  case unwindInfoToEhFrame:
+    llvm_unreachable("fixup implies __unwind_info");
+    return;
+  case unwindFDEToFunction:
+    // Do nothing for now
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
+    return;
+  case ripRel32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED | rPcRel           | rLength4 );
+    return;
+  case ripRel32Got:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32GotLoad:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Tlv:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
+    return;
+  case tlvInitSectionOffset:
+  case pointer64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED  | rExtern | rLength8);
+    return;
+  case pointer64Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED | rLength8);
+    return;
+  case ripRel32Minus1:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus1Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_1 | rPcRel           | rLength4 );
+    return;
+  case ripRel32Minus2:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus2Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_2 | rPcRel           | rLength4 );
+    return;
+  case ripRel32Minus4:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus4Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_4 | rPcRel           | rLength4 );
+    return;
+  case delta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case delta32Anon:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED             | rLength4 );
+    return;
+  case delta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
+    return;
+  case delta64Anon:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED             | rLength8 );
+    return;
+  case unwindFDEToFunction:
+  case unwindInfoToEhFrame:
+    return;
+  case negDelta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case negDelta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
+    return;
+  case ripRel32GotLoadNowLea:
+    llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+    return;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+    llvm_unreachable("__unwind_info references should have been resolved");
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
new file mode 100644 (file)
index 0000000..573efca
--- /dev/null
@@ -0,0 +1,181 @@
+//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
+#define LLD_READER_WRITER_MACHO_ATOMS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
+
+namespace lld {
+
+class File;
+
+namespace mach_o {
+
+class MachODefinedAtom : public SimpleDefinedAtom {
+public:
+  MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+                   ContentType type, Merge merge, bool thumb, bool noDeadStrip,
+                   const ArrayRef<uint8_t> content, Alignment align)
+      : SimpleDefinedAtom(f), _name(name), _content(content),
+        _align(align), _contentType(type), _scope(scope), _merge(merge),
+        _thumb(thumb), _noDeadStrip(noDeadStrip) {}
+
+  // Constructor for zero-fill content
+  MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+                   ContentType type, uint64_t size, bool noDeadStrip,
+                   Alignment align)
+      : SimpleDefinedAtom(f), _name(name),
+        _content(ArrayRef<uint8_t>(nullptr, size)), _align(align),
+        _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
+        _noDeadStrip(noDeadStrip) {}
+
+  ~MachODefinedAtom() override = default;
+
+  uint64_t size() const override { return _content.size(); }
+
+  ContentType contentType() const override { return _contentType; }
+
+  Alignment alignment() const override { return _align; }
+
+  StringRef name() const override { return _name; }
+
+  Scope scope() const override { return _scope; }
+
+  Merge merge() const override { return _merge; }
+
+  DeadStripKind deadStrip() const override {
+    if (_contentType == DefinedAtom::typeInitializerPtr)
+      return deadStripNever;
+    if (_contentType == DefinedAtom::typeTerminatorPtr)
+      return deadStripNever;
+    if (_noDeadStrip)
+      return deadStripNever;
+    return deadStripNormal;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    // Note: Zerofill atoms have a content pointer which is null.
+    return _content;
+  }
+
+  bool isThumb() const { return _thumb; }
+
+private:
+  const StringRef _name;
+  const ArrayRef<uint8_t> _content;
+  const DefinedAtom::Alignment _align;
+  const ContentType _contentType;
+  const Scope _scope;
+  const Merge _merge;
+  const bool _thumb;
+  const bool _noDeadStrip;
+};
+
+class MachODefinedCustomSectionAtom : public MachODefinedAtom {
+public:
+  MachODefinedCustomSectionAtom(const File &f, const StringRef name,
+                                Scope scope, ContentType type, Merge merge,
+                                bool thumb, bool noDeadStrip,
+                                const ArrayRef<uint8_t> content,
+                                StringRef sectionName, Alignment align)
+      : MachODefinedAtom(f, name, scope, type, merge, thumb, noDeadStrip,
+                         content, align),
+        _sectionName(sectionName) {}
+
+  ~MachODefinedCustomSectionAtom() override = default;
+
+  SectionChoice sectionChoice() const override {
+    return DefinedAtom::sectionCustomRequired;
+  }
+
+  StringRef customSectionName() const override {
+    return _sectionName;
+  }
+private:
+  StringRef _sectionName;
+};
+
+class MachOTentativeDefAtom : public SimpleDefinedAtom {
+public:
+  MachOTentativeDefAtom(const File &f, const StringRef name, Scope scope,
+                        uint64_t size, DefinedAtom::Alignment align)
+      : SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size),
+        _align(align) {}
+
+  ~MachOTentativeDefAtom() override = default;
+
+  uint64_t size() const override { return _size; }
+
+  Merge merge() const override { return DefinedAtom::mergeAsTentative; }
+
+  ContentType contentType() const override { return DefinedAtom::typeZeroFill; }
+
+  Alignment alignment() const override { return _align; }
+
+  StringRef name() const override { return _name; }
+
+  Scope scope() const override { return _scope; }
+
+  ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+private:
+  const std::string _name;
+  const Scope _scope;
+  const uint64_t _size;
+  const DefinedAtom::Alignment _align;
+};
+
+class MachOSharedLibraryAtom : public SharedLibraryAtom {
+public:
+  MachOSharedLibraryAtom(const File &file, StringRef name,
+                         StringRef dylibInstallName, bool weakDef)
+      : SharedLibraryAtom(), _file(file), _name(name),
+        _dylibInstallName(dylibInstallName) {}
+  ~MachOSharedLibraryAtom() override = default;
+
+  StringRef loadName() const override { return _dylibInstallName; }
+
+  bool canBeNullAtRuntime() const override {
+    // FIXME: this may actually be changeable. For now, all symbols are strongly
+    // defined though.
+    return false;
+  }
+
+  const File &file() const override { return _file; }
+
+  StringRef name() const override { return _name; }
+
+  Type type() const override {
+    // Unused in MachO (I think).
+    return Type::Unknown;
+  }
+
+  uint64_t size() const override {
+    // Unused in MachO (I think)
+    return 0;
+  }
+
+private:
+  const File &_file;
+  StringRef _name;
+  StringRef _dylibInstallName;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
new file mode 100644 (file)
index 0000000..70f451c
--- /dev/null
@@ -0,0 +1,29 @@
+add_lld_library(lldMachO
+  ArchHandler.cpp
+  ArchHandler_arm.cpp
+  ArchHandler_arm64.cpp
+  ArchHandler_x86.cpp
+  ArchHandler_x86_64.cpp
+  CompactUnwindPass.cpp
+  GOTPass.cpp
+  LayoutPass.cpp
+  MachOLinkingContext.cpp
+  MachONormalizedFileBinaryReader.cpp
+  MachONormalizedFileBinaryWriter.cpp
+  MachONormalizedFileFromAtoms.cpp
+  MachONormalizedFileToAtoms.cpp
+  MachONormalizedFileYAML.cpp
+  ObjCPass.cpp
+  ShimPass.cpp
+  StubsPass.cpp
+  TLVPass.cpp
+  WriterMachO.cpp
+  LINK_LIBS
+    lldCore
+    lldYAML
+    LLVMObject
+    LLVMSupport
+    ${PTHREAD_LIB}
+  )
+
+include_directories(.)
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
new file mode 100644 (file)
index 0000000..6f5ab83
--- /dev/null
@@ -0,0 +1,582 @@
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file A pass to convert MachO's __compact_unwind sections into the final
+/// __unwind_info format used during runtime. See
+/// mach-o/compact_unwind_encoding.h for more details on the formats involved.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#define DEBUG_TYPE "macho-compact-unwind"
+
+namespace lld {
+namespace mach_o {
+
+namespace {
+struct CompactUnwindEntry {
+  const Atom *rangeStart;
+  const Atom *personalityFunction;
+  const Atom *lsdaLocation;
+  const Atom *ehFrame;
+
+  uint32_t rangeLength;
+
+  // There are 3 types of compact unwind entry, distinguished by the encoding
+  // value: 0 indicates a function with no unwind info;
+  // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to
+  // __eh_frame, and that the ehFrame entry will be valid; any other value is a
+  // real compact unwind entry -- personalityFunction will be set and
+  // lsdaLocation may be.
+  uint32_t encoding;
+
+  CompactUnwindEntry(const DefinedAtom *function)
+      : rangeStart(function), personalityFunction(nullptr),
+        lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()),
+        encoding(0) {}
+
+  CompactUnwindEntry()
+      : rangeStart(nullptr), personalityFunction(nullptr),
+        lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {}
+};
+
+struct UnwindInfoPage {
+  ArrayRef<CompactUnwindEntry> entries;
+};
+}
+
+class UnwindInfoAtom : public SimpleDefinedAtom {
+public:
+  UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig,
+                 std::vector<const Atom *> &personalities,
+                 std::vector<uint32_t> &commonEncodings,
+                 std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs)
+      : SimpleDefinedAtom(file), _archHandler(archHandler),
+        _commonEncodingsOffset(7 * sizeof(uint32_t)),
+        _personalityArrayOffset(_commonEncodingsOffset +
+                                commonEncodings.size() * sizeof(uint32_t)),
+        _topLevelIndexOffset(_personalityArrayOffset +
+                             personalities.size() * sizeof(uint32_t)),
+        _lsdaIndexOffset(_topLevelIndexOffset +
+                         3 * (pages.size() + 1) * sizeof(uint32_t)),
+        _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)),
+        _isBig(isBig) {
+
+    addHeader(commonEncodings.size(), personalities.size(), pages.size());
+    addCommonEncodings(commonEncodings);
+    addPersonalityFunctions(personalities);
+    addTopLevelIndexes(pages);
+    addLSDAIndexes(pages, numLSDAs);
+    addSecondLevelPages(pages);
+  }
+
+  ~UnwindInfoAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeProcessedUnwindInfo;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override { return _contents.size(); }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR__;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override { return _contents; }
+
+  void addHeader(uint32_t numCommon, uint32_t numPersonalities,
+                 uint32_t numPages) {
+    using normalized::write32;
+
+    uint32_t headerSize = 7 * sizeof(uint32_t);
+    _contents.resize(headerSize);
+
+    uint8_t *headerEntries = _contents.data();
+    // version
+    write32(headerEntries, 1, _isBig);
+    // commonEncodingsArraySectionOffset
+    write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig);
+    // commonEncodingsArrayCount
+    write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig);
+    // personalityArraySectionOffset
+    write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset,
+            _isBig);
+    // personalityArrayCount
+    write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig);
+    // indexSectionOffset
+    write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig);
+    // indexCount
+    write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig);
+  }
+
+  /// Add the list of common encodings to the section; this is simply an array
+  /// of uint32_t compact values. Size has already been specified in the header.
+  void addCommonEncodings(std::vector<uint32_t> &commonEncodings) {
+    using normalized::write32;
+
+    _contents.resize(_commonEncodingsOffset +
+                     commonEncodings.size() * sizeof(uint32_t));
+    uint8_t *commonEncodingsArea =
+        reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset);
+
+    for (uint32_t encoding : commonEncodings) {
+      write32(commonEncodingsArea, encoding, _isBig);
+      commonEncodingsArea += sizeof(uint32_t);
+    }
+  }
+
+  void addPersonalityFunctions(std::vector<const Atom *> personalities) {
+    _contents.resize(_personalityArrayOffset +
+                     personalities.size() * sizeof(uint32_t));
+
+    for (unsigned i = 0; i < personalities.size(); ++i)
+      addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t),
+                                personalities[i]);
+  }
+
+  void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) {
+    using normalized::write32;
+
+    uint32_t numIndexes = pages.size() + 1;
+    _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t));
+
+    uint32_t pageLoc = _firstPageOffset;
+
+    // The most difficult job here is calculating the LSDAs; everything else
+    // follows fairly naturally, but we can't state where the first
+    uint8_t *indexData = &_contents[_topLevelIndexOffset];
+    uint32_t numLSDAs = 0;
+    for (unsigned i = 0; i < pages.size(); ++i) {
+      // functionOffset
+      addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t),
+                        pages[i].entries[0].rangeStart);
+      // secondLevelPagesSectionOffset
+      write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig);
+      write32(indexData + (3 * i + 2) * sizeof(uint32_t),
+              _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+
+      for (auto &entry : pages[i].entries)
+        if (entry.lsdaLocation)
+          ++numLSDAs;
+    }
+
+    // Finally, write out the final sentinel index
+    auto &finalEntry = pages[pages.size() - 1].entries.back();
+    addImageReference(_topLevelIndexOffset +
+                          3 * pages.size() * sizeof(uint32_t),
+                      finalEntry.rangeStart, finalEntry.rangeLength);
+    // secondLevelPagesSectionOffset => 0
+    write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t),
+            _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+  }
+
+  void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) {
+    _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t));
+
+    uint32_t curOffset = _lsdaIndexOffset;
+    for (auto &page : pages) {
+      for (auto &entry : page.entries) {
+        if (!entry.lsdaLocation)
+          continue;
+
+        addImageReference(curOffset, entry.rangeStart);
+        addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation);
+        curOffset += 2 * sizeof(uint32_t);
+      }
+    }
+  }
+
+  void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) {
+    for (auto &page : pages) {
+      addRegularSecondLevelPage(page);
+    }
+  }
+
+  void addRegularSecondLevelPage(const UnwindInfoPage &page) {
+    uint32_t curPageOffset = _contents.size();
+    const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t);
+    uint32_t curPageSize =
+        headerSize + 2 * page.entries.size() * sizeof(uint32_t);
+    _contents.resize(curPageOffset + curPageSize);
+
+    using normalized::write32;
+    using normalized::write16;
+    // 2 => regular page
+    write32(&_contents[curPageOffset], 2, _isBig);
+    // offset of 1st entry
+    write16(&_contents[curPageOffset + 4], headerSize, _isBig);
+    write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig);
+
+    uint32_t pagePos = curPageOffset + headerSize;
+    for (auto &entry : page.entries) {
+      addImageReference(pagePos, entry.rangeStart);
+
+      write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding,
+              _isBig);
+      if ((entry.encoding & 0x0f000000U) ==
+          _archHandler.dwarfCompactUnwindType())
+        addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame);
+
+      pagePos += 2 * sizeof(uint32_t);
+    }
+  }
+
+  void addEhFrameReference(uint32_t offset, const Atom *dest,
+                           Reference::Addend addend = 0) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.unwindRefToEhFrameKind(), offset, dest, addend);
+  }
+
+  void addImageReference(uint32_t offset, const Atom *dest,
+                         Reference::Addend addend = 0) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.imageOffsetKind(), offset, dest, addend);
+  }
+
+  void addImageReferenceIndirect(uint32_t offset, const Atom *dest) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.imageOffsetKindIndirect(), offset, dest, 0);
+  }
+
+private:
+  mach_o::ArchHandler &_archHandler;
+  std::vector<uint8_t> _contents;
+  uint32_t _commonEncodingsOffset;
+  uint32_t _personalityArrayOffset;
+  uint32_t _topLevelIndexOffset;
+  uint32_t _lsdaIndexOffset;
+  uint32_t _firstPageOffset;
+  bool _isBig;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class CompactUnwindPass : public Pass {
+public:
+  CompactUnwindPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
+        _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+
+    std::map<const Atom *, CompactUnwindEntry> unwindLocs;
+    std::map<const Atom *, const Atom *> dwarfFrames;
+    std::vector<const Atom *> personalities;
+    uint32_t numLSDAs = 0;
+
+    // First collect all __compact_unwind and __eh_frame entries, addressable by
+    // the function referred to.
+    collectCompactUnwindEntries(mergedFile, unwindLocs, personalities,
+                                numLSDAs);
+
+    collectDwarfFrameEntries(mergedFile, dwarfFrames);
+
+    // Skip rest of pass if no unwind info.
+    if (unwindLocs.empty() && dwarfFrames.empty())
+      return llvm::Error();
+
+    // FIXME: if there are more than 4 personality functions then we need to
+    // defer to DWARF info for the ones we don't put in the list. They should
+    // also probably be sorted by frequency.
+    assert(personalities.size() <= 4);
+
+    // TODO: Find commmon encodings for use by compressed pages.
+    std::vector<uint32_t> commonEncodings;
+
+    // Now sort the entries by final address and fixup the compact encoding to
+    // its final form (i.e. set personality function bits & create DWARF
+    // references where needed).
+    std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
+        mergedFile, unwindLocs, personalities, dwarfFrames);
+
+    // Remove any unused eh-frame atoms.
+    pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);
+
+    // Finally, we can start creating pages based on these entries.
+
+    DEBUG(llvm::dbgs() << "  Splitting entries into pages\n");
+    // FIXME: we split the entries into pages naively: lots of 4k pages followed
+    // by a small one. ld64 tried to minimize space and align them to real 4k
+    // boundaries. That might be worth doing, or perhaps we could perform some
+    // minor balancing for expected number of lookups.
+    std::vector<UnwindInfoPage> pages;
+    auto remainingInfos = llvm::makeArrayRef(unwindInfos);
+    do {
+      pages.push_back(UnwindInfoPage());
+
+      // FIXME: we only create regular pages at the moment. These can hold up to
+      // 1021 entries according to the documentation.
+      unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
+
+      pages.back().entries = remainingInfos.slice(0, entriesInPage);
+      remainingInfos = remainingInfos.slice(entriesInPage);
+
+      DEBUG(llvm::dbgs()
+            << "    Page from " << pages.back().entries[0].rangeStart->name()
+            << " to " << pages.back().entries.back().rangeStart->name() << " + "
+            << llvm::format("0x%x", pages.back().entries.back().rangeLength)
+            << " has " << entriesInPage << " entries\n");
+    } while (!remainingInfos.empty());
+
+    auto *unwind = new (_file.allocator())
+        UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
+                       commonEncodings, pages, numLSDAs);
+    mergedFile.addAtom(*unwind);
+
+    // Finally, remove all __compact_unwind atoms now that we've processed them.
+    mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
+      return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
+    });
+
+    return llvm::Error();
+  }
+
+  void collectCompactUnwindEntries(
+      const SimpleFile &mergedFile,
+      std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
+    DEBUG(llvm::dbgs() << "  Collecting __compact_unwind entries\n");
+
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
+        continue;
+
+      auto unwindEntry = extractCompactUnwindEntry(atom);
+      unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
+
+      DEBUG(llvm::dbgs() << "    Entry for " << unwindEntry.rangeStart->name()
+                         << ", encoding="
+                         << llvm::format("0x%08x", unwindEntry.encoding));
+      if (unwindEntry.personalityFunction)
+        DEBUG(llvm::dbgs() << ", personality="
+                           << unwindEntry.personalityFunction->name()
+                           << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+      DEBUG(llvm::dbgs() << '\n');
+
+      // Count number of LSDAs we see, since we need to know how big the index
+      // will be while laying out the section.
+      if (unwindEntry.lsdaLocation)
+        ++numLSDAs;
+
+      // Gather the personality functions now, so that they're in deterministic
+      // order (derived from the DefinedAtom order).
+      if (unwindEntry.personalityFunction) {
+        auto pFunc = std::find(personalities.begin(), personalities.end(),
+                               unwindEntry.personalityFunction);
+        if (pFunc == personalities.end())
+          personalities.push_back(unwindEntry.personalityFunction);
+      }
+    }
+  }
+
+  CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) {
+    CompactUnwindEntry entry;
+
+    for (const Reference *ref : *atom) {
+      switch (ref->offsetInAtom()) {
+      case 0:
+        // FIXME: there could legitimately be functions with multiple encoding
+        // entries. However, nothing produces them at the moment.
+        assert(ref->addend() == 0 && "unexpected offset into function");
+        entry.rangeStart = ref->target();
+        break;
+      case 0x10:
+        assert(ref->addend() == 0 && "unexpected offset into personality fn");
+        entry.personalityFunction = ref->target();
+        break;
+      case 0x18:
+        assert(ref->addend() == 0 && "unexpected offset into LSDA atom");
+        entry.lsdaLocation = ref->target();
+        break;
+      }
+    }
+
+    if (atom->rawContent().size() < 4 * sizeof(uint32_t))
+      return entry;
+
+    using normalized::read32;
+    entry.rangeLength =
+        read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig);
+    entry.encoding =
+        read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig);
+    return entry;
+  }
+
+  void
+  collectDwarfFrameEntries(const SimpleFile &mergedFile,
+                           std::map<const Atom *, const Atom *> &dwarfFrames) {
+    for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
+      if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
+        continue;
+      if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
+        continue;
+
+      if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom))
+        dwarfFrames[function] = ehFrameAtom;
+    }
+  }
+
+  /// Every atom defined in __TEXT,__text needs an entry in the final
+  /// __unwind_info section (in order). These comes from two sources:
+  ///   + Input __compact_unwind sections where possible (after adding the
+  ///      personality function offset which is only known now).
+  ///   + A synthesised reference to __eh_frame if there's no __compact_unwind
+  ///     or too many personality functions to be accommodated.
+  std::vector<CompactUnwindEntry> createUnwindInfoEntries(
+      const SimpleFile &mergedFile,
+      const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      const std::vector<const Atom *> &personalities,
+      const std::map<const Atom *, const Atom *> &dwarfFrames) {
+    std::vector<CompactUnwindEntry> unwindInfos;
+
+    DEBUG(llvm::dbgs() << "  Creating __unwind_info entries\n");
+    // The final order in the __unwind_info section must be derived from the
+    // order of typeCode atoms, since that's how they'll be put into the object
+    // file eventually (yuck!).
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      if (atom->contentType() != DefinedAtom::typeCode)
+        continue;
+
+      unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
+          atom, unwindLocs, personalities, dwarfFrames));
+
+      DEBUG(llvm::dbgs() << "    Entry for " << atom->name()
+                         << ", final encoding="
+                         << llvm::format("0x%08x", unwindInfos.back().encoding)
+                         << '\n');
+    }
+
+    return unwindInfos;
+  }
+
+  /// Remove unused EH frames.
+  ///
+  /// An EH frame is considered unused if there is a corresponding compact
+  /// unwind atom that doesn't require the EH frame.
+  void pruneUnusedEHFrames(
+                   SimpleFile &mergedFile,
+                   const std::vector<CompactUnwindEntry> &unwindInfos,
+                   const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+                   const std::map<const Atom *, const Atom *> &dwarfFrames) {
+
+    // Worklist of all 'used' FDEs.
+    std::vector<const DefinedAtom *> usedDwarfWorklist;
+
+    // We have to check two conditions when building the worklist:
+    // (1) EH frames used by compact unwind entries.
+    for (auto &entry : unwindInfos)
+      if (entry.ehFrame)
+        usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame));
+
+    // (2) EH frames that reference functions with no corresponding compact
+    //     unwind info.
+    for (auto &entry : dwarfFrames)
+      if (!unwindLocs.count(entry.first))
+        usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second));
+
+    // Add all transitively referenced CFI atoms by processing the worklist.
+    std::set<const Atom *> usedDwarfFrames;
+    while (!usedDwarfWorklist.empty()) {
+      const DefinedAtom *cfiAtom = usedDwarfWorklist.back();
+      usedDwarfWorklist.pop_back();
+      usedDwarfFrames.insert(cfiAtom);
+      for (const auto *ref : *cfiAtom) {
+        const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target());
+        if (cfiTarget->contentType() == DefinedAtom::typeCFI)
+          usedDwarfWorklist.push_back(cfiTarget);
+      }
+    }
+
+    // Finally, delete all unreferenced CFI atoms.
+    mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) {
+      if ((atom->contentType() == DefinedAtom::typeCFI) &&
+          !usedDwarfFrames.count(atom))
+        return true;
+      return false;
+    });
+  }
+
+  CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
+      const DefinedAtom *function,
+      const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      const std::vector<const Atom *> &personalities,
+      const std::map<const Atom *, const Atom *> &dwarfFrames) {
+    auto unwindLoc = unwindLocs.find(function);
+
+    CompactUnwindEntry entry;
+    if (unwindLoc == unwindLocs.end()) {
+      // Default entry has correct encoding (0 => no unwind), but we need to
+      // synthesise the function.
+      entry.rangeStart = function;
+      entry.rangeLength = function->size();
+    } else
+      entry = unwindLoc->second;
+
+
+    // If there's no __compact_unwind entry, or it explicitly says to use
+    // __eh_frame, we need to try and fill in the correct DWARF atom.
+    if (entry.encoding == _archHandler.dwarfCompactUnwindType() ||
+        entry.encoding == 0) {
+      auto dwarfFrame = dwarfFrames.find(function);
+      if (dwarfFrame != dwarfFrames.end()) {
+        entry.encoding = _archHandler.dwarfCompactUnwindType();
+        entry.ehFrame = dwarfFrame->second;
+      }
+    }
+
+    auto personality = std::find(personalities.begin(), personalities.end(),
+                                 entry.personalityFunction);
+    uint32_t personalityIdx = personality == personalities.end()
+                                  ? 0
+                                  : personality - personalities.begin() + 1;
+
+    // FIXME: We should also use DWARF when there isn't enough room for the
+    // personality function in the compact encoding.
+    assert(personalityIdx < 4 && "too many personality functions");
+
+    entry.encoding |= personalityIdx << 28;
+
+    if (entry.lsdaLocation)
+      entry.encoding |= 1U << 30;
+
+    return entry;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler &_archHandler;
+  MachOFile &_file;
+  bool _isBig;
+};
+
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsCompactUnwindPass());
+  pm.add(llvm::make_unique<CompactUnwindPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h
new file mode 100644 (file)
index 0000000..acced33
--- /dev/null
@@ -0,0 +1,155 @@
+//===- lib/ReaderWriter/MachO/ExecutableAtoms.h ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+
+#include "Atoms.h"
+#include "File.h"
+
+#include "llvm/Support/MachO.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+
+//
+// CEntryFile adds an UndefinedAtom for "_main" so that the Resolving
+// phase will fail if "_main" is undefined.
+//
+class CEntryFile : public SimpleFile {
+public:
+  CEntryFile(const MachOLinkingContext &context)
+      : SimpleFile("C entry", kindCEntryObject),
+       _undefMain(*this, context.entrySymbolName()) {
+    this->addAtom(_undefMain);
+  }
+
+private:
+  SimpleUndefinedAtom   _undefMain;
+};
+
+
+//
+// StubHelperFile adds an UndefinedAtom for "dyld_stub_binder" so that
+// the Resolveing phase will fail if "dyld_stub_binder" is undefined.
+//
+class StubHelperFile : public SimpleFile {
+public:
+  StubHelperFile(const MachOLinkingContext &context)
+      : SimpleFile("stub runtime", kindStubHelperObject),
+        _undefBinder(*this, context.binderSymbolName()) {
+    this->addAtom(_undefBinder);
+  }
+
+private:
+  SimpleUndefinedAtom   _undefBinder;
+};
+
+
+//
+// MachHeaderAliasFile lazily instantiates the magic symbols that mark the start
+// of the mach_header for final linked images.
+//
+class MachHeaderAliasFile : public SimpleFile {
+public:
+  MachHeaderAliasFile(const MachOLinkingContext &context)
+    : SimpleFile("mach_header symbols", kindHeaderObject) {
+    StringRef machHeaderSymbolName;
+    DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit;
+    StringRef dsoHandleName;
+    switch (context.outputMachOType()) {
+    case llvm::MachO::MH_OBJECT:
+      machHeaderSymbolName = "__mh_object_header";
+      break;
+    case llvm::MachO::MH_EXECUTE:
+      machHeaderSymbolName = "__mh_execute_header";
+      symbolScope = DefinedAtom::scopeGlobal;
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_FVMLIB:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_CORE:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_PRELOAD:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_DYLIB:
+      machHeaderSymbolName = "__mh_dylib_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_DYLINKER:
+      machHeaderSymbolName = "__mh_dylinker_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_BUNDLE:
+      machHeaderSymbolName = "__mh_bundle_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_DYLIB_STUB:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_DSYM:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_KEXT_BUNDLE:
+      dsoHandleName = "___dso_handle";
+      break;
+    }
+    if (!machHeaderSymbolName.empty())
+      _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+          *this, machHeaderSymbolName, symbolScope,
+          DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false,
+          true /* noDeadStrip */,
+          ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
+
+    if (!dsoHandleName.empty())
+      _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+          *this, dsoHandleName, DefinedAtom::scopeLinkageUnit,
+          DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false,
+          true /* noDeadStrip */,
+          ArrayRef<uint8_t>(), DefinedAtom::Alignment(1)));
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+
+private:
+  mutable AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
new file mode 100644 (file)
index 0000000..64a0fcf
--- /dev/null
@@ -0,0 +1,386 @@
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FILE_H
+#define LLD_READER_WRITER_MACHO_FILE_H
+
+#include "Atoms.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include <unordered_map>
+
+namespace lld {
+namespace mach_o {
+
+using lld::mach_o::normalized::Section;
+
+class MachOFile : public SimpleFile {
+public:
+  MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+    : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject),
+      _mb(std::move(mb)), _ctx(ctx) {}
+
+  MachOFile(StringRef path) : SimpleFile(path, File::kindMachObject) {}
+
+  void addDefinedAtom(StringRef name, Atom::Scope scope,
+                      DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+                      uint64_t sectionOffset, uint64_t contentSize, bool thumb,
+                      bool noDeadStrip, bool copyRefs,
+                      const Section *inSection) {
+    assert(sectionOffset+contentSize <= inSection->content.size());
+    ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+                                                        contentSize);
+    if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+      content = content.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+    auto *atom =
+        new (allocator()) MachODefinedAtom(*this, name, scope, type, merge,
+                                           thumb, noDeadStrip, content, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope,
+                      DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+                      bool thumb, bool noDeadStrip, uint64_t sectionOffset,
+                      uint64_t contentSize, StringRef sectionName,
+                      bool copyRefs, const Section *inSection) {
+    assert(sectionOffset+contentSize <= inSection->content.size());
+    ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+                                                        contentSize);
+   if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+      content = content.copy(allocator());
+      sectionName = sectionName.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+    auto *atom =
+        new (allocator()) MachODefinedCustomSectionAtom(*this, name, scope, type,
+                                                        merge, thumb,
+                                                        noDeadStrip, content,
+                                                        sectionName, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope,
+                              uint64_t sectionOffset, uint64_t size,
+                              bool noDeadStrip, bool copyRefs,
+                              const Section *inSection) {
+    if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+
+    DefinedAtom::ContentType type = DefinedAtom::typeUnknown;
+    switch (inSection->type) {
+    case llvm::MachO::S_ZEROFILL:
+      type = DefinedAtom::typeZeroFill;
+      break;
+    case llvm::MachO::S_THREAD_LOCAL_ZEROFILL:
+      type = DefinedAtom::typeTLVInitialZeroFill;
+      break;
+    default:
+      llvm_unreachable("Unrecognized zero-fill section");
+    }
+
+    auto *atom =
+        new (allocator()) MachODefinedAtom(*this, name, scope, type, size,
+                                           noDeadStrip, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addUndefinedAtom(StringRef name, bool copyRefs) {
+    if (copyRefs) {
+      // Make a copy of the atom's name that is owned by this file.
+      name = name.copy(allocator());
+    }
+    auto *atom = new (allocator()) SimpleUndefinedAtom(*this, name);
+    addAtom(*atom);
+    _undefAtoms[name] = atom;
+  }
+
+  void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size,
+                           DefinedAtom::Alignment align, bool copyRefs) {
+    if (copyRefs) {
+      // Make a copy of the atom's name that is owned by this file.
+      name = name.copy(allocator());
+    }
+    auto *atom =
+        new (allocator()) MachOTentativeDefAtom(*this, name, scope, size, align);
+    addAtom(*atom);
+    _undefAtoms[name] = atom;
+  }
+
+  /// Search this file for an the atom from 'section' that covers
+  /// 'offsetInSect'.  Returns nullptr is no atom found.
+  MachODefinedAtom *findAtomCoveringAddress(const Section &section,
+                                            uint64_t offsetInSect,
+                                            uint32_t *foundOffsetAtom=nullptr) {
+    const auto &pos = _sectionAtoms.find(&section);
+    if (pos == _sectionAtoms.end())
+      return nullptr;
+    const auto &vec = pos->second;
+    assert(offsetInSect < section.content.size());
+    // Vector of atoms for section are already sorted, so do binary search.
+    const auto &atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect,
+        [offsetInSect](const SectionOffsetAndAtom &ao,
+                       uint64_t targetAddr) -> bool {
+          // Each atom has a start offset of its slice of the
+          // section's content. This compare function must return true
+          // iff the atom's range is before the offset being searched for.
+          uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size();
+          return (atomsEndOffset <= offsetInSect);
+        });
+    if (atomPos == vec.end())
+      return nullptr;
+    if (foundOffsetAtom)
+      *foundOffsetAtom = offsetInSect - atomPos->offset;
+    return atomPos->atom;
+  }
+
+  /// Searches this file for an UndefinedAtom named 'name'. Returns
+  /// nullptr is no such atom found.
+  const lld::Atom *findUndefAtom(StringRef name) {
+    auto pos = _undefAtoms.find(name);
+    if (pos == _undefAtoms.end())
+      return nullptr;
+    return pos->second;
+  }
+
+  typedef std::function<void (MachODefinedAtom* atom)> DefinedAtomVisitor;
+
+  void eachDefinedAtom(DefinedAtomVisitor vistor) {
+    for (auto &sectAndAtoms : _sectionAtoms) {
+      for (auto &offAndAtom : sectAndAtoms.second) {
+        vistor(offAndAtom.atom);
+      }
+    }
+  }
+
+  typedef std::function<void(MachODefinedAtom *atom, uint64_t offset)>
+      SectionAtomVisitor;
+
+  void eachAtomInSection(const Section &section, SectionAtomVisitor visitor) {
+    auto pos = _sectionAtoms.find(&section);
+    if (pos == _sectionAtoms.end())
+      return;
+    auto vec = pos->second;
+
+    for (auto &offAndAtom : vec)
+      visitor(offAndAtom.atom, offAndAtom.offset);
+  }
+
+  MachOLinkingContext::Arch arch() const { return _arch; }
+  void setArch(MachOLinkingContext::Arch arch) { _arch = arch; }
+
+  MachOLinkingContext::OS OS() const { return _os; }
+  void setOS(MachOLinkingContext::OS os) { _os = os; }
+
+  MachOLinkingContext::ObjCConstraint objcConstraint() const {
+    return _objcConstraint;
+  }
+  void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) {
+    _objcConstraint = v;
+  }
+
+  uint32_t minVersion() const { return _minVersion; }
+  void setMinVersion(uint32_t v) { _minVersion = v; }
+
+  LoadCommandType minVersionLoadCommandKind() const {
+    return _minVersionLoadCommandKind;
+  }
+  void setMinVersionLoadCommandKind(LoadCommandType v) {
+    _minVersionLoadCommandKind = v;
+  }
+
+  uint32_t swiftVersion() const { return _swiftVersion; }
+  void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
+
+  bool subsectionsViaSymbols() const {
+    return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+  }
+  void setFlags(normalized::FileFlags v) { _flags = v; }
+
+  /// Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const File *F) {
+    return F->kind() == File::kindMachObject;
+  }
+
+protected:
+  std::error_code doParse() override {
+    // Convert binary file to normalized mach-o.
+    auto normFile = normalized::readBinary(_mb, _ctx->arch());
+    if (auto ec = normFile.takeError())
+      return llvm::errorToErrorCode(std::move(ec));
+    // Convert normalized mach-o to atoms.
+    if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false))
+      return llvm::errorToErrorCode(std::move(ec));
+    return std::error_code();
+  }
+
+private:
+  struct SectionOffsetAndAtom { uint64_t offset;  MachODefinedAtom *atom; };
+
+  void addAtomForSection(const Section *inSection, MachODefinedAtom* atom,
+                         uint64_t sectionOffset) {
+    SectionOffsetAndAtom offAndAtom;
+    offAndAtom.offset = sectionOffset;
+    offAndAtom.atom   = atom;
+     _sectionAtoms[inSection].push_back(offAndAtom);
+    addAtom(*atom);
+  }
+
+  typedef llvm::DenseMap<const normalized::Section *,
+                         std::vector<SectionOffsetAndAtom>>  SectionToAtoms;
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+  std::unique_ptr<MemoryBuffer> _mb;
+  MachOLinkingContext          *_ctx;
+  SectionToAtoms                _sectionAtoms;
+  NameToAtom                     _undefAtoms;
+  MachOLinkingContext::Arch      _arch = MachOLinkingContext::arch_unknown;
+  MachOLinkingContext::OS        _os = MachOLinkingContext::OS::unknown;
+  uint32_t                       _minVersion = 0;
+  LoadCommandType               _minVersionLoadCommandKind = (LoadCommandType)0;
+  MachOLinkingContext::ObjCConstraint _objcConstraint =
+      MachOLinkingContext::objc_unknown;
+  uint32_t                       _swiftVersion = 0;
+  normalized::FileFlags        _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+};
+
+class MachODylibFile : public SharedLibraryFile {
+public:
+  MachODylibFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+      : SharedLibraryFile(mb->getBufferIdentifier()),
+        _mb(std::move(mb)), _ctx(ctx) {}
+
+  MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
+
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+    // Pass down _installName so that if this requested symbol
+    // is re-exported through this dylib, the SharedLibraryAtom's loadName()
+    // is this dylib installName and not the implementation dylib's.
+    // NOTE: isData is not needed for dylibs (it matters for static libs).
+    return exports(name, _installName);
+  }
+
+  /// Adds symbol name that this dylib exports. The corresponding
+  /// SharedLibraryAtom is created lazily (since most symbols are not used).
+  void addExportedSymbol(StringRef name, bool weakDef, bool copyRefs) {
+    if (copyRefs) {
+      name = name.copy(allocator());
+    }
+    AtomAndFlags info(weakDef);
+    _nameToAtom[name] = info;
+  }
+
+  void addReExportedDylib(StringRef dylibPath) {
+    _reExportedDylibs.emplace_back(dylibPath);
+  }
+
+  StringRef installName() { return _installName; }
+  uint32_t currentVersion() { return _currentVersion; }
+  uint32_t compatVersion() { return _compatVersion; }
+
+  void setInstallName(StringRef name) { _installName = name; }
+  void setCompatVersion(uint32_t version) { _compatVersion = version; }
+  void setCurrentVersion(uint32_t version) { _currentVersion = version; }
+
+  typedef std::function<MachODylibFile *(StringRef)> FindDylib;
+
+  void loadReExportedDylibs(FindDylib find) {
+    for (ReExportedDylib &entry : _reExportedDylibs) {
+      entry.file = find(entry.path);
+    }
+  }
+
+  StringRef getDSOName() const override { return _installName; }
+
+  std::error_code doParse() override {
+    // Convert binary file to normalized mach-o.
+    auto normFile = normalized::readBinary(_mb, _ctx->arch());
+    if (auto ec = normFile.takeError())
+      return llvm::errorToErrorCode(std::move(ec));
+    // Convert normalized mach-o to atoms.
+    if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false))
+      return llvm::errorToErrorCode(std::move(ec));
+    return std::error_code();
+  }
+
+private:
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name,
+                                   StringRef installName) const {
+    // First, check if requested symbol is directly implemented by this dylib.
+    auto entry = _nameToAtom.find(name);
+    if (entry != _nameToAtom.end()) {
+      // FIXME: Make this map a set and only used in assert builds.
+      // Note, its safe to assert here as the resolver is the only client of
+      // this API and it only requests exports for undefined symbols.
+      // If we return from here we are no longer undefined so we should never
+      // get here again.
+      assert(!entry->second.atom && "Duplicate shared library export");
+      bool weakDef = entry->second.weakDef;
+      auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name,
+                                                            installName,
+                                                            weakDef);
+      entry->second.atom = atom;
+      return atom;
+    }
+
+    // Next, check if symbol is implemented in some re-exported dylib.
+    for (const ReExportedDylib &dylib : _reExportedDylibs) {
+      assert(dylib.file);
+      auto atom = dylib.file->exports(name, installName);
+      if (atom.get())
+        return atom;
+    }
+
+    // Symbol not exported or re-exported by this dylib.
+    return nullptr;
+  }
+
+  struct ReExportedDylib {
+    ReExportedDylib(StringRef p) : path(p), file(nullptr) { }
+    StringRef       path;
+    MachODylibFile *file;
+  };
+
+  struct AtomAndFlags {
+    AtomAndFlags() : atom(nullptr), weakDef(false) { }
+    AtomAndFlags(bool weak) : atom(nullptr), weakDef(weak) { }
+    const SharedLibraryAtom  *atom;
+    bool                      weakDef;
+  };
+
+  std::unique_ptr<MemoryBuffer>              _mb;
+  MachOLinkingContext                       *_ctx;
+  StringRef                                  _installName;
+  uint32_t                                   _currentVersion;
+  uint32_t                                   _compatVersion;
+  std::vector<ReExportedDylib>               _reExportedDylibs;
+  mutable std::unordered_map<StringRef, AtomAndFlags> _nameToAtom;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FILE_H
diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
new file mode 100644 (file)
index 0000000..76d2958
--- /dev/null
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/MachO/FlatNamespaceFile.h -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+#define LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class FlatNamespaceFile : public SharedLibraryFile {
+public:
+  FlatNamespaceFile(const MachOLinkingContext &context)
+    : SharedLibraryFile("flat namespace") { }
+
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+    return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
+                                                    false);
+  }
+
+  StringRef getDSOName() const override { return "flat-namespace"; }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _noDefinedAtoms;
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _noDefinedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
new file mode 100644 (file)
index 0000000..6cdca0a
--- /dev/null
@@ -0,0 +1,184 @@
+//===- lib/ReaderWriter/MachO/GOTPass.cpp -----------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all GOT kind references to real references.
+/// That is, in assembly you can write something like:
+///     movq foo@GOTPCREL(%rip), %rax
+/// which means you want to load a pointer to "foo" out of the GOT (global
+/// Offsets Table). In the object file, the Atom containing this instruction
+/// has a Reference whose target is an Atom named "foo" and the Reference
+/// kind is a GOT load.  The linker needs to instantiate a pointer sized
+/// GOT entry.  This is done be creating a GOT Atom to represent that pointer
+/// sized data in this pass, and altering the Atom graph so the Reference now
+/// points to the GOT Atom entry (corresponding to "foo") and changing the
+/// Reference Kind to reflect it is now pointing to a GOT entry (rather
+/// then needing a GOT entry).
+///
+/// There is one optimization the linker can do here.  If the target of the GOT
+/// is in the same linkage unit and does not need to be interposable, and
+/// the GOT use is just a load (not some other operation), this pass can
+/// transform that load into an LEA (add).  This optimizes away one memory load
+/// which at runtime that could stall the pipeline.  This optimization only
+/// works for architectures in which a (GOT) load instruction can be change to
+/// an LEA instruction that is the same size.  The method isGOTAccess() should
+/// only return true for "canBypassGOT" if this optimization is supported.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+//  GOT Entry Atom created by the GOT pass.
+//
+class GOTEntryAtom : public SimpleDefinedAtom {
+public:
+  GOTEntryAtom(const File &file, bool is64, StringRef name)
+    : SimpleDefinedAtom(file), _is64(is64), _name(name) { }
+
+  ~GOTEntryAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeGOT;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+  StringRef slotName() const {
+    return _name;
+  }
+
+private:
+  const bool _is64;
+  StringRef _name;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class GOTPass : public Pass {
+public:
+  GOTPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at instructions accessing the GOT.
+        bool canBypassGOT;
+        if (!_archHandler.isGOTAccess(*ref, canBypassGOT))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+
+        if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+          // Update reference kind to reflect that target is a direct accesss.
+          _archHandler.updateReferenceToGOT(ref, false);
+        } else {
+          // Replace the target with a reference to a GOT entry.
+          const DefinedAtom *gotEntry = makeGOTEntry(target);
+          const_cast<Reference *>(ref)->setTarget(gotEntry);
+          // Update reference kind to reflect that target is now a GOT entry.
+          _archHandler.updateReferenceToGOT(ref, true);
+        }
+      }
+    }
+
+    // Sort and add all created GOT Atoms to master file
+    std::vector<const GOTEntryAtom *> entries;
+    entries.reserve(_targetToGOT.size());
+    for (auto &it : _targetToGOT)
+      entries.push_back(it.second);
+    std::sort(entries.begin(), entries.end(),
+              [](const GOTEntryAtom *left, const GOTEntryAtom *right) {
+      return (left->slotName().compare(right->slotName()) < 0);
+    });
+    for (const GOTEntryAtom *slot : entries)
+      mergedFile.addAtom(*slot);
+
+    return llvm::Error();
+  }
+
+  bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
+    // Accesses to shared library symbols must go through GOT.
+    if (isa<SharedLibraryAtom>(target))
+      return true;
+    // Accesses to interposable symbols in same linkage unit must also go
+    // through GOT.
+    const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+    if (defTarget != nullptr &&
+        defTarget->interposable() != DefinedAtom::interposeNo) {
+      assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+      return true;
+    }
+    // Target does not require indirection.  So, if instruction allows GOT to be
+    // by-passed, do that optimization and don't create GOT entry.
+    return !canBypassGOT;
+  }
+
+  const DefinedAtom *makeGOTEntry(const Atom *target) {
+    auto pos = _targetToGOT.find(target);
+    if (pos == _targetToGOT.end()) {
+      auto *gotEntry = new (_file.allocator())
+          GOTEntryAtom(_file, _ctx.is64Bit(), target->name());
+      _targetToGOT[target] = gotEntry;
+      const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
+                                                nonLazyPointerReferenceToBinder;
+      gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+                             nlInfo.kind, 0, target, 0);
+      return gotEntry;
+    }
+    return pos->second;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                             &_archHandler;
+  MachOFile                                       &_file;
+  llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsGOTPass());
+  pm.add(llvm::make_unique<GOTPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
new file mode 100644 (file)
index 0000000..dd2ee85
--- /dev/null
@@ -0,0 +1,489 @@
+//===-- ReaderWriter/MachO/LayoutPass.cpp - Layout atoms ------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LayoutPass.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include <algorithm>
+#include <set>
+#include <utility>
+
+using namespace lld;
+
+#define DEBUG_TYPE "LayoutPass"
+
+namespace lld {
+namespace mach_o {
+
+static bool compareAtoms(const LayoutPass::SortKey &,
+                         const LayoutPass::SortKey &,
+                         LayoutPass::SortOverride customSorter);
+
+#ifndef NDEBUG
+// Return "reason (leftval, rightval)"
+static std::string formatReason(StringRef reason, int leftVal, int rightVal) {
+  return (Twine(reason) + " (" + Twine(leftVal) + ", " + Twine(rightVal) + ")")
+      .str();
+}
+
+// Less-than relationship of two atoms must be transitive, which is, if a < b
+// and b < c, a < c must be true. This function checks the transitivity by
+// checking the sort results.
+static void checkTransitivity(std::vector<LayoutPass::SortKey> &vec,
+                              LayoutPass::SortOverride customSorter) {
+  for (auto i = vec.begin(), e = vec.end(); (i + 1) != e; ++i) {
+    for (auto j = i + 1; j != e; ++j) {
+      assert(compareAtoms(*i, *j, customSorter));
+      assert(!compareAtoms(*j, *i, customSorter));
+    }
+  }
+}
+
+// Helper functions to check follow-on graph.
+typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+
+static std::string atomToDebugString(const Atom *atom) {
+  const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+  std::string str;
+  llvm::raw_string_ostream s(str);
+  if (definedAtom->name().empty())
+    s << "<anonymous " << definedAtom << ">";
+  else
+    s << definedAtom->name();
+  s << " in ";
+  if (definedAtom->customSectionName().empty())
+    s << "<anonymous>";
+  else
+    s << definedAtom->customSectionName();
+  s.flush();
+  return str;
+}
+
+static void showCycleDetectedError(const Registry &registry,
+                                   AtomToAtomT &followOnNexts,
+                                   const DefinedAtom *atom) {
+  const DefinedAtom *start = atom;
+  llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
+  do {
+    llvm::dbgs() << "  " << atomToDebugString(atom) << "\n";
+    for (const Reference *ref : *atom) {
+      StringRef kindValStr;
+      if (!registry.referenceKindToString(ref->kindNamespace(), ref->kindArch(),
+                                          ref->kindValue(), kindValStr)) {
+        kindValStr = "<unknown>";
+      }
+      llvm::dbgs() << "    " << kindValStr
+                   << ": " << atomToDebugString(ref->target()) << "\n";
+    }
+    atom = followOnNexts[atom];
+  } while (atom != start);
+  llvm::report_fatal_error("Cycle detected");
+}
+
+/// Exit if there's a cycle in a followon chain reachable from the
+/// given root atom. Uses the tortoise and hare algorithm to detect a
+/// cycle.
+static void checkNoCycleInFollowonChain(const Registry &registry,
+                                        AtomToAtomT &followOnNexts,
+                                        const DefinedAtom *root) {
+  const DefinedAtom *tortoise = root;
+  const DefinedAtom *hare = followOnNexts[root];
+  while (true) {
+    if (!tortoise || !hare)
+      return;
+    if (tortoise == hare)
+      showCycleDetectedError(registry, followOnNexts, tortoise);
+    tortoise = followOnNexts[tortoise];
+    hare = followOnNexts[followOnNexts[hare]];
+  }
+}
+
+static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
+                                      const DefinedAtom *atom) {
+  if (!atom) return;
+  auto i = followOnRoots.find(atom);
+  if (i == followOnRoots.end()) {
+    llvm_unreachable(((Twine("Atom <") + atomToDebugString(atom) +
+                       "> has no follow-on root!"))
+                         .str()
+                         .c_str());
+  }
+  const DefinedAtom *ap = i->second;
+  while (true) {
+    const DefinedAtom *next = followOnRoots[ap];
+    if (!next) {
+      llvm_unreachable((Twine("Atom <" + atomToDebugString(atom) +
+                              "> is not reachable from its root!"))
+                           .str()
+                           .c_str());
+    }
+    if (next == ap)
+      return;
+    ap = next;
+  }
+}
+
+static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) {
+  for (const DefinedAtom *atom : atomRange) {
+    llvm::dbgs() << "  file=" << atom->file().path()
+                 << ", name=" << atom->name()
+                 << ", size=" << atom->size()
+                 << ", type=" << atom->contentType()
+                 << ", ordinal=" << atom->ordinal()
+                 << "\n";
+  }
+}
+
+/// Verify that the followon chain is sane. Should not be called in
+/// release binary.
+void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
+
+  // Verify that there's no cycle in follow-on chain.
+  std::set<const DefinedAtom *> roots;
+  for (const auto &ai : _followOnRoots)
+    roots.insert(ai.second);
+  for (const DefinedAtom *root : roots)
+    checkNoCycleInFollowonChain(_registry, _followOnNexts, root);
+
+  // Verify that all the atoms in followOnNexts have references to
+  // their roots.
+  for (const auto &ai : _followOnNexts) {
+    checkReachabilityFromRoot(_followOnRoots, ai.first);
+    checkReachabilityFromRoot(_followOnRoots, ai.second);
+  }
+}
+#endif // #ifndef NDEBUG
+
+/// The function compares atoms by sorting atoms in the following order
+/// a) Sorts atoms by their ordinal overrides (layout-after/ingroup)
+/// b) Sorts atoms by their permissions
+/// c) Sorts atoms by their content
+/// d) Sorts atoms by custom sorter
+/// e) Sorts atoms on how they appear using File Ordinality
+/// f) Sorts atoms on how they appear within the File
+static bool compareAtomsSub(const LayoutPass::SortKey &lc,
+                            const LayoutPass::SortKey &rc,
+                            LayoutPass::SortOverride customSorter,
+                            std::string &reason) {
+  const DefinedAtom *left = lc._atom.get();
+  const DefinedAtom *right = rc._atom.get();
+  if (left == right) {
+    reason = "same";
+    return false;
+  }
+
+  // Find the root of the chain if it is a part of a follow-on chain.
+  const DefinedAtom *leftRoot = lc._root;
+  const DefinedAtom *rightRoot = rc._root;
+
+  // Sort atoms by their ordinal overrides only if they fall in the same
+  // chain.
+  if (leftRoot == rightRoot) {
+    DEBUG(reason = formatReason("override", lc._override, rc._override));
+    return lc._override < rc._override;
+  }
+
+  // Sort same permissions together.
+  DefinedAtom::ContentPermissions leftPerms = leftRoot->permissions();
+  DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
+
+  if (leftPerms != rightPerms) {
+    DEBUG(reason =
+              formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+    return leftPerms < rightPerms;
+  }
+
+  // Sort same content types together.
+  DefinedAtom::ContentType leftType = leftRoot->contentType();
+  DefinedAtom::ContentType rightType = rightRoot->contentType();
+
+  if (leftType != rightType) {
+    DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
+    return leftType < rightType;
+  }
+
+  // Use custom sorter if supplied.
+  if (customSorter) {
+    bool leftBeforeRight;
+    if (customSorter(leftRoot, rightRoot, leftBeforeRight))
+      return leftBeforeRight;
+  }
+
+  // Sort by .o order.
+  const File *leftFile = &leftRoot->file();
+  const File *rightFile = &rightRoot->file();
+
+  if (leftFile != rightFile) {
+    DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+                                (int)rightFile->ordinal()));
+    return leftFile->ordinal() < rightFile->ordinal();
+  }
+
+  // Sort by atom order with .o file.
+  uint64_t leftOrdinal = leftRoot->ordinal();
+  uint64_t rightOrdinal = rightRoot->ordinal();
+
+  if (leftOrdinal != rightOrdinal) {
+    DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+                                (int)rightRoot->ordinal()));
+    return leftOrdinal < rightOrdinal;
+  }
+
+  llvm::errs() << "Unordered: <" << left->name() << "> <"
+               << right->name() << ">\n";
+  llvm_unreachable("Atoms with Same Ordinal!");
+}
+
+static bool compareAtoms(const LayoutPass::SortKey &lc,
+                         const LayoutPass::SortKey &rc,
+                         LayoutPass::SortOverride customSorter) {
+  std::string reason;
+  bool result = compareAtomsSub(lc, rc, customSorter, reason);
+  DEBUG({
+    StringRef comp = result ? "<" : ">=";
+    llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
+                 << "' " << comp << " '"
+                 << rc._atom.get()->name() << "' (" << reason << ")\n";
+  });
+  return result;
+}
+
+LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
+    : _registry(registry), _customSorter(std::move(sorter)) {}
+
+// Returns the atom immediately followed by the given atom in the followon
+// chain.
+const DefinedAtom *LayoutPass::findAtomFollowedBy(
+    const DefinedAtom *targetAtom) {
+  // Start from the beginning of the chain and follow the chain until
+  // we find the targetChain.
+  const DefinedAtom *atom = _followOnRoots[targetAtom];
+  while (true) {
+    const DefinedAtom *prevAtom = atom;
+    AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+    // The target atom must be in the chain of its root.
+    assert(targetFollowOnAtomsIter != _followOnNexts.end());
+    atom = targetFollowOnAtomsIter->second;
+    if (atom == targetAtom)
+      return prevAtom;
+  }
+}
+
+// Check if all the atoms followed by the given target atom are of size zero.
+// When this method is called, an atom being added is not of size zero and
+// will be added to the head of the followon chain. All the atoms between the
+// atom and the targetAtom (specified by layout-after) need to be of size zero
+// in this case. Otherwise the desired layout is impossible.
+bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
+  const DefinedAtom *atom = _followOnRoots[targetAtom];
+  while (true) {
+    if (atom == targetAtom)
+      return true;
+    if (atom->size() != 0)
+      // TODO: print warning that an impossible layout is being desired by the
+      // user.
+      return false;
+    AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+    // The target atom must be in the chain of its root.
+    assert(targetFollowOnAtomsIter != _followOnNexts.end());
+    atom = targetFollowOnAtomsIter->second;
+  }
+}
+
+// Set the root of all atoms in targetAtom's chain to the given root.
+void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
+                              const DefinedAtom *root) {
+  // Walk through the followon chain and override each node's root.
+  while (true) {
+    _followOnRoots[targetAtom] = root;
+    AtomToAtomT::iterator targetFollowOnAtomsIter =
+        _followOnNexts.find(targetAtom);
+    if (targetFollowOnAtomsIter == _followOnNexts.end())
+      return;
+    targetAtom = targetFollowOnAtomsIter->second;
+  }
+}
+
+/// This pass builds the followon tables described by two DenseMaps
+/// followOnRoots and followonNexts.
+/// The followOnRoots map contains a mapping of a DefinedAtom to its root
+/// The followOnNexts map contains a mapping of what DefinedAtom follows the
+/// current Atom
+/// The algorithm follows a very simple approach
+/// a) If the atom is first seen, then make that as the root atom
+/// b) The targetAtom which this Atom contains, has the root thats set to the
+///    root of the current atom
+/// c) If the targetAtom is part of a different tree and the root of the
+///    targetAtom is itself, Chain all the atoms that are contained in the tree
+///    to the current Tree
+/// d) If the targetAtom is part of a different chain and the root of the
+///    targetAtom until the targetAtom has all atoms of size 0, then chain the
+///    targetAtoms and its tree to the current chain
+void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
+  // Set the initial size of the followon and the followonNext hash to the
+  // number of atoms that we have.
+  _followOnRoots.reserve(range.size());
+  _followOnNexts.reserve(range.size());
+  for (const DefinedAtom *ai : range) {
+    for (const Reference *r : *ai) {
+      if (r->kindNamespace() != lld::Reference::KindNamespace::all ||
+          r->kindValue() != lld::Reference::kindLayoutAfter)
+        continue;
+      const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
+      _followOnNexts[ai] = targetAtom;
+
+      // If we find a followon for the first time, let's make that atom as the
+      // root atom.
+      if (_followOnRoots.count(ai) == 0)
+        _followOnRoots[ai] = ai;
+
+      auto iter = _followOnRoots.find(targetAtom);
+      if (iter == _followOnRoots.end()) {
+        // If the targetAtom is not a root of any chain, let's make the root of
+        // the targetAtom to the root of the current chain.
+
+        // The expression m[i] = m[j] where m is a DenseMap and i != j is not
+        // safe. m[j] returns a reference, which would be invalidated when a
+        // rehashing occurs. If rehashing occurs to make room for m[i], m[j]
+        // becomes invalid, and that invalid reference would be used as the RHS
+        // value of the expression.
+        // Copy the value to workaround.
+        const DefinedAtom *tmp = _followOnRoots[ai];
+        _followOnRoots[targetAtom] = tmp;
+        continue;
+      }
+      if (iter->second == targetAtom) {
+        // If the targetAtom is the root of a chain, the chain becomes part of
+        // the current chain. Rewrite the subchain's root to the current
+        // chain's root.
+        setChainRoot(targetAtom, _followOnRoots[ai]);
+        continue;
+      }
+      // The targetAtom is already a part of a chain. If the current atom is
+      // of size zero, we can insert it in the middle of the chain just
+      // before the target atom, while not breaking other atom's followon
+      // relationships. If it's not, we can only insert the current atom at
+      // the beginning of the chain. All the atoms followed by the target
+      // atom must be of size zero in that case to satisfy the followon
+      // relationships.
+      size_t currentAtomSize = ai->size();
+      if (currentAtomSize == 0) {
+        const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
+        _followOnNexts[targetPrevAtom] = ai;
+        const DefinedAtom *tmp = _followOnRoots[targetPrevAtom];
+        _followOnRoots[ai] = tmp;
+        continue;
+      }
+      if (!checkAllPrevAtomsZeroSize(targetAtom))
+        break;
+      _followOnNexts[ai] = _followOnRoots[targetAtom];
+      setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
+    }
+  }
+}
+
+/// Build an ordinal override map by traversing the followon chain, and
+/// assigning ordinals to each atom, if the atoms have their ordinals
+/// already assigned skip the atom and move to the next. This is the
+/// main map thats used to sort the atoms while comparing two atoms together
+void
+LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
+  uint64_t index = 0;
+  for (const DefinedAtom *ai : range) {
+    const DefinedAtom *atom = ai;
+    if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
+      continue;
+    AtomToAtomT::iterator start = _followOnRoots.find(atom);
+    if (start == _followOnRoots.end())
+      continue;
+    for (const DefinedAtom *nextAtom = start->second; nextAtom;
+         nextAtom = _followOnNexts[nextAtom]) {
+      AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
+      if (pos == _ordinalOverrideMap.end())
+        _ordinalOverrideMap[nextAtom] = index++;
+    }
+  }
+}
+
+std::vector<LayoutPass::SortKey>
+LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const {
+  std::vector<SortKey> ret;
+  for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) {
+    auto ri = _followOnRoots.find(atom.get());
+    auto oi = _ordinalOverrideMap.find(atom.get());
+    const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second;
+    uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
+    ret.push_back(SortKey(std::move(atom), root, override));
+  }
+  return ret;
+}
+
+void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
+                            std::vector<SortKey> &keys) const {
+  size_t i = 0;
+  for (SortKey &k : keys)
+    atomRange[i++] = std::move(k._atom);
+}
+
+/// Perform the actual pass
+llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
+  DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+  // sort the atoms
+  ScopedTask task(getDefaultDomain(), "LayoutPass");
+  File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
+
+  // Build follow on tables
+  buildFollowOnTable(atomRange);
+
+  // Check the structure of followon graph if running in debug mode.
+  DEBUG(checkFollowonChain(atomRange));
+
+  // Build override maps
+  buildOrdinalOverrideMap(atomRange);
+
+  DEBUG({
+    llvm::dbgs() << "unsorted atoms:\n";
+    printDefinedAtoms(atomRange);
+  });
+
+  std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
+  parallel_sort(vec.begin(), vec.end(),
+      [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+        return compareAtoms(l, r, _customSorter);
+      });
+  DEBUG(checkTransitivity(vec, _customSorter));
+  undecorate(atomRange, vec);
+
+  DEBUG({
+    llvm::dbgs() << "sorted atoms:\n";
+    printDefinedAtoms(atomRange);
+  });
+
+  DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+  return llvm::Error();
+}
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<LayoutPass>(
+      ctx.registry(), [&](const DefinedAtom * left, const DefinedAtom * right,
+                          bool & leftBeforeRight) ->bool {
+    return ctx.customAtomOrderer(left, right, leftBeforeRight);
+  }));
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
new file mode 100644 (file)
index 0000000..c18777e
--- /dev/null
@@ -0,0 +1,119 @@
+//===------ lib/ReaderWriter/MachO/LayoutPass.h - Handles Layout of atoms -===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+#define LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class SimpleFile;
+
+namespace mach_o {
+
+/// This linker pass does the layout of the atoms. The pass is done after the
+/// order their .o files were found on the command line, then by order of the
+/// atoms (address) in the .o file.  But some atoms have a preferred location
+/// in their section (such as pinned to the start or end of the section), so
+/// the sort must take that into account too.
+class LayoutPass : public Pass {
+public:
+  struct SortKey {
+    SortKey(OwningAtomPtr<DefinedAtom> &&atom,
+            const DefinedAtom *root, uint64_t override)
+    : _atom(std::move(atom)), _root(root), _override(override) {}
+    OwningAtomPtr<DefinedAtom> _atom;
+    const DefinedAtom *_root;
+    uint64_t _override;
+
+    // Note, these are only here to appease MSVC bots which didn't like
+    // the same methods being implemented/deleted in OwningAtomPtr.
+    SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root),
+                             _override(key._override) {
+      key._root = nullptr;
+    }
+
+    SortKey &operator=(SortKey &&key) {
+      _atom = std::move(key._atom);
+      _root = key._root;
+      key._root = nullptr;
+      _override = key._override;
+      return *this;
+    }
+
+  private:
+    SortKey(const SortKey &) = delete;
+    void operator=(const SortKey&) = delete;
+  };
+
+  typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
+                              bool &leftBeforeRight)> SortOverride;
+
+  LayoutPass(const Registry &registry, SortOverride sorter);
+
+  /// Sorts atoms in mergedFile by content type then by command line order.
+  llvm::Error perform(SimpleFile &mergedFile) override;
+
+  ~LayoutPass() override = default;
+
+private:
+  // Build the followOn atoms chain as specified by the kindLayoutAfter
+  // reference type
+  void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range);
+
+  // Build a map of Atoms to ordinals for sorting the atoms
+  void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range);
+
+  const Registry &_registry;
+  SortOverride _customSorter;
+
+  typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+  typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
+
+  // A map to be used to sort atoms. It represents the order of atoms in the
+  // result; if Atom X is mapped to atom Y in this map, X will be located
+  // immediately before Y in the output file. Y might be mapped to another
+  // atom, constructing a follow-on chain. An atom cannot be mapped to more
+  // than one atom unless all but one atom are of size zero.
+  AtomToAtomT _followOnNexts;
+
+  // A map to be used to sort atoms. It's a map from an atom to its root of
+  // follow-on chain. A root atom is mapped to itself. If an atom is not in
+  // _followOnNexts, the atom is not in this map, and vice versa.
+  AtomToAtomT _followOnRoots;
+
+  AtomToOrdinalT _ordinalOverrideMap;
+
+  // Helper methods for buildFollowOnTable().
+  const DefinedAtom *findAtomFollowedBy(const DefinedAtom *targetAtom);
+  bool checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom);
+
+  void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
+
+  std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const;
+
+  void undecorate(File::AtomRange<DefinedAtom> &atomRange,
+                  std::vector<SortKey> &keys) const;
+
+  // Check if the follow-on graph is a correct structure. For debugging only.
+  void checkFollowonChain(const File::AtomRange<DefinedAtom> &range);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
new file mode 100644 (file)
index 0000000..05375f1
--- /dev/null
@@ -0,0 +1,1117 @@
+//===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "ArchHandler.h"
+#include "File.h"
+#include "FlatNamespaceFile.h"
+#include "MachONormalizedFile.h"
+#include "MachOPasses.h"
+#include "SectCreateFile.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+#if defined(HAVE_CXXABI_H)
+#include <cxxabi.h>
+#endif
+
+using lld::mach_o::ArchHandler;
+using lld::mach_o::MachOFile;
+using lld::mach_o::MachODylibFile;
+using namespace llvm::MachO;
+
+namespace lld {
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
+  result = 0;
+
+  if (str.empty())
+    return false;
+
+  SmallVector<StringRef, 3> parts;
+  llvm::SplitString(str, parts, ".");
+
+  unsigned long long num;
+  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+    return true;
+  if (num > 65535)
+    return true;
+  result = num << 16;
+
+  if (parts.size() > 1) {
+    if (llvm::getAsUnsignedInteger(parts[1], 10, num))
+      return true;
+    if (num > 255)
+      return true;
+    result |= (num << 8);
+  }
+
+  if (parts.size() > 2) {
+    if (llvm::getAsUnsignedInteger(parts[2], 10, num))
+      return true;
+    if (num > 255)
+      return true;
+    result |= num;
+  }
+
+  return false;
+}
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+  result = 0;
+
+  if (str.empty())
+    return false;
+
+  SmallVector<StringRef, 5> parts;
+  llvm::SplitString(str, parts, ".");
+
+  unsigned long long num;
+  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+    return true;
+  if (num > 0xFFFFFF)
+    return true;
+  result = num << 40;
+
+  unsigned Shift = 30;
+  for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+    if (llvm::getAsUnsignedInteger(str, 10, num))
+      return true;
+    if (num > 0x3FF)
+      return true;
+    result |= (num << Shift);
+    Shift -= 10;
+  }
+
+  return false;
+}
+
+MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
+  { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },
+  { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },
+  { "ppc",    arch_ppc,    false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
+  { "armv6",  arch_armv6,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6 },
+  { "armv7",  arch_armv7,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7 },
+  { "armv7s", arch_armv7s, true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7S },
+  { "arm64",  arch_arm64,  true,  CPU_TYPE_ARM64,   CPU_SUBTYPE_ARM64_ALL },
+  { "",       arch_unknown,false, 0,                0 }
+};
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
+      return info->arch;
+  }
+  return arch_unknown;
+}
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromName(StringRef archName) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->archName.equals(archName))
+      return info->arch;
+  }
+  return arch_unknown;
+}
+
+StringRef MachOLinkingContext::nameFromArch(Arch arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->archName;
+  }
+  return "<unknown>";
+}
+
+uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->cputype;
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->cpusubtype;
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
+  return mach_o::normalized::isThinObjectFile(path, arch);
+}
+
+bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
+                                           uint32_t &size) {
+  return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
+}
+
+MachOLinkingContext::MachOLinkingContext() {}
+
+MachOLinkingContext::~MachOLinkingContext() {
+  // Atoms are allocated on BumpPtrAllocator's on File's.
+  // As we transfer atoms from one file to another, we need to clear all of the
+  // atoms before we remove any of the BumpPtrAllocator's.
+  auto &nodes = getNodes();
+  for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
+    FileNode *node = dyn_cast<FileNode>(nodes[i].get());
+    if (!node)
+      continue;
+    File *file = node->getFile();
+    file->clearAtoms();
+  }
+}
+
+void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
+                                    uint32_t minOSVersion,
+                                    bool exportDynamicSymbols) {
+  _outputMachOType = type;
+  _arch = arch;
+  _os = os;
+  _osMinVersion = minOSVersion;
+
+  // If min OS not specified on command line, use reasonable defaults.
+  // Note that we only do sensible defaults when emitting something other than
+  // object and preload.
+  if (_outputMachOType != llvm::MachO::MH_OBJECT &&
+      _outputMachOType != llvm::MachO::MH_PRELOAD) {
+    if (minOSVersion == 0) {
+      switch (_arch) {
+      case arch_x86_64:
+      case arch_x86:
+        parsePackedVersion("10.8", _osMinVersion);
+        _os = MachOLinkingContext::OS::macOSX;
+        break;
+      case arch_armv6:
+      case arch_armv7:
+      case arch_armv7s:
+      case arch_arm64:
+        parsePackedVersion("7.0", _osMinVersion);
+        _os = MachOLinkingContext::OS::iOS;
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  switch (_outputMachOType) {
+  case llvm::MachO::MH_EXECUTE:
+    // If targeting newer OS, use _main
+    if (minOS("10.8", "6.0")) {
+      _entrySymbolName = "_main";
+    } else {
+      // If targeting older OS, use start (in crt1.o)
+      _entrySymbolName = "start";
+    }
+
+    // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not
+    // support) and 4KB on 32-bit.
+    if (is64Bit(_arch)) {
+      _pageZeroSize = 0x100000000;
+    } else {
+      _pageZeroSize = 0x1000;
+    }
+
+    // Initial base address is __PAGEZERO size.
+    _baseAddress = _pageZeroSize;
+
+    // Make PIE by default when targetting newer OSs.
+    switch (os) {
+      case OS::macOSX:
+        if (minOSVersion >= 0x000A0700) // MacOSX 10.7
+          _pie = true;
+        break;
+      case OS::iOS:
+        if (minOSVersion >= 0x00040300) // iOS 4.3
+          _pie = true;
+       break;
+       case OS::iOS_simulator:
+        _pie = true;
+       break;
+       case OS::unknown:
+       break;
+    }
+    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+    break;
+  case llvm::MachO::MH_DYLIB:
+    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+    break;
+  case llvm::MachO::MH_BUNDLE:
+    break;
+  case llvm::MachO::MH_OBJECT:
+    _printRemainingUndefines = false;
+    _allowRemainingUndefines = true;
+  default:
+    break;
+  }
+
+  // Set default segment page sizes based on arch.
+  if (arch == arch_arm64)
+    _pageSize = 4*4096;
+}
+
+uint32_t MachOLinkingContext::getCPUType() const {
+  return cpuTypeFromArch(_arch);
+}
+
+uint32_t MachOLinkingContext::getCPUSubType() const {
+  return cpuSubtypeFromArch(_arch);
+}
+
+bool MachOLinkingContext::is64Bit(Arch arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->cputype & CPU_ARCH_ABI64);
+    }
+  }
+  // unknown archs are not 64-bit.
+  return false;
+}
+
+bool MachOLinkingContext::isHostEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->littleEndian == llvm::sys::IsLittleEndianHost);
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isBigEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return ! info->littleEndian;
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::is64Bit() const {
+  return is64Bit(_arch);
+}
+
+bool MachOLinkingContext::outputTypeHasEntry() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+  case MH_DYLINKER:
+  case MH_PRELOAD:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsStubsPass() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+    return !_outputMachOTypeStatic;
+  case MH_DYLIB:
+  case MH_BUNDLE:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsGOTPass() const {
+  // GOT pass not used in -r mode.
+  if (_outputMachOType == MH_OBJECT)
+    return false;
+  // Only some arches use GOT pass.
+  switch (_arch) {
+    case arch_x86_64:
+    case arch_arm64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool MachOLinkingContext::needsCompactUnwindPass() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+  case MH_DYLIB:
+  case MH_BUNDLE:
+    return archHandler().needsCompactUnwind();
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsObjCPass() const {
+  // ObjC pass is only needed if any of the inputs were ObjC.
+  return _objcConstraint != objc_unknown;
+}
+
+bool MachOLinkingContext::needsShimPass() const {
+  // Shim pass only used in final executables.
+  if (_outputMachOType == MH_OBJECT)
+    return false;
+  // Only 32-bit arm arches use Shim pass.
+  switch (_arch) {
+  case arch_armv6:
+  case arch_armv7:
+  case arch_armv7s:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsTLVPass() const {
+  switch (_outputMachOType) {
+  case MH_BUNDLE:
+  case MH_EXECUTE:
+  case MH_DYLIB:
+    return true;
+  default:
+    return false;
+  }
+}
+
+StringRef MachOLinkingContext::binderSymbolName() const {
+  return archHandler().stubInfo().binderSymbolName;
+}
+
+bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
+  uint32_t parsedVersion;
+  switch (_os) {
+  case OS::macOSX:
+    if (parsePackedVersion(mac, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  case OS::iOS:
+  case OS::iOS_simulator:
+    if (parsePackedVersion(iOS, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  case OS::unknown:
+    // If we don't know the target, then assume that we don't meet the min OS.
+    // This matches the ld64 behaviour
+    return false;
+  }
+  llvm_unreachable("invalid OS enum");
+}
+
+bool MachOLinkingContext::addEntryPointLoadCommand() const {
+  if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) {
+    return minOS("10.8", "6.0");
+  }
+  return false;
+}
+
+bool MachOLinkingContext::addUnixThreadLoadCommand() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+    if (_outputMachOTypeStatic)
+      return true;
+    else
+      return !minOS("10.8", "6.0");
+    break;
+  case MH_DYLINKER:
+  case MH_PRELOAD:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::pathExists(StringRef path) const {
+  if (!_testingFileUsage)
+    return llvm::sys::fs::exists(path.str());
+
+  // Otherwise, we're in test mode: only files explicitly provided on the
+  // command-line exist.
+  std::string key = path.str();
+  std::replace(key.begin(), key.end(), '\\', '/');
+  return _existingPaths.find(key) != _existingPaths.end();
+}
+
+bool MachOLinkingContext::fileExists(StringRef path) const {
+  bool found = pathExists(path);
+  // Log search misses.
+  if (!found)
+    addInputFileNotFound(path);
+
+  // When testing, file is never opened, so logging is done here.
+  if (_testingFileUsage && found)
+    addInputFileDependency(path);
+
+  return found;
+}
+
+void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {
+  _syslibRoots = paths;
+}
+
+void MachOLinkingContext::addRpath(StringRef rpath) {
+  _rpaths.push_back(rpath);
+}
+
+void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
+                                               bool isSystemPath) {
+  bool addedModifiedPath = false;
+
+  // -syslibroot only applies to absolute paths.
+  if (libPath.startswith("/")) {
+    for (auto syslibRoot : _syslibRoots) {
+      SmallString<256> path(syslibRoot);
+      llvm::sys::path::append(path, libPath);
+      if (pathExists(path)) {
+        _searchDirs.push_back(path.str().copy(_allocator));
+        addedModifiedPath = true;
+      }
+    }
+  }
+
+  if (addedModifiedPath)
+    return;
+
+  // Finally, if only one -syslibroot is given, system paths which aren't in it
+  // get suppressed.
+  if (_syslibRoots.size() != 1 || !isSystemPath) {
+    if (pathExists(libPath)) {
+      _searchDirs.push_back(libPath);
+    }
+  }
+}
+
+void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
+                                                bool isSystemPath) {
+  bool pathAdded = false;
+
+  // -syslibroot only used with to absolute framework search paths.
+  if (fwPath.startswith("/")) {
+    for (auto syslibRoot : _syslibRoots) {
+      SmallString<256> path(syslibRoot);
+      llvm::sys::path::append(path, fwPath);
+      if (pathExists(path)) {
+        _frameworkDirs.push_back(path.str().copy(_allocator));
+        pathAdded = true;
+      }
+    }
+  }
+  // If fwPath found in any -syslibroot, then done.
+  if (pathAdded)
+    return;
+
+  // If only one -syslibroot, system paths not in that SDK are suppressed.
+  if (isSystemPath && (_syslibRoots.size() == 1))
+    return;
+
+  // Only use raw fwPath if that directory exists.
+  if (pathExists(fwPath))
+    _frameworkDirs.push_back(fwPath);
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchDirForLibrary(StringRef path,
+                                         StringRef libName) const {
+  SmallString<256> fullPath;
+  if (libName.endswith(".o")) {
+    // A request ending in .o is special: just search for the file directly.
+    fullPath.assign(path);
+    llvm::sys::path::append(fullPath, libName);
+    if (fileExists(fullPath))
+      return fullPath.str().copy(_allocator);
+    return llvm::None;
+  }
+
+  // Search for dynamic library
+  fullPath.assign(path);
+  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");
+  if (fileExists(fullPath))
+    return fullPath.str().copy(_allocator);
+
+  // If not, try for a static library
+  fullPath.assign(path);
+  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
+  if (fileExists(fullPath))
+    return fullPath.str().copy(_allocator);
+
+  return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchLibrary(StringRef libName) const {
+  SmallString<256> path;
+  for (StringRef dir : searchDirs()) {
+    llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
+    if (searchDir)
+      return searchDir;
+  }
+
+  return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+  SmallString<256> fullPath;
+  for (StringRef dir : frameworkDirs()) {
+    fullPath.assign(dir);
+    llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
+    if (fileExists(fullPath))
+      return fullPath.str().copy(_allocator);
+  }
+
+  return llvm::None;
+}
+
+bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
+  // TODO: if -arch not specified, look at arch of first .o file.
+
+  if (_currentVersion && _outputMachOType != MH_DYLIB) {
+    diagnostics << "error: -current_version can only be used with dylibs\n";
+    return false;
+  }
+
+  if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
+    diagnostics
+        << "error: -compatibility_version can only be used with dylibs\n";
+    return false;
+  }
+
+  if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
+    diagnostics
+        << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
+    return false;
+  }
+
+  if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
+    diagnostics
+        << "error: -bundle_loader can only be used with Mach-O bundles\n";
+    return false;
+  }
+
+  // If -exported_symbols_list used, all exported symbols must be defined.
+  if (_exportMode == ExportMode::whiteList) {
+    for (const auto &symbol : _exportedSymbols)
+      addInitialUndefinedSymbol(symbol.getKey());
+  }
+
+  // If -dead_strip, set up initial live symbols.
+  if (deadStrip()) {
+    // Entry point is live.
+    if (outputTypeHasEntry())
+      addDeadStripRoot(entrySymbolName());
+    // Lazy binding helper is live.
+    if (needsStubsPass())
+      addDeadStripRoot(binderSymbolName());
+    // If using -exported_symbols_list, make all exported symbols live.
+    if (_exportMode == ExportMode::whiteList) {
+      setGlobalsAreDeadStripRoots(false);
+      for (const auto &symbol : _exportedSymbols)
+        addDeadStripRoot(symbol.getKey());
+    }
+  }
+
+  addOutputFileDependency(outputPath());
+
+  return true;
+}
+
+void MachOLinkingContext::addPasses(PassManager &pm) {
+  // objc pass should be before layout pass.  Otherwise test cases may contain
+  // no atoms which confuses the layout pass.
+  if (needsObjCPass())
+    mach_o::addObjCPass(pm, *this);
+  mach_o::addLayoutPass(pm, *this);
+  if (needsStubsPass())
+    mach_o::addStubsPass(pm, *this);
+  if (needsCompactUnwindPass())
+    mach_o::addCompactUnwindPass(pm, *this);
+  if (needsGOTPass())
+    mach_o::addGOTPass(pm, *this);
+  if (needsTLVPass())
+    mach_o::addTLVPass(pm, *this);
+  if (needsShimPass())
+    mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
+}
+
+Writer &MachOLinkingContext::writer() const {
+  if (!_writer)
+    _writer = createWriterMachO(*this);
+  return *_writer;
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MachOLinkingContext::getMemoryBuffer(StringRef path) {
+  addInputFileDependency(path);
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
+    MemoryBuffer::getFileOrSTDIN(path);
+  if (std::error_code ec = mbOrErr.getError())
+    return ec;
+  std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
+
+  // If buffer contains a fat file, find required arch in fat buffer
+  // and switch buffer to point to just that required slice.
+  uint32_t offset;
+  uint32_t size;
+  if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))
+    return MemoryBuffer::getFileSlice(path, size, offset);
+  return std::move(mb);
+}
+
+MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = getMemoryBuffer(path);
+  if (mbOrErr.getError())
+    return nullptr;
+
+  ErrorOr<std::unique_ptr<File>> fileOrErr =
+      registry().loadFile(std::move(mbOrErr.get()));
+  if (!fileOrErr)
+    return nullptr;
+  std::unique_ptr<File> &file = fileOrErr.get();
+  file->parse();
+  MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());
+  // Node object now owned by _indirectDylibs vector.
+  _indirectDylibs.push_back(std::move(file));
+  return result;
+}
+
+MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
+  // See if already loaded.
+  auto pos = _pathToDylibMap.find(path);
+  if (pos != _pathToDylibMap.end())
+    return pos->second;
+
+  // Search -L paths if of the form "libXXX.dylib"
+  std::pair<StringRef, StringRef> split = path.rsplit('/');
+  StringRef leafName = split.second;
+  if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
+    // FIXME: Need to enhance searchLibrary() to only look for .dylib
+    auto libPath = searchLibrary(leafName);
+    if (libPath)
+      return loadIndirectDylib(libPath.getValue());
+  }
+
+  // Try full path with sysroot.
+  for (StringRef sysPath : _syslibRoots) {
+    SmallString<256> fullPath;
+    fullPath.assign(sysPath);
+    llvm::sys::path::append(fullPath, path);
+    if (pathExists(fullPath))
+      return loadIndirectDylib(fullPath);
+  }
+
+  // Try full path.
+  if (pathExists(path)) {
+    return loadIndirectDylib(path);
+  }
+
+  return nullptr;
+}
+
+uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->currentVersion();
+  else
+    return 0x1000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->compatVersion();
+  else
+    return 0x1000; // 1.0
+}
+
+void MachOLinkingContext::createImplicitFiles(
+                            std::vector<std::unique_ptr<File> > &result) {
+  // Add indirect dylibs by asking each linked dylib to add its indirects.
+  // Iterate until no more dylibs get loaded.
+  size_t dylibCount = 0;
+  while (dylibCount != _allDylibs.size()) {
+    dylibCount = _allDylibs.size();
+    for (MachODylibFile *dylib : _allDylibs) {
+      dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {
+                                  return findIndirectDylib(path); });
+    }
+  }
+
+  // Let writer add output type specific extras.
+  writer().createImplicitFiles(result);
+
+  // If undefinedMode is != error, add a FlatNamespaceFile instance. This will
+  // provide a SharedLibraryAtom for symbols that aren't defined elsewhere.
+  if (undefinedMode() != UndefinedMode::error) {
+    result.emplace_back(new mach_o::FlatNamespaceFile(*this));
+    _flatNamespaceFile = result.back().get();
+  }
+}
+
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
+                                        bool upward) const {
+  std::lock_guard<std::mutex> lock(_dylibsMutex);
+  _allDylibs.insert(dylib);
+  _pathToDylibMap[dylib->installName()] = dylib;
+  // If path is different than install name, register path too.
+  if (!dylib->path().equals(dylib->installName()))
+    _pathToDylibMap[dylib->path()] = dylib;
+  if (upward)
+    _upwardDylibs.insert(dylib);
+}
+
+bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
+  for (MachODylibFile *dylib : _upwardDylibs) {
+    if (dylib->installName().equals(installName))
+      return true;
+  }
+  return false;
+}
+
+ArchHandler &MachOLinkingContext::archHandler() const {
+  if (!_archHandler)
+    _archHandler = ArchHandler::create(_arch);
+  return *_archHandler;
+}
+
+void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
+                                              uint16_t align) {
+  SectionAlign entry = { seg, sect, align };
+  _sectAligns.push_back(entry);
+}
+
+void MachOLinkingContext::addSectCreateSection(
+                                        StringRef seg, StringRef sect,
+                                        std::unique_ptr<MemoryBuffer> content) {
+
+  if (!_sectCreateFile) {
+    auto sectCreateFile = llvm::make_unique<mach_o::SectCreateFile>();
+    _sectCreateFile = sectCreateFile.get();
+    getNodes().push_back(llvm::make_unique<FileNode>(std::move(sectCreateFile)));
+  }
+
+  assert(_sectCreateFile && "sectcreate file does not exist.");
+  _sectCreateFile->addSection(seg, sect, std::move(content));
+}
+
+bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
+                                         uint16_t &align) const {
+  for (const SectionAlign &entry : _sectAligns) {
+    if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
+      align = entry.align;
+      return true;
+    }
+  }
+  return false;
+}
+
+void MachOLinkingContext::addExportSymbol(StringRef sym) {
+  // Support old crufty export lists with bogus entries.
+  if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
+    llvm::errs() << "warning: ignoring " << sym << " in export list\n";
+    return;
+  }
+  // Only i386 MacOSX uses old ABI, so don't change those.
+  if ((_os != OS::macOSX) || (_arch != arch_x86)) {
+    // ObjC has two differnent ABIs.  Be nice and allow one export list work for
+    // both ABIs by renaming symbols.
+    if (sym.startswith(".objc_class_name_")) {
+      std::string abi2className("_OBJC_CLASS_$_");
+      abi2className += sym.substr(17);
+      _exportedSymbols.insert(copy(abi2className));
+      std::string abi2metaclassName("_OBJC_METACLASS_$_");
+      abi2metaclassName += sym.substr(17);
+      _exportedSymbols.insert(copy(abi2metaclassName));
+      return;
+    }
+  }
+
+  // FIXME: Support wildcards.
+  _exportedSymbols.insert(sym);
+}
+
+bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {
+  switch (_exportMode) {
+  case ExportMode::globals:
+    llvm_unreachable("exportSymbolNamed() should not be called in this mode");
+    break;
+  case ExportMode::whiteList:
+    return _exportedSymbols.count(sym);
+  case ExportMode::blackList:
+    return !_exportedSymbols.count(sym);
+  }
+  llvm_unreachable("_exportMode unknown enum value");
+}
+
+std::string MachOLinkingContext::demangle(StringRef symbolName) const {
+  // Only try to demangle symbols if -demangle on command line
+  if (!demangleSymbols())
+    return symbolName;
+
+  // Only try to demangle symbols that look like C++ symbols
+  if (!symbolName.startswith("__Z"))
+    return symbolName;
+
+#if defined(HAVE_CXXABI_H)
+  SmallString<256> symBuff;
+  StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+  // Mach-O has extra leading underscore that needs to be removed.
+  const char *cstr = nullTermSym.data() + 1;
+  int status;
+  char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
+  if (demangled) {
+    std::string result(demangled);
+    // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+    free(demangled);
+    return result;
+  }
+#endif
+
+  return symbolName;
+}
+
+std::error_code MachOLinkingContext::createDependencyFile(StringRef path) {
+  std::error_code ec;
+  _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(new
+                         llvm::raw_fd_ostream(path, ec, llvm::sys::fs::F_None));
+  if (ec) {
+    _dependencyInfo.reset();
+    return ec;
+  }
+
+  char linkerVersionOpcode = 0x00;
+  *_dependencyInfo << linkerVersionOpcode;
+  *_dependencyInfo << "lld";     // FIXME
+  *_dependencyInfo << '\0';
+
+  return std::error_code();
+}
+
+void MachOLinkingContext::addInputFileDependency(StringRef path) const {
+  if (!_dependencyInfo)
+    return;
+
+  char inputFileOpcode = 0x10;
+  *_dependencyInfo << inputFileOpcode;
+  *_dependencyInfo << path;
+  *_dependencyInfo << '\0';
+}
+
+void MachOLinkingContext::addInputFileNotFound(StringRef path) const {
+  if (!_dependencyInfo)
+    return;
+
+  char inputFileOpcode = 0x11;
+  *_dependencyInfo << inputFileOpcode;
+  *_dependencyInfo << path;
+  *_dependencyInfo << '\0';
+}
+
+void MachOLinkingContext::addOutputFileDependency(StringRef path) const {
+  if (!_dependencyInfo)
+    return;
+
+  char outputFileOpcode = 0x40;
+  *_dependencyInfo << outputFileOpcode;
+  *_dependencyInfo << path;
+  *_dependencyInfo << '\0';
+}
+
+void MachOLinkingContext::appendOrderedSymbol(StringRef symbol,
+                                              StringRef filename) {
+  // To support sorting static functions which may have the same name in
+  // multiple .o files, _orderFiles maps the symbol name to a vector
+  // of OrderFileNode each of which can specify a file prefix.
+  OrderFileNode info;
+  if (!filename.empty())
+    info.fileFilter = copy(filename);
+  info.order = _orderFileEntries++;
+  _orderFiles[symbol].push_back(info);
+}
+
+bool
+MachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+                                      const DefinedAtom *atom,
+                                      unsigned &ordinal) {
+  const File *objFile = &atom->file();
+  assert(objFile);
+  StringRef objName = objFile->path();
+  std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit('/');
+  if (!dirAndLeaf.second.empty())
+    objName = dirAndLeaf.second;
+  for (const OrderFileNode &info : nodes) {
+    if (info.fileFilter.empty()) {
+      // Have unprefixed symbol name in order file that matches this atom.
+      ordinal = info.order;
+      return true;
+    }
+    if (info.fileFilter.equals(objName)) {
+      // Have prefixed symbol name in order file that matches atom's path.
+      ordinal = info.order;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
+                                            const DefinedAtom *right,
+                                            bool &leftBeforeRight) const {
+  // No custom sorting if no order file entries.
+  if (!_orderFileEntries)
+    return false;
+
+  // Order files can only order named atoms.
+  StringRef leftName = left->name();
+  StringRef rightName = right->name();
+  if (leftName.empty() || rightName.empty())
+    return false;
+
+  // If neither is in order file list, no custom sorter.
+  auto leftPos = _orderFiles.find(leftName);
+  auto rightPos = _orderFiles.find(rightName);
+  bool leftIsOrdered = (leftPos != _orderFiles.end());
+  bool rightIsOrdered = (rightPos != _orderFiles.end());
+  if (!leftIsOrdered && !rightIsOrdered)
+    return false;
+
+  // There could be multiple symbols with same name but different file prefixes.
+  unsigned leftOrder;
+  unsigned rightOrder;
+  bool foundLeft =
+      leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);
+  bool foundRight = rightIsOrdered &&
+                    findOrderOrdinal(rightPos->getValue(), right, rightOrder);
+  if (!foundLeft && !foundRight)
+    return false;
+
+  // If only one is in order file list, ordered one goes first.
+  if (foundLeft != foundRight)
+    leftBeforeRight = foundLeft;
+  else
+    leftBeforeRight = (leftOrder < rightOrder);
+
+  return true;
+}
+
+static bool isLibrary(const std::unique_ptr<Node> &elem) {
+  if (FileNode *node = dyn_cast<FileNode>(const_cast<Node *>(elem.get()))) {
+    File *file = node->getFile();
+    return isa<SharedLibraryFile>(file) || isa<ArchiveLibraryFile>(file);
+  }
+  return false;
+}
+
+// The darwin linker processes input files in two phases.  The first phase
+// links in all object (.o) files in command line order. The second phase
+// links in libraries in command line order.
+// In this function we reorder the input files so that all the object files
+// comes before any library file. We also make a group for the library files
+// so that the Resolver will reiterate over the libraries as long as we find
+// new undefines from libraries.
+void MachOLinkingContext::finalizeInputFiles() {
+  std::vector<std::unique_ptr<Node>> &elements = getNodes();
+  std::stable_sort(elements.begin(), elements.end(),
+                   [](const std::unique_ptr<Node> &a,
+                      const std::unique_ptr<Node> &b) {
+                     return !isLibrary(a) && isLibrary(b);
+                   });
+  size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);
+  elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
+}
+
+llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
+  auto *machoFile = dyn_cast<MachOFile>(&file);
+  if (!machoFile)
+    return llvm::Error();
+
+  // Check that the arch of the context matches that of the file.
+  // Also set the arch of the context if it didn't have one.
+  if (_arch == arch_unknown) {
+    _arch = machoFile->arch();
+  } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
+    // Archs are different.
+    return llvm::make_error<GenericError>(file.path() +
+                  Twine(" cannot be linked due to incompatible architecture"));
+  }
+
+  // Check that the OS of the context matches that of the file.
+  // Also set the OS of the context if it didn't have one.
+  if (_os == OS::unknown) {
+    _os = machoFile->OS();
+  } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
+    // OSes are different.
+    return llvm::make_error<GenericError>(file.path() +
+              Twine(" cannot be linked due to incompatible operating systems"));
+  }
+
+  // Check that if the objc info exists, that it is compatible with the target
+  // OS.
+  switch (machoFile->objcConstraint()) {
+    case objc_unknown:
+      // The file is not compiled with objc, so skip the checks.
+      break;
+    case objc_gc_only:
+    case objc_supports_gc:
+      llvm_unreachable("GC support should already have thrown an error");
+    case objc_retainReleaseForSimulator:
+      // The file is built with simulator objc, so make sure that the context
+      // is also building with simulator support.
+      if (_os != OS::iOS_simulator)
+        return llvm::make_error<GenericError>(file.path() +
+          Twine(" cannot be linked.  It contains ObjC built for the simulator"
+                " while we are linking a non-simulator target"));
+      assert((_objcConstraint == objc_unknown ||
+              _objcConstraint == objc_retainReleaseForSimulator) &&
+             "Must be linking with retain/release for the simulator");
+      _objcConstraint = objc_retainReleaseForSimulator;
+      break;
+    case objc_retainRelease:
+      // The file is built without simulator objc, so make sure that the
+      // context is also building without simulator support.
+      if (_os == OS::iOS_simulator)
+        return llvm::make_error<GenericError>(file.path() +
+          Twine(" cannot be linked.  It contains ObjC built for a non-simulator"
+                " target while we are linking a simulator target"));
+      assert((_objcConstraint == objc_unknown ||
+              _objcConstraint == objc_retainRelease) &&
+             "Must be linking with retain/release for a non-simulator target");
+      _objcConstraint = objc_retainRelease;
+      break;
+  }
+
+  // Check that the swift version of the context matches that of the file.
+  // Also set the swift version of the context if it didn't have one.
+  if (!_swiftVersion) {
+    _swiftVersion = machoFile->swiftVersion();
+  } else if (machoFile->swiftVersion() &&
+             machoFile->swiftVersion() != _swiftVersion) {
+    // Swift versions are different.
+    return llvm::make_error<GenericError>("different swift versions");
+  }
+
+  return llvm::Error();
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
new file mode 100644 (file)
index 0000000..92a21f7
--- /dev/null
@@ -0,0 +1,344 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file These data structures comprise the "normalized" view of
+/// mach-o object files. The normalized view is an in-memory only data structure
+/// which is always in native endianness and pointer size.
+///
+/// The normalized view easily converts to and from YAML using YAML I/O.
+///
+/// The normalized view converts to and from binary mach-o object files using
+/// the writeBinary() and readBinary() functions.
+///
+/// The normalized view converts to and from lld::Atoms using the
+/// normalizedToAtoms() and normalizedFromAtoms().
+///
+/// Overall, the conversion paths available look like:
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        ^
+///                        |
+///                        v
+///                  +------------+         +------+
+///                  | normalized |   <->   | yaml |
+///                  +------------+         +------+
+///                        ^
+///                        |
+///                        v
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+///
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using llvm::BumpPtrAllocator;
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex32;
+using llvm::yaml::Hex16;
+using llvm::yaml::Hex8;
+using llvm::yaml::SequenceTraits;
+using llvm::MachO::HeaderFileType;
+using llvm::MachO::BindType;
+using llvm::MachO::RebaseType;
+using llvm::MachO::NListType;
+using llvm::MachO::RelocationInfoType;
+using llvm::MachO::SectionType;
+using llvm::MachO::LoadCommandType;
+using llvm::MachO::ExportSymbolKind;
+using llvm::MachO::DataRegionType;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+
+/// The real mach-o relocation record is 8-bytes on disk and is
+/// encoded in one of two different bit-field patterns.  This
+/// normalized form has the union of all possible fields.
+struct Relocation {
+  Relocation() : offset(0), scattered(false),
+                 type(llvm::MachO::GENERIC_RELOC_VANILLA),
+                 length(0), pcRel(false), isExtern(false), value(0),
+                 symbol(0) { }
+
+  Hex32               offset;
+  bool                scattered;
+  RelocationInfoType  type;
+  uint8_t             length;
+  bool                pcRel;
+  bool                isExtern;
+  Hex32               value;
+  uint32_t            symbol;
+};
+
+/// A typedef so that YAML I/O can treat this vector as a sequence.
+typedef std::vector<Relocation> Relocations;
+
+/// A typedef so that YAML I/O can process the raw bytes in a section.
+typedef std::vector<Hex8> ContentBytes;
+
+/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence.
+typedef std::vector<uint32_t> IndirectSymbols;
+
+/// A typedef so that YAML I/O can encode/decode section attributes.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
+
+/// A typedef so that YAML I/O can encode/decode section alignment.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
+
+/// Mach-O has a 32-bit and 64-bit section record.  This normalized form
+/// can support either kind.
+struct Section {
+  Section() : type(llvm::MachO::S_REGULAR),
+              attributes(0), alignment(1), address(0) { }
+
+  StringRef       segmentName;
+  StringRef       sectionName;
+  SectionType     type;
+  SectionAttr     attributes;
+  SectionAlignment        alignment;
+  Hex64           address;
+  ArrayRef<uint8_t> content;
+  Relocations     relocations;
+  IndirectSymbols indirectSymbols;
+
+#ifndef NDEBUG
+  raw_ostream& operator<<(raw_ostream &OS) const {
+    dump(OS);
+    return OS;
+  }
+
+  void dump(raw_ostream &OS = llvm::dbgs()) const;
+#endif
+};
+
+
+/// A typedef so that YAML I/O can encode/decode the scope bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, SymbolScope)
+
+/// A typedef so that YAML I/O can encode/decode the desc bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SymbolDesc)
+
+/// Mach-O has a 32-bit and 64-bit symbol table entry (nlist), and the symbol
+/// type and scope and mixed in the same n_type field.  This normalized form
+/// works for any pointer size and separates out the type and scope.
+struct Symbol {
+  Symbol() : type(llvm::MachO::N_UNDF), scope(0), sect(0), desc(0), value(0) { }
+
+  StringRef     name;
+  NListType     type;
+  SymbolScope   scope;
+  uint8_t       sect;
+  SymbolDesc    desc;
+  Hex64         value;
+};
+
+/// Check whether the given section type indicates a zero-filled section.
+// FIXME: Utility functions of this kind should probably be moved into
+//        llvm/Support.
+inline bool isZeroFillSection(SectionType T) {
+  return (T == llvm::MachO::S_ZEROFILL ||
+          T == llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
+/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
+
+/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
+
+/// Segments are only used in normalized final linked images (not in relocatable
+/// object files). They specify how a range of the file is loaded.
+struct Segment {
+  StringRef     name;
+  Hex64         address;
+  Hex64         size;
+  VMProtect     init_access;
+  VMProtect     max_access;
+};
+
+/// Only used in normalized final linked images to specify on which dylibs
+/// it depends.
+struct DependentDylib {
+  StringRef       path;
+  LoadCommandType kind;
+  PackedVersion   compatVersion;
+  PackedVersion   currentVersion;
+};
+
+/// A normalized rebasing entry.  Only used in normalized final linked images.
+struct RebaseLocation {
+  Hex32         segOffset;
+  uint8_t       segIndex;
+  RebaseType    kind;
+};
+
+/// A normalized binding entry.  Only used in normalized final linked images.
+struct BindLocation {
+  Hex32           segOffset;
+  uint8_t         segIndex;
+  BindType        kind;
+  bool            canBeNull;
+  int             ordinal;
+  StringRef       symbolName;
+  Hex64           addend;
+};
+
+/// A typedef so that YAML I/O can encode/decode export flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportFlags)
+
+/// A normalized export entry.  Only used in normalized final linked images.
+struct Export {
+  StringRef         name;
+  Hex64             offset;
+  ExportSymbolKind  kind;
+  ExportFlags       flags;
+  Hex32             otherOffset;
+  StringRef         otherName;
+};
+
+/// A normalized data-in-code entry.
+struct DataInCode {
+  Hex32           offset;
+  Hex16           length;
+  DataRegionType  kind;
+};
+
+
+/// A typedef so that YAML I/O can encode/decode mach_header.flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
+
+///
+struct NormalizedFile {
+  MachOLinkingContext::Arch   arch = MachOLinkingContext::arch_unknown;
+  HeaderFileType              fileType = llvm::MachO::MH_OBJECT;
+  FileFlags                   flags = 0;
+  std::vector<Segment>        segments; // Not used in object files.
+  std::vector<Section>        sections;
+
+  // Symbols sorted by kind.
+  std::vector<Symbol>         localSymbols;
+  std::vector<Symbol>         globalSymbols;
+  std::vector<Symbol>         undefinedSymbols;
+
+  // Maps to load commands with no LINKEDIT content (final linked images only).
+  std::vector<DependentDylib> dependentDylibs;
+  StringRef                   installName;        // dylibs only
+  PackedVersion               compatVersion = 0;  // dylibs only
+  PackedVersion               currentVersion = 0; // dylibs only
+  bool                        hasUUID = false;
+  bool                        hasMinVersionLoadCommand = false;
+  bool                        generateDataInCodeLoadCommand = false;
+  std::vector<StringRef>      rpaths;
+  Hex64                       entryAddress = 0;
+  Hex64                       stackSize = 0;
+  MachOLinkingContext::OS     os = MachOLinkingContext::OS::unknown;
+  Hex64                       sourceVersion = 0;
+  PackedVersion               minOSverson = 0;
+  PackedVersion               sdkVersion = 0;
+  LoadCommandType             minOSVersionKind = (LoadCommandType)0;
+
+  // Maps to load commands with LINKEDIT content (final linked images only).
+  Hex32                       pageSize = 0;
+  std::vector<RebaseLocation> rebasingInfo;
+  std::vector<BindLocation>   bindingInfo;
+  std::vector<BindLocation>   weakBindingInfo;
+  std::vector<BindLocation>   lazyBindingInfo;
+  std::vector<Export>         exportInfo;
+  std::vector<uint8_t>        functionStarts;
+  std::vector<DataInCode>     dataInCode;
+
+  // TODO:
+  // code-signature
+  // split-seg-info
+  // function-starts
+
+  // For any allocations in this struct which need to be owned by this struct.
+  BumpPtrAllocator            ownedAllocations;
+};
+
+/// Tests if a file is a non-fat mach-o object file.
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
+
+/// If the buffer is a fat file with the request arch, then this function
+/// returns true with 'offset' and 'size' set to location of the arch slice
+/// within the buffer.  Otherwise returns false;
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+                      uint32_t &offset, uint32_t &size);
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+           const MachOLinkingContext::Arch arch);
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file);
+
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Writes a yaml encoded mach-o files given an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+                        const NormalizedFile &normalizedFile,
+                        bool copyRefs);
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+                       const NormalizedFile &normalizedFile,
+                       bool copyRefs);
+
+/// Takes in-memory normalized dylib or object and parses it into lld::File
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+                  bool copyRefs);
+
+/// Takes atoms and generates a normalized macho-o view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
+
+
+} // namespace normalized
+
+/// Class for interfacing mach-o yaml files into generic yaml parsing
+class MachOYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+public:
+  MachOYamlIOTaggedDocumentHandler(MachOLinkingContext::Arch arch)
+    : _arch(arch) { }
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override;
+private:
+  const MachOLinkingContext::Arch _arch;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
new file mode 100644 (file)
index 0000000..a17de5b
--- /dev/null
@@ -0,0 +1,586 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts from
+/// mach-o on-disk binary format to in-memory normalized mach-o.
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        |
+///                        |
+///                        v
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+
+#include "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <system_error>
+
+using namespace llvm::MachO;
+using llvm::object::ExportEntry;
+using llvm::object::MachOObjectFile;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+// Utility to call a lambda expression on each load command.
+static llvm::Error forEachLoadCommand(
+    StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
+    std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
+  const char* p = lcRange.begin();
+  for (unsigned i=0; i < lcCount; ++i) {
+    const load_command *lc = reinterpret_cast<const load_command*>(p);
+    load_command lcCopy;
+    const load_command *slc = lc;
+    if (isBig != llvm::sys::IsBigEndianHost) {
+      memcpy(&lcCopy, lc, sizeof(load_command));
+      swapStruct(lcCopy);
+      slc = &lcCopy;
+    }
+    if ( (p + slc->cmdsize) > lcRange.end() )
+      return llvm::make_error<GenericError>("Load command exceeds range");
+
+    if (func(slc->cmd, slc->cmdsize, p))
+      return llvm::Error();
+
+    p += slc->cmdsize;
+  }
+
+  return llvm::Error();
+}
+
+static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
+                                         bool bigEndian,
+                                         uint32_t reloff, uint32_t nreloc) {
+  if ((reloff + nreloc*8) > buffer.size())
+    return make_error_code(llvm::errc::executable_format_error);
+  const any_relocation_info* relocsArray =
+            reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff);
+
+  for(uint32_t i=0; i < nreloc; ++i) {
+    relocs.push_back(unpackRelocation(relocsArray[i], bigEndian));
+  }
+  return std::error_code();
+}
+
+static std::error_code
+appendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig,
+                      uint32_t istOffset, uint32_t istCount,
+                      uint32_t startIndex, uint32_t count) {
+  if ((istOffset + istCount*4) > buffer.size())
+    return make_error_code(llvm::errc::executable_format_error);
+  if (startIndex+count  > istCount)
+    return make_error_code(llvm::errc::executable_format_error);
+  const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data();
+
+  for(uint32_t i=0; i < count; ++i) {
+    isyms.push_back(read32(
+        indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig));
+  }
+  return std::error_code();
+}
+
+
+template <typename T> static T readBigEndian(T t) {
+  if (llvm::sys::IsLittleEndianHost)
+    llvm::sys::swapByteOrder(t);
+  return t;
+}
+
+
+static bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) {
+  switch (read32(&mh->magic, false)) {
+  case llvm::MachO::MH_MAGIC:
+    is64 = false;
+    isBig = false;
+    return true;
+  case llvm::MachO::MH_MAGIC_64:
+    is64 = true;
+    isBig = false;
+    return true;
+  case llvm::MachO::MH_CIGAM:
+    is64 = false;
+    isBig = true;
+    return true;
+  case llvm::MachO::MH_CIGAM_64:
+    is64 = true;
+    isBig = true;
+    return true;
+  default:
+    return false;
+  }
+}
+
+
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
+  // Try opening and mapping file at path.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path);
+  if (b.getError())
+    return false;
+
+  // If file length < 32 it is too small to be mach-o object file.
+  StringRef fileBuffer = b->get()->getBuffer();
+  if (fileBuffer.size() < 32)
+    return false;
+
+  // If file buffer does not start with MH_MAGIC (and variants), not obj file.
+  const mach_header *mh = reinterpret_cast<const mach_header *>(
+                                                            fileBuffer.begin());
+  bool is64, isBig;
+  if (!isMachOHeader(mh, is64, isBig))
+    return false;
+
+  // If not MH_OBJECT, not object file.
+  if (read32(&mh->filetype, isBig) != MH_OBJECT)
+    return false;
+
+  // Lookup up arch from cpu/subtype pair.
+  arch = MachOLinkingContext::archFromCpuType(
+      read32(&mh->cputype, isBig),
+      read32(&mh->cpusubtype, isBig));
+  return true;
+}
+
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+                      uint32_t &offset, uint32_t &size) {
+  const char *start = mb.getBufferStart();
+  const llvm::MachO::fat_header *fh =
+      reinterpret_cast<const llvm::MachO::fat_header *>(start);
+  if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC)
+    return false;
+  uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
+  const fat_arch *fstart =
+      reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
+  const fat_arch *fend =
+      reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) +
+                                         sizeof(fat_arch) * nfat_arch);
+  const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch);
+  const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
+  for (const fat_arch *fa = fstart; fa < fend; ++fa) {
+    if ((readBigEndian(fa->cputype) == reqCpuType) &&
+        (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) {
+      offset = readBigEndian(fa->offset);
+      size = readBigEndian(fa->size);
+      if ((offset + size) > mb.getBufferSize())
+        return false;
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+           const MachOLinkingContext::Arch arch) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  const char *start = mb->getBufferStart();
+  size_t objSize = mb->getBufferSize();
+  const mach_header *mh = reinterpret_cast<const mach_header *>(start);
+
+  uint32_t sliceOffset;
+  uint32_t sliceSize;
+  if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) {
+    start = &start[sliceOffset];
+    objSize = sliceSize;
+    mh = reinterpret_cast<const mach_header *>(start);
+  }
+
+  // Determine endianness and pointer size for mach-o file.
+  bool is64, isBig;
+  if (!isMachOHeader(mh, is64, isBig))
+    return llvm::make_error<GenericError>("File is not a mach-o");
+
+  // Endian swap header, if needed.
+  mach_header headerCopy;
+  const mach_header *smh = mh;
+  if (isBig != llvm::sys::IsBigEndianHost) {
+    memcpy(&headerCopy, mh, sizeof(mach_header));
+    swapStruct(headerCopy);
+    smh = &headerCopy;
+  }
+
+  // Validate head and load commands fit in buffer.
+  const uint32_t lcCount = smh->ncmds;
+  const char *lcStart =
+      start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
+  StringRef lcRange(lcStart, smh->sizeofcmds);
+  if (lcRange.end() > (start + objSize))
+    return llvm::make_error<GenericError>("Load commands exceed file size");
+
+  // Get architecture from mach_header.
+  f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
+  if (f->arch != arch) {
+    return llvm::make_error<GenericError>(
+                                  Twine("file is wrong architecture. Expected "
+                                  "(" + MachOLinkingContext::nameFromArch(arch)
+                                  + ") found ("
+                                  + MachOLinkingContext::nameFromArch(f->arch)
+                                  + ")" ));
+  }
+  // Copy file type and flags
+  f->fileType = HeaderFileType(smh->filetype);
+  f->flags = smh->flags;
+
+
+  // Pre-scan load commands looking for indirect symbol table.
+  uint32_t indirectSymbolTableOffset = 0;
+  uint32_t indirectSymbolTableCount = 0;
+  auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+                               [&](uint32_t cmd, uint32_t size,
+                                   const char *lc) -> bool {
+    if (cmd == LC_DYSYMTAB) {
+      const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
+      indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
+      indirectSymbolTableCount = read32(&d->nindirectsyms, isBig);
+      return true;
+    }
+    return false;
+  });
+  if (ec)
+    return std::move(ec);
+
+  // Walk load commands looking for segments/sections and the symbol table.
+  const data_in_code_entry *dataInCode = nullptr;
+  const dyld_info_command *dyldInfo = nullptr;
+  uint32_t dataInCodeSize = 0;
+  ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+                    [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
+    switch(cmd) {
+    case LC_SEGMENT_64:
+      if (is64) {
+        const segment_command_64 *seg =
+                              reinterpret_cast<const segment_command_64*>(lc);
+        const unsigned sectionCount = read32(&seg->nsects, isBig);
+        const section_64 *sects = reinterpret_cast<const section_64*>
+                                  (lc + sizeof(segment_command_64));
+        const unsigned lcSize = sizeof(segment_command_64)
+                                              + sectionCount*sizeof(section_64);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size)
+          return true;
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section_64 *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type = (SectionType)(read32(&sect->flags, isBig) &
+                                       SECTION_TYPE);
+          section.attributes  = read32(&sect->flags, isBig) & SECTION_ATTRIBUTES;
+          section.alignment   = 1 << read32(&sect->align, isBig);
+          section.address     = read64(&sect->addr, isBig);
+          const uint8_t *content =
+            (const uint8_t *)start + read32(&sect->offset, isBig);
+          size_t contentSize = read64(&sect->size, isBig);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content = llvm::makeArrayRef(content, contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), isBig,
+                            read32(&sect->reloff, isBig),
+                            read32(&sect->nreloc, isBig));
+          if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+            appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(),
+                                  isBig,
+                                  indirectSymbolTableOffset,
+                                  indirectSymbolTableCount,
+                                  read32(&sect->reserved1, isBig),
+                                  contentSize/4);
+          }
+          f->sections.push_back(section);
+        }
+      }
+      break;
+    case LC_SEGMENT:
+      if (!is64) {
+        const segment_command *seg =
+                              reinterpret_cast<const segment_command*>(lc);
+        const unsigned sectionCount = read32(&seg->nsects, isBig);
+        const section *sects = reinterpret_cast<const section*>
+                                  (lc + sizeof(segment_command));
+        const unsigned lcSize = sizeof(segment_command)
+                                              + sectionCount*sizeof(section);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size)
+          return true;
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type = (SectionType)(read32(&sect->flags, isBig) &
+                                       SECTION_TYPE);
+          section.attributes =
+              read32((const uint8_t *)&sect->flags, isBig) & SECTION_ATTRIBUTES;
+          section.alignment   = 1 << read32(&sect->align, isBig);
+          section.address     = read32(&sect->addr, isBig);
+          const uint8_t *content =
+            (const uint8_t *)start + read32(&sect->offset, isBig);
+          size_t contentSize = read32(&sect->size, isBig);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content = llvm::makeArrayRef(content, contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), isBig,
+                            read32(&sect->reloff, isBig),
+                            read32(&sect->nreloc, isBig));
+          if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+            appendIndirectSymbols(
+                section.indirectSymbols, mb->getBuffer(), isBig,
+                indirectSymbolTableOffset, indirectSymbolTableCount,
+                read32(&sect->reserved1, isBig), contentSize / 4);
+          }
+          f->sections.push_back(section);
+        }
+      }
+      break;
+    case LC_SYMTAB: {
+      const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
+      const char *strings = start + read32(&st->stroff, isBig);
+      const uint32_t strSize = read32(&st->strsize, isBig);
+      // Validate string pool and symbol table all in buffer.
+      if (read32((const uint8_t *)&st->stroff, isBig) +
+              read32((const uint8_t *)&st->strsize, isBig) >
+          objSize)
+        return true;
+      if (is64) {
+        const uint32_t symOffset = read32(&st->symoff, isBig);
+        const uint32_t symCount = read32(&st->nsyms, isBig);
+        if ( symOffset+(symCount*sizeof(nlist_64)) > objSize)
+          return true;
+        const nlist_64 *symbols =
+            reinterpret_cast<const nlist_64 *>(start + symOffset);
+        // Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          nlist_64 tempSym;
+          memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
+          const nlist_64 *sin = &tempSym;
+          if (isBig != llvm::sys::IsBigEndianHost)
+            swapStruct(tempSym);
+          Symbol sout;
+          if (sin->n_strx > strSize)
+            return true;
+          sout.name  = &strings[sin->n_strx];
+          sout.type  = (NListType)(sin->n_type & N_TYPE);
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sin->n_type & N_EXT)
+            f->globalSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      } else {
+        const uint32_t symOffset = read32(&st->symoff, isBig);
+        const uint32_t symCount = read32(&st->nsyms, isBig);
+        if ( symOffset+(symCount*sizeof(nlist)) > objSize)
+          return true;
+        const nlist *symbols =
+            reinterpret_cast<const nlist *>(start + symOffset);
+        // Convert each nlist to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          const nlist *sin = &symbols[i];
+          nlist tempSym;
+          if (isBig != llvm::sys::IsBigEndianHost) {
+            tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
+          }
+          Symbol sout;
+          if (sin->n_strx > strSize)
+            return true;
+          sout.name  = &strings[sin->n_strx];
+          sout.type  = (NListType)(sin->n_type & N_TYPE);
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sout.scope == (SymbolScope)N_EXT)
+            f->globalSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      }
+      }
+      break;
+    case LC_ID_DYLIB: {
+      const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+      f->installName = lc + read32(&dl->dylib.name, isBig);
+      f->currentVersion = read32(&dl->dylib.current_version, isBig);
+      f->compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+      }
+      break;
+    case LC_DATA_IN_CODE: {
+      const linkedit_data_command *ldc =
+                            reinterpret_cast<const linkedit_data_command*>(lc);
+      dataInCode = reinterpret_cast<const data_in_code_entry *>(
+          start + read32(&ldc->dataoff, isBig));
+      dataInCodeSize = read32(&ldc->datasize, isBig);
+      }
+      break;
+    case LC_LOAD_DYLIB:
+    case LC_LOAD_WEAK_DYLIB:
+    case LC_REEXPORT_DYLIB:
+    case LC_LOAD_UPWARD_DYLIB: {
+      const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+      DependentDylib entry;
+      entry.path = lc + read32(&dl->dylib.name, isBig);
+      entry.kind = LoadCommandType(cmd);
+      entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+      entry.currentVersion = read32(&dl->dylib.current_version, isBig);
+      f->dependentDylibs.push_back(entry);
+     }
+      break;
+    case LC_RPATH: {
+      const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc);
+      f->rpaths.push_back(lc + read32(&rpc->path, isBig));
+     }
+      break;
+    case LC_DYLD_INFO:
+    case LC_DYLD_INFO_ONLY:
+      dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
+      break;
+    case LC_VERSION_MIN_MACOSX:
+    case LC_VERSION_MIN_IPHONEOS:
+    case LC_VERSION_MIN_WATCHOS:
+    case LC_VERSION_MIN_TVOS:
+      // If we are emitting an object file, then we may take the load command
+      // kind from these commands and pass it on to the output
+      // file.
+      f->minOSVersionKind = (LoadCommandType)cmd;
+      break;
+    }
+    return false;
+  });
+  if (ec)
+    return std::move(ec);
+
+  if (dataInCode) {
+    // Convert on-disk data_in_code_entry array to DataInCode vector.
+    for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) {
+      DataInCode entry;
+      entry.offset = read32(&dataInCode[i].offset, isBig);
+      entry.length = read16(&dataInCode[i].length, isBig);
+      entry.kind =
+          (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig);
+      f->dataInCode.push_back(entry);
+    }
+  }
+
+  if (dyldInfo) {
+    // If any exports, extract and add to normalized exportInfo vector.
+    if (dyldInfo->export_size) {
+      const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start +
+                                                          dyldInfo->export_off);
+      ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
+      for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
+        Export normExport;
+        normExport.name = trieExport.name().copy(f->ownedAllocations);
+        normExport.offset = trieExport.address();
+        normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
+        normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
+        normExport.otherOffset = trieExport.other();
+        if (!trieExport.otherName().empty())
+          normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
+        f->exportInfo.push_back(normExport);
+      }
+    }
+  }
+
+  return std::move(f);
+}
+
+class MachOObjectReader : public Reader {
+public:
+  MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    return (magic == llvm::sys::fs::file_magic::macho_object &&
+            mb.getBufferSize() > 32);
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const Registry &registry) const override {
+    std::unique_ptr<File> ret =
+        llvm::make_unique<MachOFile>(std::move(mb), &_ctx);
+    return std::move(ret);
+  }
+
+private:
+  MachOLinkingContext &_ctx;
+};
+
+class MachODylibReader : public Reader {
+public:
+  MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    switch (magic) {
+    case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
+    case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
+      return mb.getBufferSize() > 32;
+    default:
+      return false;
+    }
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const Registry &registry) const override {
+    std::unique_ptr<File> ret =
+        llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx);
+    return std::move(ret);
+  }
+
+private:
+  MachOLinkingContext &_ctx;
+};
+
+} // namespace normalized
+} // namespace mach_o
+
+void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
+  MachOLinkingContext::Arch arch = ctx.arch();
+  add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx)));
+  add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx)));
+  addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
+               ctx.archHandler().kindStrings());
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                           new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
+}
+
+
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
new file mode 100644 (file)
index 0000000..86823ef
--- /dev/null
@@ -0,0 +1,218 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+
+#include "MachONormalizedFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MachO.h"
+#include <system_error>
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+class ByteBuffer {
+public:
+  ByteBuffer() : _ostream(_bytes) { }
+
+  void append_byte(uint8_t b) {
+    _ostream << b;
+  }
+  void append_uleb128(uint64_t value) {
+    llvm::encodeULEB128(value, _ostream);
+  }
+  void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+    unsigned min = llvm::getULEB128Size(value);
+    assert(min <= byteCount);
+    unsigned pad = byteCount - min;
+    llvm::encodeULEB128(value, _ostream, pad);
+  }
+  void append_sleb128(int64_t value) {
+    llvm::encodeSLEB128(value, _ostream);
+  }
+  void append_string(StringRef str) {
+    _ostream << str;
+    append_byte(0);
+  }
+  void align(unsigned alignment) {
+    while ( (_ostream.tell() % alignment) != 0 )
+      append_byte(0);
+  }
+  size_t size() {
+    return _ostream.tell();
+  }
+  const uint8_t *bytes() {
+    return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+  }
+
+private:
+  SmallVector<char, 128>        _bytes;
+  // Stream ivar must be after SmallVector ivar to construct properly.
+  llvm::raw_svector_ostream     _ostream;
+};
+
+using namespace llvm::support::endian;
+using llvm::sys::getSwappedBytes;
+
+template<typename T>
+static inline uint16_t read16(const T *loc, bool isBig) {
+  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
+         "invalid pointer alignment");
+  return isBig ? read16be(loc) : read16le(loc);
+}
+
+template<typename T>
+static inline uint32_t read32(const T *loc, bool isBig) {
+  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
+         "invalid pointer alignment");
+  return isBig ? read32be(loc) : read32le(loc);
+}
+
+template<typename T>
+static inline uint64_t read64(const T *loc, bool isBig) {
+  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
+         "invalid pointer alignment");
+  return isBig ? read64be(loc) : read64le(loc);
+}
+
+inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
+  if (isBig)
+    write16be(loc, value);
+  else
+    write16le(loc, value);
+}
+
+inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
+  if (isBig)
+    write32be(loc, value);
+  else
+    write32le(loc, value);
+}
+
+inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
+  if (isBig)
+    write64be(loc, value);
+  else
+    write64le(loc, value);
+}
+
+inline uint32_t
+bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
+                                                          uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1);
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  return (value >> shift) & mask;
+}
+
+inline void
+bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
+                            uint8_t firstBit, uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1);
+  assert((newBits & mask) == newBits);
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  bits &= ~(mask << shift);
+  bits |= (newBits << shift);
+}
+
+inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
+                                   bool isBigEndian) {
+  uint32_t r0 = read32(&r.r_word0, isBigEndian);
+  uint32_t r1 = read32(&r.r_word1, isBigEndian);
+
+  Relocation result;
+  if (r0 & llvm::MachO::R_SCATTERED) {
+    // scattered relocation record always laid out like big endian bit field
+    result.offset     = bitFieldExtract(r0, true, 8, 24);
+    result.scattered  = true;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r0, true, 4, 4);
+    result.length     = bitFieldExtract(r0, true, 2, 2);
+    result.pcRel      = bitFieldExtract(r0, true, 1, 1);
+    result.isExtern   = false;
+    result.value      = r1;
+    result.symbol     = 0;
+  } else {
+    result.offset     = r0;
+    result.scattered  = false;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r1, isBigEndian, 28, 4);
+    result.length     = bitFieldExtract(r1, isBigEndian, 25, 2);
+    result.pcRel      = bitFieldExtract(r1, isBigEndian, 24, 1);
+    result.isExtern   = bitFieldExtract(r1, isBigEndian, 27, 1);
+    result.value      = 0;
+    result.symbol     = bitFieldExtract(r1, isBigEndian, 0, 24);
+  }
+  return result;
+}
+
+
+inline llvm::MachO::any_relocation_info
+packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
+  uint32_t r0 = 0;
+  uint32_t r1 = 0;
+
+  if (r.scattered) {
+    r1 = r.value;
+    bitFieldSet(r0, true, r.offset,    8, 24);
+    bitFieldSet(r0, true, r.type,      4, 4);
+    bitFieldSet(r0, true, r.length,    2, 2);
+    bitFieldSet(r0, true, r.pcRel,     1, 1);
+    bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
+  } else {
+    r0 = r.offset;
+    bitFieldSet(r1, isBigEndian, r.type,     28, 4);
+    bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
+    bitFieldSet(r1, isBigEndian, r.length,   25, 2);
+    bitFieldSet(r1, isBigEndian, r.pcRel,    24, 1);
+    bitFieldSet(r1, isBigEndian, r.symbol,   0,  24);
+  }
+
+  llvm::MachO::any_relocation_info result;
+  result.r_word0 = swap ? getSwappedBytes(r0) : r0;
+  result.r_word1 = swap ? getSwappedBytes(r1) : r1;
+  return result;
+}
+
+inline StringRef getString16(const char s[16]) {
+  StringRef x = s;
+  if ( x.size() > 16 )
+    return x.substr(0, 16);
+  else
+    return x;
+}
+
+inline void setString16(StringRef str, char s[16]) {
+  memset(s, 0, 16);
+  memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
+}
+
+// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
+// that the same table can be used to map mach-o sections to and from
+// DefinedAtom::ContentType.
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+                                          StringRef &segmentName,
+                                          StringRef &sectionName,
+                                          SectionType &sectionType,
+                                          SectionAttr &sectionAttrs,
+                                          bool &relocsToDefinedCanBeImplicit);
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
new file mode 100644 (file)
index 0000000..f3e1596
--- /dev/null
@@ -0,0 +1,1500 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts normalized
+/// mach-o in memory to mach-o binary on disk.
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        ^
+///                        |
+///                        |
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <list>
+#include <map>
+#include <system_error>
+
+using namespace llvm::MachO;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode; // Forward declaration.
+
+struct TrieEdge : public llvm::ilist_node<TrieEdge> {
+  TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+
+  StringRef          _subString;
+  struct TrieNode   *_child;
+};
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+
+namespace llvm {
+  using lld::mach_o::normalized::TrieEdge;
+  template <>
+  struct ilist_traits<TrieEdge>
+    : public ilist_default_traits<TrieEdge> {
+  private:
+    mutable ilist_half_node<TrieEdge> Sentinel;
+  public:
+    TrieEdge *createSentinel() const {
+      return static_cast<TrieEdge*>(&Sentinel);
+    }
+    void destroySentinel(TrieEdge *) const {}
+
+    TrieEdge *provideInitialHead() const { return createSentinel(); }
+    TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); }
+    static void noteHead(TrieEdge*, TrieEdge*) {}
+    void deleteNode(TrieEdge *N) {}
+
+  private:
+    void createNode(const TrieEdge &);
+  };
+} // namespace llvm
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode {
+  typedef llvm::ilist<TrieEdge> TrieEdgeList;
+
+  TrieNode(StringRef s)
+      : _cummulativeString(s), _address(0), _flags(0), _other(0),
+        _trieOffset(0), _hasExportInfo(false) {}
+  ~TrieNode() = default;
+
+  void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+                 std::vector<TrieNode *> &allNodes);
+  bool updateOffset(uint32_t &offset);
+  void appendToByteBuffer(ByteBuffer &out);
+
+private:
+  StringRef                 _cummulativeString;
+  TrieEdgeList              _children;
+  uint64_t                  _address;
+  uint64_t                  _flags;
+  uint64_t                  _other;
+  StringRef                 _importedName;
+  uint32_t                  _trieOffset;
+  bool                      _hasExportInfo;
+};
+
+/// Utility class for writing a mach-o binary file given an in-memory
+/// normalized file.
+class MachOFileLayout {
+public:
+  /// All layout computation is done in the constructor.
+  MachOFileLayout(const NormalizedFile &file);
+
+  /// Returns the final file size as computed in the constructor.
+  size_t      size() const;
+
+  // Returns size of the mach_header and load commands.
+  size_t      headerAndLoadCommandsSize() const;
+
+  /// Writes the normalized file as a binary mach-o file to the specified
+  /// path.  This does not have a stream interface because the generated
+  /// file may need the 'x' bit set.
+  llvm::Error writeBinary(StringRef path);
+
+private:
+  uint32_t    loadCommandsSize(uint32_t &count);
+  void        buildFileOffsets();
+  void        writeMachHeader();
+  llvm::Error writeLoadCommands();
+  void        writeSectionContent();
+  void        writeRelocations();
+  void        writeSymbolTable();
+  void        writeRebaseInfo();
+  void        writeBindingInfo();
+  void        writeLazyBindingInfo();
+  void        writeExportInfo();
+  void        writeFunctionStartsInfo();
+  void        writeDataInCodeInfo();
+  void        writeLinkEditContent();
+  void        buildLinkEditInfo();
+  void        buildRebaseInfo();
+  void        buildBindInfo();
+  void        buildLazyBindInfo();
+  void        buildExportTrie();
+  void        computeFunctionStartsSize();
+  void        computeDataInCodeSize();
+  void        computeSymbolTableSizes();
+  void        buildSectionRelocations();
+  void        appendSymbols(const std::vector<Symbol> &symbols,
+                                      uint32_t &symOffset, uint32_t &strOffset);
+  uint32_t    indirectSymbolIndex(const Section &sect, uint32_t &index);
+  uint32_t    indirectSymbolElementSize(const Section &sect);
+
+  // For use as template parameter to load command methods.
+  struct MachO64Trait {
+    typedef llvm::MachO::segment_command_64 command;
+    typedef llvm::MachO::section_64         section;
+    enum { LC = llvm::MachO::LC_SEGMENT_64 };
+  };
+
+  // For use as template parameter to load command methods.
+  struct MachO32Trait {
+    typedef llvm::MachO::segment_command   command;
+    typedef llvm::MachO::section           section;
+    enum { LC = llvm::MachO::LC_SEGMENT };
+  };
+
+  template <typename T>
+  llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc);
+  template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc);
+
+  uint32_t pointerAlign(uint32_t value);
+  static StringRef dyldPath();
+
+  struct SegExtraInfo {
+    uint32_t                    fileOffset;
+    uint32_t                    fileSize;
+    std::vector<const Section*> sections;
+  };
+  typedef std::map<const Segment*, SegExtraInfo> SegMap;
+  struct SectionExtraInfo {
+    uint32_t                    fileOffset;
+  };
+  typedef std::map<const Section*, SectionExtraInfo> SectionMap;
+
+  const NormalizedFile &_file;
+  std::error_code _ec;
+  uint8_t              *_buffer;
+  const bool            _is64;
+  const bool            _swap;
+  const bool            _bigEndianArch;
+  uint64_t              _seg1addr;
+  uint32_t              _startOfLoadCommands;
+  uint32_t              _countOfLoadCommands;
+  uint32_t              _endOfLoadCommands;
+  uint32_t              _startOfRelocations;
+  uint32_t              _startOfFunctionStarts;
+  uint32_t              _startOfDataInCode;
+  uint32_t              _startOfSymbols;
+  uint32_t              _startOfIndirectSymbols;
+  uint32_t              _startOfSymbolStrings;
+  uint32_t              _endOfSymbolStrings;
+  uint32_t              _symbolTableLocalsStartIndex;
+  uint32_t              _symbolTableGlobalsStartIndex;
+  uint32_t              _symbolTableUndefinesStartIndex;
+  uint32_t              _symbolStringPoolSize;
+  uint32_t              _symbolTableSize;
+  uint32_t              _functionStartsSize;
+  uint32_t              _dataInCodeSize;
+  uint32_t              _indirectSymbolTableCount;
+  // Used in object file creation only
+  uint32_t              _startOfSectionsContent;
+  uint32_t              _endOfSectionsContent;
+  // Used in final linked image only
+  uint32_t              _startOfLinkEdit;
+  uint32_t              _startOfRebaseInfo;
+  uint32_t              _endOfRebaseInfo;
+  uint32_t              _startOfBindingInfo;
+  uint32_t              _endOfBindingInfo;
+  uint32_t              _startOfLazyBindingInfo;
+  uint32_t              _endOfLazyBindingInfo;
+  uint32_t              _startOfExportTrie;
+  uint32_t              _endOfExportTrie;
+  uint32_t              _endOfLinkEdit;
+  uint64_t              _addressOfLinkEdit;
+  SegMap                _segInfo;
+  SectionMap            _sectInfo;
+  ByteBuffer            _rebaseInfo;
+  ByteBuffer            _bindingInfo;
+  ByteBuffer            _lazyBindingInfo;
+  ByteBuffer            _weakBindingInfo;
+  ByteBuffer            _exportTrie;
+};
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
+  MachOFileLayout layout(file);
+  return layout.headerAndLoadCommandsSize();
+}
+
+StringRef MachOFileLayout::dyldPath() {
+  return "/usr/lib/dyld";
+}
+
+uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
+  return llvm::alignTo(value, _is64 ? 8 : 4);
+}
+
+
+size_t MachOFileLayout::headerAndLoadCommandsSize() const {
+  return _endOfLoadCommands;
+}
+
+MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+    : _file(file),
+      _is64(MachOLinkingContext::is64Bit(file.arch)),
+      _swap(!MachOLinkingContext::isHostEndian(file.arch)),
+      _bigEndianArch(MachOLinkingContext::isBigEndian(file.arch)),
+      _seg1addr(INT64_MAX) {
+  _startOfLoadCommands = _is64 ? sizeof(mach_header_64) : sizeof(mach_header);
+  const size_t segCommandBaseSize =
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectsSize = (_is64 ? sizeof(section_64) : sizeof(section));
+  if (file.fileType == llvm::MachO::MH_OBJECT) {
+    // object files have just one segment load command containing all sections
+    _endOfLoadCommands = _startOfLoadCommands
+                               + segCommandBaseSize
+                               + file.sections.size() * sectsSize
+                               + sizeof(symtab_command);
+    _countOfLoadCommands = 2;
+    if (file.hasMinVersionLoadCommand) {
+      _endOfLoadCommands += sizeof(version_min_command);
+      _countOfLoadCommands++;
+    }
+    if (!_file.functionStarts.empty()) {
+      _endOfLoadCommands += sizeof(linkedit_data_command);
+      _countOfLoadCommands++;
+    }
+    if (_file.generateDataInCodeLoadCommand) {
+      _endOfLoadCommands += sizeof(linkedit_data_command);
+      _countOfLoadCommands++;
+    }
+    // Assign file offsets to each section.
+    _startOfSectionsContent = _endOfLoadCommands;
+    unsigned relocCount = 0;
+    uint64_t offset = _startOfSectionsContent;
+    for (const Section &sect : file.sections) {
+      if (isZeroFillSection(sect.type))
+        _sectInfo[&sect].fileOffset = 0;
+      else {
+        offset = llvm::alignTo(offset, sect.alignment);
+        _sectInfo[&sect].fileOffset = offset;
+        offset += sect.content.size();
+      }
+      relocCount += sect.relocations.size();
+    }
+    _endOfSectionsContent = offset;
+
+    computeSymbolTableSizes();
+    computeFunctionStartsSize();
+    computeDataInCodeSize();
+
+    // Align start of relocations.
+    _startOfRelocations = pointerAlign(_endOfSectionsContent);
+    _startOfFunctionStarts = _startOfRelocations + relocCount * 8;
+    _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+    _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+    // Add Indirect symbol table.
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    // Align start of symbol table and symbol strings.
+    _startOfSymbolStrings = _startOfIndirectSymbols
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfRelocations=" << _startOfRelocations << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  startOfSectionsContent=" << _startOfSectionsContent << "\n"
+      << "  endOfSectionsContent=" << _endOfSectionsContent << "\n");
+  } else {
+    // Final linked images have one load command per segment.
+    _endOfLoadCommands = _startOfLoadCommands
+                          + loadCommandsSize(_countOfLoadCommands);
+
+    // Assign section file offsets.
+    buildFileOffsets();
+    buildLinkEditInfo();
+
+    // LINKEDIT of final linked images has in order:
+    // rebase info, binding info, lazy binding info, weak binding info,
+    // data-in-code, symbol table, indirect symbol table, symbol table strings.
+    _startOfRebaseInfo = _startOfLinkEdit;
+    _endOfRebaseInfo = _startOfRebaseInfo + _rebaseInfo.size();
+    _startOfBindingInfo = _endOfRebaseInfo;
+    _endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
+    _startOfLazyBindingInfo = _endOfBindingInfo;
+    _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
+    _startOfExportTrie = _endOfLazyBindingInfo;
+    _endOfExportTrie = _startOfExportTrie + _exportTrie.size();
+    _startOfFunctionStarts = _endOfExportTrie;
+    _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+    _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    _startOfSymbolStrings = _startOfIndirectSymbols
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfLinkEdit=" << _startOfLinkEdit << "\n"
+      << "  startOfRebaseInfo=" << _startOfRebaseInfo << "\n"
+      << "  endOfRebaseInfo=" << _endOfRebaseInfo << "\n"
+      << "  startOfBindingInfo=" << _startOfBindingInfo << "\n"
+      << "  endOfBindingInfo=" << _endOfBindingInfo << "\n"
+      << "  startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
+      << "  endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
+      << "  startOfExportTrie=" << _startOfExportTrie << "\n"
+      << "  endOfExportTrie=" << _endOfExportTrie << "\n"
+      << "  startOfFunctionStarts=" << _startOfFunctionStarts << "\n"
+      << "  startOfDataInCode=" << _startOfDataInCode << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  addressOfLinkEdit=" << _addressOfLinkEdit << "\n");
+  }
+}
+
+uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
+  uint32_t size = 0;
+  count = 0;
+
+  const size_t segCommandSize =
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectionSize = (_is64 ? sizeof(section_64) : sizeof(section));
+
+  // Add LC_SEGMENT for each segment.
+  size += _file.segments.size() * segCommandSize;
+  count += _file.segments.size();
+  // Add section record for each section.
+  size += _file.sections.size() * sectionSize;
+
+  // If creating a dylib, add LC_ID_DYLIB.
+  if (_file.fileType == llvm::MachO::MH_DYLIB) {
+    size += sizeof(dylib_command) + pointerAlign(_file.installName.size() + 1);
+    ++count;
+  }
+
+  // Add LC_DYLD_INFO
+  size += sizeof(dyld_info_command);
+  ++count;
+
+  // Add LC_SYMTAB
+  size += sizeof(symtab_command);
+  ++count;
+
+  // Add LC_DYSYMTAB
+  if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+    size += sizeof(dysymtab_command);
+    ++count;
+  }
+
+  // If main executable add LC_LOAD_DYLINKER
+  if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+    size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
+    ++count;
+  }
+
+  // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+  // LC_VERSION_MIN_TVOS
+  if (_file.hasMinVersionLoadCommand) {
+    size += sizeof(version_min_command);
+    ++count;
+  }
+
+  // Add LC_SOURCE_VERSION
+  size += sizeof(source_version_command);
+  ++count;
+
+  // If main executable add LC_MAIN
+  if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+    size += sizeof(entry_point_command);
+    ++count;
+  }
+
+  // Add LC_LOAD_DYLIB for each dependent dylib.
+  for (const DependentDylib &dep : _file.dependentDylibs) {
+    size += sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+    ++count;
+  }
+
+  // Add LC_RPATH
+  for (const StringRef &path : _file.rpaths) {
+    size += pointerAlign(sizeof(rpath_command) + path.size() + 1);
+    ++count;
+  }
+
+  // Add LC_FUNCTION_STARTS if needed
+  if (!_file.functionStarts.empty()) {
+    size += sizeof(linkedit_data_command);
+    ++count;
+  }
+
+  // Add LC_DATA_IN_CODE if requested.  Note, we do encode zero length entries.
+  // FIXME: Zero length entries is only to match ld64.  Should we change this?
+  if (_file.generateDataInCodeLoadCommand) {
+    size += sizeof(linkedit_data_command);
+    ++count;
+  }
+
+  return size;
+}
+
+static bool overlaps(const Segment &s1, const Segment &s2) {
+  if (s2.address >= s1.address+s1.size)
+    return false;
+  if (s1.address >= s2.address+s2.size)
+    return false;
+  return true;
+}
+
+static bool overlaps(const Section &s1, const Section &s2) {
+  if (s2.address >= s1.address+s1.content.size())
+    return false;
+  if (s1.address >= s2.address+s2.content.size())
+    return false;
+  return true;
+}
+
+void MachOFileLayout::buildFileOffsets() {
+  // Verify no segments overlap
+  for (const Segment &sg1 : _file.segments) {
+    for (const Segment &sg2 : _file.segments) {
+      if (&sg1 == &sg2)
+        continue;
+      if (overlaps(sg1,sg2)) {
+        _ec = make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+
+  // Verify no sections overlap
+  for (const Section &s1 : _file.sections) {
+    for (const Section &s2 : _file.sections) {
+      if (&s1 == &s2)
+        continue;
+      if (overlaps(s1,s2)) {
+        _ec = make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+
+  // Build side table of extra info about segments and sections.
+  SegExtraInfo t;
+  t.fileOffset = 0;
+  for (const Segment &sg : _file.segments) {
+    _segInfo[&sg] = t;
+  }
+  SectionExtraInfo t2;
+  t2.fileOffset = 0;
+  // Assign sections to segments.
+  for (const Section &s : _file.sections) {
+    _sectInfo[&s] = t2;
+    bool foundSegment = false;
+    for (const Segment &sg : _file.segments) {
+      if (sg.name.equals(s.segmentName)) {
+        if ((s.address >= sg.address)
+                        && (s.address+s.content.size() <= sg.address+sg.size)) {
+          _segInfo[&sg].sections.push_back(&s);
+          foundSegment = true;
+          break;
+        }
+      }
+    }
+    if (!foundSegment) {
+      _ec = make_error_code(llvm::errc::executable_format_error);
+      return;
+    }
+  }
+
+  // Assign file offsets.
+  uint32_t fileOffset = 0;
+  DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "buildFileOffsets()\n");
+  for (const Segment &sg : _file.segments) {
+    _segInfo[&sg].fileOffset = fileOffset;
+    if ((_seg1addr == INT64_MAX) && sg.init_access)
+      _seg1addr = sg.address;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "  segment=" << sg.name
+                  << ", fileOffset=" << _segInfo[&sg].fileOffset << "\n");
+
+    uint32_t segFileSize = 0;
+    // A segment that is not zero-fill must use a least one page of disk space.
+    if (sg.init_access)
+      segFileSize = _file.pageSize;
+    for (const Section *s : _segInfo[&sg].sections) {
+      uint32_t sectOffset = s->address - sg.address;
+      uint32_t sectFileSize =
+        isZeroFillSection(s->type) ? 0 : s->content.size();
+      segFileSize = std::max(segFileSize, sectOffset + sectFileSize);
+
+      _sectInfo[s].fileOffset = _segInfo[&sg].fileOffset + sectOffset;
+      DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "    section=" << s->sectionName
+                  << ", fileOffset=" << fileOffset << "\n");
+    }
+
+    // round up all segments to page aligned, except __LINKEDIT
+    if (!sg.name.equals("__LINKEDIT")) {
+      _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize);
+      fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize);
+    }
+    _addressOfLinkEdit = sg.address + sg.size;
+  }
+  _startOfLinkEdit = fileOffset;
+}
+
+size_t MachOFileLayout::size() const {
+  return _endOfSymbolStrings;
+}
+
+void MachOFileLayout::writeMachHeader() {
+  auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+  // dynamic x86 executables on newer OS version should also set the
+  // CPU_SUBTYPE_LIB64 mask in the CPU subtype.
+  // FIXME: Check that this is a dynamic executable, not a static one.
+  if (_file.fileType == llvm::MachO::MH_EXECUTE &&
+      cpusubtype == CPU_SUBTYPE_X86_64_ALL &&
+      _file.os == MachOLinkingContext::OS::macOSX) {
+    uint32_t version;
+    bool failed = MachOLinkingContext::parsePackedVersion("10.5", version);
+    if (!failed && _file.minOSverson >= version)
+      cpusubtype |= CPU_SUBTYPE_LIB64;
+  }
+
+  mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
+  mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
+  mh->cputype =  MachOLinkingContext::cpuTypeFromArch(_file.arch);
+  mh->cpusubtype = cpusubtype;
+  mh->filetype = _file.fileType;
+  mh->ncmds = _countOfLoadCommands;
+  mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
+  mh->flags = _file.flags;
+  if (_swap)
+    swapStruct(*mh);
+}
+
+uint32_t MachOFileLayout::indirectSymbolIndex(const Section &sect,
+                                                   uint32_t &index) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  uint32_t result = index;
+  index += sect.indirectSymbols.size();
+  return result;
+}
+
+uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  if (sect.type != S_SYMBOL_STUBS)
+    return 0;
+  return sect.content.size() / sect.indirectSymbols.size();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+  typename T::command* seg = reinterpret_cast<typename T::command*>(lc);
+  seg->cmd = T::LC;
+  seg->cmdsize = sizeof(typename T::command)
+                          + _file.sections.size() * sizeof(typename T::section);
+  uint8_t *next = lc + seg->cmdsize;
+  memset(seg->segname, 0, 16);
+  seg->vmaddr = 0;
+  seg->vmsize = _file.sections.back().address
+              + _file.sections.back().content.size();
+  seg->fileoff = _endOfLoadCommands;
+  seg->filesize = seg->vmsize;
+  seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->nsects = _file.sections.size();
+  seg->flags = 0;
+  if (_swap)
+    swapStruct(*seg);
+  typename T::section *sout = reinterpret_cast<typename T::section*>
+                                              (lc+sizeof(typename T::command));
+  uint32_t relOffset = _startOfRelocations;
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Section &sin : _file.sections) {
+    setString16(sin.sectionName, sout->sectname);
+    setString16(sin.segmentName, sout->segname);
+    sout->addr = sin.address;
+    sout->size = sin.content.size();
+    sout->offset = _sectInfo[&sin].fileOffset;
+    sout->align = llvm::Log2_32(sin.alignment);
+    sout->reloff = sin.relocations.empty() ? 0 : relOffset;
+    sout->nreloc = sin.relocations.size();
+    sout->flags = sin.type | sin.attributes;
+    sout->reserved1 = indirectSymbolIndex(sin, indirectSymRunningIndex);
+    sout->reserved2 = indirectSymbolElementSize(sin);
+    relOffset += sin.relocations.size() * sizeof(any_relocation_info);
+    if (_swap)
+      swapStruct(*sout);
+    ++sout;
+  }
+  lc = next;
+  return llvm::Error();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Segment &seg : _file.segments) {
+    // Link edit has no sections and a custom range of address, so handle it
+    // specially.
+    SegExtraInfo &segInfo = _segInfo[&seg];
+    if (seg.name.equals("__LINKEDIT")) {
+      size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+      typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+      cmd->cmd = T::LC;
+      cmd->cmdsize = sizeof(typename T::command);
+      uint8_t *next = lc + cmd->cmdsize;
+      setString16("__LINKEDIT", cmd->segname);
+      cmd->vmaddr   = _addressOfLinkEdit;
+      cmd->vmsize   = llvm::alignTo(linkeditSize, _file.pageSize);
+      cmd->fileoff  = _startOfLinkEdit;
+      cmd->filesize = linkeditSize;
+      cmd->initprot = seg.init_access;
+      cmd->maxprot  = seg.max_access;
+      cmd->nsects   = 0;
+      cmd->flags    = 0;
+      if (_swap)
+        swapStruct(*cmd);
+      lc = next;
+      continue;
+    }
+    // Write segment command with trailing sections.
+    typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+    cmd->cmd = T::LC;
+    cmd->cmdsize = sizeof(typename T::command)
+                        + segInfo.sections.size() * sizeof(typename T::section);
+    uint8_t *next = lc + cmd->cmdsize;
+    setString16(seg.name, cmd->segname);
+    cmd->vmaddr   = seg.address;
+    cmd->vmsize   = seg.size;
+    cmd->fileoff  = segInfo.fileOffset;
+    cmd->filesize = segInfo.fileSize;
+    cmd->initprot = seg.init_access;
+    cmd->maxprot  = seg.max_access;
+    cmd->nsects   = segInfo.sections.size();
+    cmd->flags    = 0;
+    if (_swap)
+      swapStruct(*cmd);
+    typename T::section *sect = reinterpret_cast<typename T::section*>
+                                               (lc+sizeof(typename T::command));
+    for (const Section *section : segInfo.sections) {
+      setString16(section->sectionName, sect->sectname);
+      setString16(section->segmentName, sect->segname);
+      sect->addr      = section->address;
+      sect->size      = section->content.size();
+      if (isZeroFillSection(section->type))
+        sect->offset  = 0;
+      else
+        sect->offset  = section->address - seg.address + segInfo.fileOffset;
+      sect->align     = llvm::Log2_32(section->alignment);
+      sect->reloff    = 0;
+      sect->nreloc    = 0;
+      sect->flags     = section->type | section->attributes;
+      sect->reserved1 = indirectSymbolIndex(*section, indirectSymRunningIndex);
+      sect->reserved2 = indirectSymbolElementSize(*section);
+      if (_swap)
+        swapStruct(*sect);
+      ++sect;
+    }
+    lc = reinterpret_cast<uint8_t*>(next);
+  }
+  return llvm::Error();
+}
+
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+                                       bool _swap,
+                                       uint8_t *&lc) {
+  if (!_file.hasMinVersionLoadCommand)
+    return;
+  version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+  switch (_file.os) {
+    case MachOLinkingContext::OS::unknown:
+      vm->cmd     = _file.minOSVersionKind;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = 0;
+      break;
+    case MachOLinkingContext::OS::macOSX:
+      vm->cmd     = LC_VERSION_MIN_MACOSX;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = _file.sdkVersion;
+      break;
+    case MachOLinkingContext::OS::iOS:
+    case MachOLinkingContext::OS::iOS_simulator:
+      vm->cmd     = LC_VERSION_MIN_IPHONEOS;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = _file.sdkVersion;
+      break;
+  }
+  if (_swap)
+    swapStruct(*vm);
+  lc += sizeof(version_min_command);
+}
+
+llvm::Error MachOFileLayout::writeLoadCommands() {
+  uint8_t *lc = &_buffer[_startOfLoadCommands];
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have one unnamed segment which holds all sections.
+    if (_is64) {
+     if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc))
+       return ec;
+    } else {
+      if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc))
+        return ec;
+    }
+    // Add LC_SYMTAB with symbol table info
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.localSymbols.size() + _file.globalSymbols.size()
+                                            + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+    lc += sizeof(symtab_command);
+
+    // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+    // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+    writeVersionMinLoadCommand(_file, _swap, lc);
+
+    // Add LC_FUNCTION_STARTS if needed.
+    if (_functionStartsSize != 0) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_FUNCTION_STARTS;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfFunctionStarts;
+      dl->datasize = _functionStartsSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+
+    // Add LC_DATA_IN_CODE if requested.
+    if (_file.generateDataInCodeLoadCommand) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_DATA_IN_CODE;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfDataInCode;
+      dl->datasize = _dataInCodeSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+  } else {
+    // Final linked images have sections under segments.
+    if (_is64) {
+      if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc))
+        return ec;
+    } else {
+      if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc))
+        return ec;
+    }
+
+    // Add LC_ID_DYLIB command for dynamic libraries.
+    if (_file.fileType == llvm::MachO::MH_DYLIB) {
+      dylib_command *dc = reinterpret_cast<dylib_command*>(lc);
+      StringRef path = _file.installName;
+      uint32_t size = sizeof(dylib_command) + pointerAlign(path.size() + 1);
+      dc->cmd                         = LC_ID_DYLIB;
+      dc->cmdsize                     = size;
+      dc->dylib.name                  = sizeof(dylib_command); // offset
+      // needs to be some constant value different than the one in LC_LOAD_DYLIB
+      dc->dylib.timestamp             = 1;
+      dc->dylib.current_version       = _file.currentVersion;
+      dc->dylib.compatibility_version = _file.compatVersion;
+      if (_swap)
+        swapStruct(*dc);
+      memcpy(lc + sizeof(dylib_command), path.begin(), path.size());
+      lc[sizeof(dylib_command) + path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_DYLD_INFO_ONLY.
+    dyld_info_command* di = reinterpret_cast<dyld_info_command*>(lc);
+    di->cmd            = LC_DYLD_INFO_ONLY;
+    di->cmdsize        = sizeof(dyld_info_command);
+    di->rebase_off     = _rebaseInfo.size() ? _startOfRebaseInfo : 0;
+    di->rebase_size    = _rebaseInfo.size();
+    di->bind_off       = _bindingInfo.size() ? _startOfBindingInfo : 0;
+    di->bind_size      = _bindingInfo.size();
+    di->weak_bind_off  = 0;
+    di->weak_bind_size = 0;
+    di->lazy_bind_off  = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
+    di->lazy_bind_size = _lazyBindingInfo.size();
+    di->export_off     = _exportTrie.size() ? _startOfExportTrie : 0;
+    di->export_size    = _exportTrie.size();
+    if (_swap)
+      swapStruct(*di);
+    lc += sizeof(dyld_info_command);
+
+    // Add LC_SYMTAB with symbol table info.
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.localSymbols.size() + _file.globalSymbols.size()
+                                            + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+    lc += sizeof(symtab_command);
+
+    // Add LC_DYSYMTAB
+    if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+      dysymtab_command* dst = reinterpret_cast<dysymtab_command*>(lc);
+      dst->cmd            = LC_DYSYMTAB;
+      dst->cmdsize        = sizeof(dysymtab_command);
+      dst->ilocalsym      = _symbolTableLocalsStartIndex;
+      dst->nlocalsym      = _file.localSymbols.size();
+      dst->iextdefsym     = _symbolTableGlobalsStartIndex;
+      dst->nextdefsym     = _file.globalSymbols.size();
+      dst->iundefsym      = _symbolTableUndefinesStartIndex;
+      dst->nundefsym      = _file.undefinedSymbols.size();
+      dst->tocoff         = 0;
+      dst->ntoc           = 0;
+      dst->modtaboff      = 0;
+      dst->nmodtab        = 0;
+      dst->extrefsymoff   = 0;
+      dst->nextrefsyms    = 0;
+      dst->indirectsymoff = _startOfIndirectSymbols;
+      dst->nindirectsyms  = _indirectSymbolTableCount;
+      dst->extreloff      = 0;
+      dst->nextrel        = 0;
+      dst->locreloff      = 0;
+      dst->nlocrel        = 0;
+      if (_swap)
+        swapStruct(*dst);
+      lc += sizeof(dysymtab_command);
+    }
+
+    // If main executable, add LC_LOAD_DYLINKER
+    if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+      // Build LC_LOAD_DYLINKER load command.
+      uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
+      dylinker_command* dl = reinterpret_cast<dylinker_command*>(lc);
+      dl->cmd              = LC_LOAD_DYLINKER;
+      dl->cmdsize          = size;
+      dl->name             = sizeof(dylinker_command); // offset
+      if (_swap)
+        swapStruct(*dl);
+      memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
+      lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+    // LC_VERSION_MIN_TVOS
+    writeVersionMinLoadCommand(_file, _swap, lc);
+
+    // Add LC_SOURCE_VERSION
+    {
+      // Note, using a temporary here to appease UB as we may not be aligned
+      // enough for a struct containing a uint64_t when emitting a 32-bit binary
+      source_version_command sv;
+      sv.cmd       = LC_SOURCE_VERSION;
+      sv.cmdsize   = sizeof(source_version_command);
+      sv.version   = _file.sourceVersion;
+      if (_swap)
+        swapStruct(sv);
+      memcpy(lc, &sv, sizeof(source_version_command));
+      lc += sizeof(source_version_command);
+    }
+
+    // If main executable, add LC_MAIN.
+    if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+      // Build LC_MAIN load command.
+      // Note, using a temporary here to appease UB as we may not be aligned
+      // enough for a struct containing a uint64_t when emitting a 32-bit binary
+      entry_point_command ep;
+      ep.cmd       = LC_MAIN;
+      ep.cmdsize   = sizeof(entry_point_command);
+      ep.entryoff  = _file.entryAddress - _seg1addr;
+      ep.stacksize = _file.stackSize;
+      if (_swap)
+        swapStruct(ep);
+      memcpy(lc, &ep, sizeof(entry_point_command));
+      lc += sizeof(entry_point_command);
+    }
+
+    // Add LC_LOAD_DYLIB commands
+    for (const DependentDylib &dep : _file.dependentDylibs) {
+      dylib_command* dc = reinterpret_cast<dylib_command*>(lc);
+      uint32_t size = sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+      dc->cmd                         = dep.kind;
+      dc->cmdsize                     = size;
+      dc->dylib.name                  = sizeof(dylib_command); // offset
+      // needs to be some constant value different than the one in LC_ID_DYLIB
+      dc->dylib.timestamp             = 2;
+      dc->dylib.current_version       = dep.currentVersion;
+      dc->dylib.compatibility_version = dep.compatVersion;
+      if (_swap)
+        swapStruct(*dc);
+      memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());
+      lc[sizeof(dylib_command)+dep.path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_RPATH
+    for (const StringRef &path : _file.rpaths) {
+      rpath_command *rpc = reinterpret_cast<rpath_command *>(lc);
+      uint32_t size = pointerAlign(sizeof(rpath_command) + path.size() + 1);
+      rpc->cmd                         = LC_RPATH;
+      rpc->cmdsize                     = size;
+      rpc->path                        = sizeof(rpath_command); // offset
+      if (_swap)
+        swapStruct(*rpc);
+      memcpy(lc+sizeof(rpath_command), path.begin(), path.size());
+      lc[sizeof(rpath_command)+path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_FUNCTION_STARTS if needed.
+    if (_functionStartsSize != 0) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_FUNCTION_STARTS;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfFunctionStarts;
+      dl->datasize = _functionStartsSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+
+    // Add LC_DATA_IN_CODE if requested.
+    if (_file.generateDataInCodeLoadCommand) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_DATA_IN_CODE;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfDataInCode;
+      dl->datasize = _dataInCodeSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+  }
+  return llvm::Error();
+}
+
+void MachOFileLayout::writeSectionContent() {
+  for (const Section &s : _file.sections) {
+    // Copy all section content to output buffer.
+    if (isZeroFillSection(s.type))
+      continue;
+    if (s.content.empty())
+      continue;
+    uint32_t offset = _sectInfo[&s].fileOffset;
+    uint8_t *p = &_buffer[offset];
+    memcpy(p, &s.content[0], s.content.size());
+    p += s.content.size();
+  }
+}
+
+void MachOFileLayout::writeRelocations() {
+  uint32_t relOffset = _startOfRelocations;
+  for (Section sect : _file.sections) {
+    for (Relocation r : sect.relocations) {
+      any_relocation_info* rb = reinterpret_cast<any_relocation_info*>(
+                                                           &_buffer[relOffset]);
+      *rb = packRelocation(r, _swap, _bigEndianArch);
+      relOffset += sizeof(any_relocation_info);
+    }
+  }
+}
+
+void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
+                                   uint32_t &symOffset, uint32_t &strOffset) {
+  for (const Symbol &sym : symbols) {
+    if (_is64) {
+      nlist_64* nb = reinterpret_cast<nlist_64*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist_64);
+    } else {
+      nlist* nb = reinterpret_cast<nlist*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist);
+    }
+    memcpy(&_buffer[strOffset], sym.name.begin(), sym.name.size());
+    strOffset += sym.name.size();
+    _buffer[strOffset++] ='\0'; // Strings in table have nul terminator.
+  }
+}
+
+void MachOFileLayout::writeFunctionStartsInfo() {
+  if (!_functionStartsSize)
+    return;
+  memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(),
+         _functionStartsSize);
+}
+
+void MachOFileLayout::writeDataInCodeInfo() {
+  uint32_t offset = _startOfDataInCode;
+  for (const DataInCode &entry : _file.dataInCode) {
+    data_in_code_entry *dst = reinterpret_cast<data_in_code_entry*>(
+                                                             &_buffer[offset]);
+    dst->offset = entry.offset;
+    dst->length = entry.length;
+    dst->kind   = entry.kind;
+    if (_swap)
+      swapStruct(*dst);
+    offset += sizeof(data_in_code_entry);
+  }
+}
+
+void MachOFileLayout::writeSymbolTable() {
+  // Write symbol table and symbol strings in parallel.
+  uint32_t symOffset = _startOfSymbols;
+  uint32_t strOffset = _startOfSymbolStrings;
+  _buffer[strOffset++] = '\0'; // Reserve n_strx offset of zero to mean no name.
+  appendSymbols(_file.localSymbols, symOffset, strOffset);
+  appendSymbols(_file.globalSymbols, symOffset, strOffset);
+  appendSymbols(_file.undefinedSymbols, symOffset, strOffset);
+  // Write indirect symbol table array.
+  uint32_t *indirects = reinterpret_cast<uint32_t*>
+                                            (&_buffer[_startOfIndirectSymbols]);
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have sections in same order as input normalized file.
+    for (const Section &section : _file.sections) {
+      for (uint32_t index : section.indirectSymbols) {
+        if (_swap)
+          *indirects++ = llvm::sys::getSwappedBytes(index);
+        else
+          *indirects++ = index;
+      }
+    }
+  } else {
+    // Final linked images must sort sections from normalized file.
+    for (const Segment &seg : _file.segments) {
+      SegExtraInfo &segInfo = _segInfo[&seg];
+      for (const Section *section : segInfo.sections) {
+        for (uint32_t index : section->indirectSymbols) {
+          if (_swap)
+            *indirects++ = llvm::sys::getSwappedBytes(index);
+          else
+            *indirects++ = index;
+        }
+      }
+    }
+  }
+}
+
+void MachOFileLayout::writeRebaseInfo() {
+  memcpy(&_buffer[_startOfRebaseInfo], _rebaseInfo.bytes(), _rebaseInfo.size());
+}
+
+void MachOFileLayout::writeBindingInfo() {
+  memcpy(&_buffer[_startOfBindingInfo],
+                                    _bindingInfo.bytes(), _bindingInfo.size());
+}
+
+void MachOFileLayout::writeLazyBindingInfo() {
+  memcpy(&_buffer[_startOfLazyBindingInfo],
+                            _lazyBindingInfo.bytes(), _lazyBindingInfo.size());
+}
+
+void MachOFileLayout::writeExportInfo() {
+  memcpy(&_buffer[_startOfExportTrie], _exportTrie.bytes(), _exportTrie.size());
+}
+
+void MachOFileLayout::buildLinkEditInfo() {
+  buildRebaseInfo();
+  buildBindInfo();
+  buildLazyBindInfo();
+  buildExportTrie();
+  computeSymbolTableSizes();
+  computeFunctionStartsSize();
+  computeDataInCodeSize();
+}
+
+void MachOFileLayout::buildSectionRelocations() {
+
+}
+
+void MachOFileLayout::buildRebaseInfo() {
+  // TODO: compress rebasing info.
+  for (const RebaseLocation& entry : _file.rebasingInfo) {
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_TYPE_IMM | entry.kind);
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                            | entry.segIndex);
+    _rebaseInfo.append_uleb128(entry.segOffset);
+    _rebaseInfo.append_uleb128(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1);
+  }
+  _rebaseInfo.append_byte(REBASE_OPCODE_DONE);
+  _rebaseInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildBindInfo() {
+  // TODO: compress bind info.
+  uint64_t lastAddend = 0;
+  for (const BindLocation& entry : _file.bindingInfo) {
+    _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+    _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                            | entry.segIndex);
+    _bindingInfo.append_uleb128(entry.segOffset);
+    if (entry.ordinal > 0)
+      _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+                               (entry.ordinal & 0xF));
+    else
+      _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+                               (entry.ordinal & 0xF));
+    _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+    _bindingInfo.append_string(entry.symbolName);
+    if (entry.addend != lastAddend) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+      _bindingInfo.append_sleb128(entry.addend);
+      lastAddend = entry.addend;
+    }
+    _bindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+  }
+  _bindingInfo.append_byte(BIND_OPCODE_DONE);
+  _bindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildLazyBindInfo() {
+  for (const BindLocation& entry : _file.lazyBindingInfo) {
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                            | entry.segIndex);
+    _lazyBindingInfo.append_uleb128Fixed(entry.segOffset, 5);
+    if (entry.ordinal > 0)
+      _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+                                   (entry.ordinal & 0xF));
+    else
+      _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+                                   (entry.ordinal & 0xF));
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+    _lazyBindingInfo.append_string(entry.symbolName);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_DONE);
+  }
+  _lazyBindingInfo.append_byte(BIND_OPCODE_DONE);
+  _lazyBindingInfo.align(_is64 ? 8 : 4);
+}
+
+void TrieNode::addSymbol(const Export& entry,
+                         BumpPtrAllocator &allocator,
+                         std::vector<TrieNode*> &allNodes) {
+  StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+  for (TrieEdge &edge : _children) {
+    StringRef edgeStr = edge._subString;
+    if (partialStr.startswith(edgeStr)) {
+      // Already have matching edge, go down that path.
+      edge._child->addSymbol(entry, allocator, allNodes);
+      return;
+    }
+    // See if string has commmon prefix with existing edge.
+    for (int n=edgeStr.size()-1; n > 0; --n) {
+      if (partialStr.substr(0, n).equals(edgeStr.substr(0, n))) {
+        // Splice in new node:  was A -> C,  now A -> B -> C
+        StringRef bNodeStr = edge._child->_cummulativeString;
+        bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
+        auto *bNode = new (allocator) TrieNode(bNodeStr);
+        allNodes.push_back(bNode);
+        TrieNode* cNode = edge._child;
+        StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
+        StringRef bcEdgeStr = edgeStr.substr(n).copy(allocator);
+        DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                        << "splice in TrieNode('" << bNodeStr
+                        << "') between edge '"
+                        << abEdgeStr << "' and edge='"
+                        << bcEdgeStr<< "'\n");
+        TrieEdge& abEdge = edge;
+        abEdge._subString = abEdgeStr;
+        abEdge._child = bNode;
+        auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
+        bNode->_children.insert(bNode->_children.end(), bcEdge);
+        bNode->addSymbol(entry, allocator, allNodes);
+        return;
+      }
+    }
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+    assert(entry.otherOffset != 0);
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+    assert(entry.otherOffset != 0);
+  }
+  // No commonality with any existing child, make a new edge.
+  auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+  auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
+  _children.insert(_children.end(), newEdge);
+  DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                   << "new TrieNode('" << entry.name << "') with edge '"
+                   << partialStr << "' from node='"
+                   << _cummulativeString << "'\n");
+  newNode->_address = entry.offset;
+  newNode->_flags = entry.flags | entry.kind;
+  newNode->_other = entry.otherOffset;
+  if ((entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && !entry.otherName.empty())
+    newNode->_importedName = entry.otherName.copy(allocator);
+  newNode->_hasExportInfo = true;
+  allNodes.push_back(newNode);
+}
+
+bool TrieNode::updateOffset(uint32_t& offset) {
+  uint32_t nodeSize = 1; // Length when no export info
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      nodeSize = llvm::getULEB128Size(_flags);
+      nodeSize += llvm::getULEB128Size(_other); // Other contains ordinal.
+      nodeSize += _importedName.size();
+      ++nodeSize; // Trailing zero in imported name.
+    } else {
+      nodeSize = llvm::getULEB128Size(_flags) + llvm::getULEB128Size(_address);
+      if (_flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+        nodeSize += llvm::getULEB128Size(_other);
+    }
+    // Overall node size so far is uleb128 of export info + actual export info.
+    nodeSize += llvm::getULEB128Size(nodeSize);
+  }
+  // Compute size of all child edges.
+  ++nodeSize; // Byte for number of chidren.
+  for (TrieEdge &edge : _children) {
+    nodeSize += edge._subString.size() + 1 // String length.
+              + llvm::getULEB128Size(edge._child->_trieOffset); // Offset len.
+  }
+  // On input, 'offset' is new prefered location for this node.
+  bool result = (_trieOffset != offset);
+  // Store new location in node object for use by parents.
+  _trieOffset = offset;
+  // Update offset for next iteration.
+  offset += nodeSize;
+  // Return true if _trieOffset was changed.
+  return result;
+}
+
+void TrieNode::appendToByteBuffer(ByteBuffer &out) {
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      if (!_importedName.empty()) {
+        // nodes with re-export info: size, flags, ordinal, import-name
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other)
+                          + _importedName.size() + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_string(_importedName);
+      } else {
+        // nodes without re-export info: size, flags, ordinal, empty-string
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other) + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_byte(0);
+      }
+    } else if ( _flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+      // Nodes with export info: size, flags, address, other
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address)
+                        + llvm::getULEB128Size(_other);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+      out.append_uleb128(_other);
+    } else {
+      // Nodes with export info: size, flags, address
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+    }
+  } else {
+    // Node with no export info.
+    uint32_t nodeSize = 0;
+    out.append_byte(nodeSize);
+  }
+  // Add number of children.
+  assert(_children.size() < 256);
+  out.append_byte(_children.size());
+  // Append each child edge substring and node offset.
+  for (TrieEdge &edge : _children) {
+    out.append_string(edge._subString);
+    out.append_uleb128(edge._child->_trieOffset);
+  }
+}
+
+void MachOFileLayout::buildExportTrie() {
+  if (_file.exportInfo.empty())
+    return;
+
+  // For all temporary strings and objects used building trie.
+  BumpPtrAllocator allocator;
+
+  // Build trie of all exported symbols.
+  auto *rootNode = new (allocator) TrieNode(StringRef());
+  std::vector<TrieNode*> allNodes;
+  allNodes.reserve(_file.exportInfo.size()*2);
+  allNodes.push_back(rootNode);
+  for (const Export& entry : _file.exportInfo) {
+    rootNode->addSymbol(entry, allocator, allNodes);
+  }
+
+  // Assign each node in the vector an offset in the trie stream, iterating
+  // until all uleb128 sizes have stabilized.
+  bool more;
+  do {
+    uint32_t offset = 0;
+    more = false;
+    for (TrieNode* node : allNodes) {
+      if (node->updateOffset(offset))
+        more = true;
+    }
+  } while (more);
+
+  // Serialize trie to ByteBuffer.
+  for (TrieNode* node : allNodes) {
+    node->appendToByteBuffer(_exportTrie);
+  }
+  _exportTrie.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::computeSymbolTableSizes() {
+  // MachO symbol tables have three ranges: locals, globals, and undefines
+  const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
+  _symbolTableSize = nlistSize * (_file.localSymbols.size()
+                                + _file.globalSymbols.size()
+                                + _file.undefinedSymbols.size());
+  _symbolStringPoolSize = 1; // Always reserve 1-byte for the empty string.
+  for (const Symbol &sym : _file.localSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.globalSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.undefinedSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  _symbolTableLocalsStartIndex = 0;
+  _symbolTableGlobalsStartIndex = _file.localSymbols.size();
+  _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex
+                                    + _file.globalSymbols.size();
+
+  _indirectSymbolTableCount = 0;
+  for (const Section &sect : _file.sections) {
+    _indirectSymbolTableCount += sect.indirectSymbols.size();
+  }
+}
+
+void MachOFileLayout::computeFunctionStartsSize() {
+  _functionStartsSize = _file.functionStarts.size();
+}
+
+void MachOFileLayout::computeDataInCodeSize() {
+  _dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
+}
+
+void MachOFileLayout::writeLinkEditContent() {
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    writeRelocations();
+    writeFunctionStartsInfo();
+    writeDataInCodeInfo();
+    writeSymbolTable();
+  } else {
+    writeRebaseInfo();
+    writeBindingInfo();
+    writeLazyBindingInfo();
+    // TODO: add weak binding info
+    writeExportInfo();
+    writeFunctionStartsInfo();
+    writeDataInCodeInfo();
+    writeSymbolTable();
+  }
+}
+
+llvm::Error MachOFileLayout::writeBinary(StringRef path) {
+  // Check for pending error from constructor.
+  if (_ec)
+    return llvm::errorCodeToError(_ec);
+  // Create FileOutputBuffer with calculated size.
+  unsigned flags = 0;
+  if (_file.fileType != llvm::MachO::MH_OBJECT)
+    flags = llvm::FileOutputBuffer::F_executable;
+  ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
+      llvm::FileOutputBuffer::create(path, size(), flags);
+  if (std::error_code ec = fobOrErr.getError())
+    return llvm::errorCodeToError(ec);
+  std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
+  // Write content.
+  _buffer = fob->getBufferStart();
+  writeMachHeader();
+  if (auto ec = writeLoadCommands())
+    return ec;
+  writeSectionContent();
+  writeLinkEditContent();
+  fob->commit();
+
+  return llvm::Error();
+}
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path) {
+  MachOFileLayout layout(file);
+  return layout.writeBinary(path);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
new file mode 100644 (file)
index 0000000..4775c75
--- /dev/null
@@ -0,0 +1,1425 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory Atoms to in-memory normalized mach-o.
+///
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+///                        ^
+///                        |
+///                        |
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+
+#include "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+#include <map>
+#include <system_error>
+
+using llvm::StringRef;
+using llvm::isa;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using namespace lld;
+
+namespace {
+
+struct AtomInfo {
+  const DefinedAtom  *atom;
+  uint64_t            offsetInSection;
+};
+
+struct SectionInfo {
+  SectionInfo(StringRef seg, StringRef sect, SectionType type,
+              const MachOLinkingContext &ctxt, uint32_t attr,
+              bool relocsToDefinedCanBeImplicit);
+
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               type;
+  uint32_t                  attributes;
+  uint64_t                  address;
+  uint64_t                  size;
+  uint16_t                  alignment;
+
+  /// If this is set, the any relocs in this section which point to defined
+  /// addresses can be implicitly generated.  This is the case for the
+  /// __eh_frame section where references to the function can be implicit if the
+  /// function is defined.
+  bool                      relocsToDefinedCanBeImplicit;
+
+
+  std::vector<AtomInfo>     atomsAndOffsets;
+  uint32_t                  normalizedSectionIndex;
+  uint32_t                  finalSectionIndex;
+};
+
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
+                         const MachOLinkingContext &ctxt, uint32_t attrs,
+                         bool relocsToDefinedCanBeImplicit)
+ : segmentName(sg), sectionName(sct), type(t), attributes(attrs),
+                 address(0), size(0), alignment(1),
+                 relocsToDefinedCanBeImplicit(relocsToDefinedCanBeImplicit),
+                 normalizedSectionIndex(0), finalSectionIndex(0) {
+  uint16_t align = 1;
+  if (ctxt.sectionAligned(segmentName, sectionName, align)) {
+    alignment = align;
+  }
+}
+
+struct SegmentInfo {
+  SegmentInfo(StringRef name);
+
+  StringRef                  name;
+  uint64_t                   address;
+  uint64_t                   size;
+  uint32_t                   init_access;
+  uint32_t                   max_access;
+  std::vector<SectionInfo*>  sections;
+  uint32_t                   normalizedSegmentIndex;
+};
+
+SegmentInfo::SegmentInfo(StringRef n)
+ : name(n), address(0), size(0), init_access(0), max_access(0),
+   normalizedSegmentIndex(0) {
+}
+
+class Util {
+public:
+  Util(const MachOLinkingContext &ctxt)
+      : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
+        _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {}
+  ~Util();
+
+  void      processDefinedAtoms(const lld::File &atomFile);
+  void      processAtomAttributes(const DefinedAtom *atom);
+  void      assignAtomToSection(const DefinedAtom *atom);
+  void      organizeSections();
+  void      assignAddressesToSections(const NormalizedFile &file);
+  uint32_t  fileFlags();
+  void      copySegmentInfo(NormalizedFile &file);
+  void      copySectionInfo(NormalizedFile &file);
+  void      updateSectionInfo(NormalizedFile &file);
+  void      buildAtomToAddressMap();
+  llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
+  void      addExportInfo(const lld::File &, NormalizedFile &file);
+  void      addSectionRelocs(const lld::File &, NormalizedFile &file);
+  void      addFunctionStarts(const lld::File &, NormalizedFile &file);
+  void      buildDataInCodeArray(const lld::File &, NormalizedFile &file);
+  void      addDependentDylibs(const lld::File &, NormalizedFile &file);
+  void      copyEntryPointAddress(NormalizedFile &file);
+  void      copySectionContent(NormalizedFile &file);
+
+  bool allSourceFilesHaveMinVersions() const {
+    return _allSourceFilesHaveMinVersions;
+  }
+
+  uint32_t minVersion() const {
+    return _minVersion;
+  }
+
+  LoadCommandType minVersionCommandType() const {
+    return _minVersionCommandType;
+  }
+
+private:
+  typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
+  typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
+
+  struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
+  typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
+
+  SectionInfo *sectionForAtom(const DefinedAtom*);
+  SectionInfo *getRelocatableSection(DefinedAtom::ContentType type);
+  SectionInfo *getFinalSection(DefinedAtom::ContentType type);
+  void         appendAtom(SectionInfo *sect, const DefinedAtom *atom);
+  SegmentInfo *segmentForName(StringRef segName);
+  void         layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
+  void         layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &);
+  void         copySectionContent(SectionInfo *si, ContentBytes &content);
+  uint16_t     descBits(const DefinedAtom* atom);
+  int          dylibOrdinal(const SharedLibraryAtom *sa);
+  void         segIndexForSection(const SectionInfo *sect,
+                             uint8_t &segmentIndex, uint64_t &segmentStartAddr);
+  const Atom  *targetOfLazyPointer(const DefinedAtom *lpAtom);
+  const Atom  *targetOfStub(const DefinedAtom *stubAtom);
+  llvm::Error getSymbolTableRegion(const DefinedAtom* atom,
+                                   bool &inGlobalsRegion,
+                                   SymbolScope &symbolScope);
+  void         appendSection(SectionInfo *si, NormalizedFile &file);
+  uint32_t     sectionIndexForAtom(const Atom *atom);
+
+  typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
+  struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
+  struct AtomSorter {
+    bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
+  };
+  struct SegmentSorter {
+    bool operator()(const SegmentInfo *left, const SegmentInfo *right);
+    static unsigned weight(const SegmentInfo *);
+  };
+  struct TextSectionSorter {
+    bool operator()(const SectionInfo *left, const SectionInfo *right);
+    static unsigned weight(const SectionInfo *);
+  };
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler          &_archHandler;
+  llvm::BumpPtrAllocator        _allocator;
+  std::vector<SectionInfo*>     _sectionInfos;
+  std::vector<SegmentInfo*>     _segmentInfos;
+  TypeToSection                 _sectionMap;
+  std::vector<SectionInfo*>     _customSections;
+  AtomToAddress                 _atomToAddress;
+  DylibPathToInfo               _dylibInfo;
+  const DefinedAtom            *_entryAtom;
+  AtomToIndex                   _atomToSymbolIndex;
+  std::vector<const Atom *>     _machHeaderAliasAtoms;
+  bool                          _hasTLVDescriptors;
+  bool                          _subsectionsViaSymbols;
+  bool                          _allSourceFilesHaveMinVersions = true;
+  LoadCommandType               _minVersionCommandType = (LoadCommandType)0;
+  uint32_t                      _minVersion = 0;
+};
+
+Util::~Util() {
+  // The SectionInfo structs are BumpPtr allocated, but atomsAndOffsets needs
+  // to be deleted.
+  for (SectionInfo *si : _sectionInfos) {
+    // clear() destroys vector elements, but does not deallocate.
+    // Instead use swap() to deallocate vector buffer.
+    std::vector<AtomInfo> empty;
+    si->atomsAndOffsets.swap(empty);
+  }
+  // The SegmentInfo structs are BumpPtr allocated, but sections needs
+  // to be deleted.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    std::vector<SectionInfo*> empty2;
+    sgi->sections.swap(empty2);
+  }
+}
+
+SectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) {
+  StringRef segmentName;
+  StringRef sectionName;
+  SectionType sectionType;
+  SectionAttr sectionAttrs;
+  bool relocsToDefinedCanBeImplicit;
+
+  // Use same table used by when parsing .o files.
+  relocatableSectionInfoForContentType(type, segmentName, sectionName,
+                                       sectionType, sectionAttrs,
+                                       relocsToDefinedCanBeImplicit);
+  // If we already have a SectionInfo with this name, re-use it.
+  // This can happen if two ContentType map to the same mach-o section.
+  for (auto sect : _sectionMap) {
+    if (sect.second->sectionName.equals(sectionName) &&
+        sect.second->segmentName.equals(segmentName)) {
+      return sect.second;
+    }
+  }
+  // Otherwise allocate new SectionInfo object.
+  auto *sect = new (_allocator)
+      SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs,
+                  relocsToDefinedCanBeImplicit);
+  _sectionInfos.push_back(sect);
+  _sectionMap[type] = sect;
+  return sect;
+}
+
+#define ENTRY(seg, sect, type, atomType) \
+  {seg, sect, type, DefinedAtom::atomType }
+
+struct MachOFinalSectionFromAtomType {
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               sectionType;
+  DefinedAtom::ContentType  atomType;
+};
+
+const MachOFinalSectionFromAtomType sectsToAtomType[] = {
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeCode),
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeMachHeader),
+  ENTRY("__TEXT", "__cstring",        S_CSTRING_LITERALS, typeCString),
+  ENTRY("__TEXT", "__ustring",        S_REGULAR,          typeUTF16String),
+  ENTRY("__TEXT", "__const",          S_REGULAR,          typeConstant),
+  ENTRY("__TEXT", "__const",          S_4BYTE_LITERALS,   typeLiteral4),
+  ENTRY("__TEXT", "__const",          S_8BYTE_LITERALS,   typeLiteral8),
+  ENTRY("__TEXT", "__const",          S_16BYTE_LITERALS,  typeLiteral16),
+  ENTRY("__TEXT", "__stubs",          S_SYMBOL_STUBS,     typeStub),
+  ENTRY("__TEXT", "__stub_helper",    S_REGULAR,          typeStubHelper),
+  ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR,          typeLSDA),
+  ENTRY("__TEXT", "__eh_frame",       S_COALESCED,        typeCFI),
+  ENTRY("__TEXT", "__unwind_info",    S_REGULAR,          typeProcessedUnwindInfo),
+  ENTRY("__DATA", "__data",           S_REGULAR,          typeData),
+  ENTRY("__DATA", "__const",          S_REGULAR,          typeConstData),
+  ENTRY("__DATA", "__cfstring",       S_REGULAR,          typeCFString),
+  ENTRY("__DATA", "__la_symbol_ptr",  S_LAZY_SYMBOL_POINTERS,
+                                                          typeLazyPointer),
+  ENTRY("__DATA", "__mod_init_func",  S_MOD_INIT_FUNC_POINTERS,
+                                                          typeInitializerPtr),
+  ENTRY("__DATA", "__mod_term_func",  S_MOD_TERM_FUNC_POINTERS,
+                                                          typeTerminatorPtr),
+  ENTRY("__DATA", "__got",            S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__nl_symbol_ptr",  S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeNonLazyPointer),
+  ENTRY("__DATA", "__thread_vars",    S_THREAD_LOCAL_VARIABLES,
+                                                          typeThunkTLV),
+  ENTRY("__DATA", "__thread_data",    S_THREAD_LOCAL_REGULAR,
+                                                          typeTLVInitialData),
+  ENTRY("__DATA", "__thread_ptrs",    S_THREAD_LOCAL_VARIABLE_POINTERS,
+                                                          typeTLVInitializerPtr),
+  ENTRY("__DATA", "__thread_bss",     S_THREAD_LOCAL_ZEROFILL,
+                                                         typeTLVInitialZeroFill),
+  ENTRY("__DATA", "__bss",            S_ZEROFILL,         typeZeroFill),
+  ENTRY("__DATA", "__interposing",    S_INTERPOSING,      typeInterposingTuples),
+};
+#undef ENTRY
+
+SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
+  for (auto &p : sectsToAtomType) {
+    if (p.atomType != atomType)
+      continue;
+    SectionAttr sectionAttrs = 0;
+    switch (atomType) {
+    case DefinedAtom::typeMachHeader:
+    case DefinedAtom::typeCode:
+    case DefinedAtom::typeStub:
+    case DefinedAtom::typeStubHelper:
+      sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
+      break;
+    case DefinedAtom::typeThunkTLV:
+      _hasTLVDescriptors = true;
+      break;
+    default:
+      break;
+    }
+    // If we already have a SectionInfo with this name, re-use it.
+    // This can happen if two ContentType map to the same mach-o section.
+    for (auto sect : _sectionMap) {
+      if (sect.second->sectionName.equals(p.sectionName) &&
+          sect.second->segmentName.equals(p.segmentName)) {
+        return sect.second;
+      }
+    }
+    // Otherwise allocate new SectionInfo object.
+    auto *sect = new (_allocator) SectionInfo(
+        p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs,
+        /* relocsToDefinedCanBeImplicit */ false);
+    _sectionInfos.push_back(sect);
+    _sectionMap[atomType] = sect;
+    return sect;
+  }
+  llvm_unreachable("content type not yet supported");
+}
+
+SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
+  if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+    // Section for this atom is derived from content type.
+    DefinedAtom::ContentType type = atom->contentType();
+    auto pos = _sectionMap.find(type);
+    if ( pos != _sectionMap.end() )
+      return pos->second;
+    bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+    return rMode ? getRelocatableSection(type) : getFinalSection(type);
+  } else {
+    // This atom needs to be in a custom section.
+    StringRef customName = atom->customSectionName();
+    // Look to see if we have already allocated the needed custom section.
+    for(SectionInfo *sect : _customSections) {
+      const DefinedAtom *firstAtom = sect->atomsAndOffsets.front().atom;
+      if (firstAtom->customSectionName().equals(customName)) {
+        return sect;
+      }
+    }
+    // Not found, so need to create a new custom section.
+    size_t seperatorIndex = customName.find('/');
+    assert(seperatorIndex != StringRef::npos);
+    StringRef segName = customName.slice(0, seperatorIndex);
+    StringRef sectName = customName.drop_front(seperatorIndex + 1);
+    auto *sect =
+        new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx,
+                                     0, /* relocsToDefinedCanBeImplicit */ false);
+    _customSections.push_back(sect);
+    _sectionInfos.push_back(sect);
+    return sect;
+  }
+}
+
+void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
+  // Figure out offset for atom in this section given alignment constraints.
+  uint64_t offset = sect->size;
+  DefinedAtom::Alignment atomAlign = atom->alignment();
+  uint64_t align = atomAlign.value;
+  uint64_t requiredModulus = atomAlign.modulus;
+  uint64_t currentModulus = (offset % align);
+  if ( currentModulus != requiredModulus ) {
+    if ( requiredModulus > currentModulus )
+      offset += requiredModulus-currentModulus;
+    else
+      offset += align+requiredModulus-currentModulus;
+  }
+  // Record max alignment of any atom in this section.
+  if (align > sect->alignment)
+    sect->alignment = atomAlign.value;
+  // Assign atom to this section with this offset.
+  AtomInfo ai = {atom, offset};
+  sect->atomsAndOffsets.push_back(ai);
+  // Update section size to include this atom.
+  sect->size = offset + atom->size();
+}
+
+void Util::processDefinedAtoms(const lld::File &atomFile) {
+  for (const DefinedAtom *atom : atomFile.defined()) {
+    processAtomAttributes(atom);
+    assignAtomToSection(atom);
+  }
+}
+
+void Util::processAtomAttributes(const DefinedAtom *atom) {
+  if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+    // If the file doesn't use subsections via symbols, then make sure we don't
+    // add that flag to the final output file if we have a relocatable file.
+    if (!machoFile->subsectionsViaSymbols())
+      _subsectionsViaSymbols = false;
+
+    // All the source files must have min versions for us to output an object
+    // file with a min version.
+    if (auto v = machoFile->minVersion())
+      _minVersion = std::max(_minVersion, v);
+    else
+      _allSourceFilesHaveMinVersions = false;
+
+    // If we don't have a platform load command, but one of the source files
+    // does, then take the one from the file.
+    if (!_minVersionCommandType)
+      if (auto v = machoFile->minVersionLoadCommandKind())
+        _minVersionCommandType = v;
+  }
+}
+
+void Util::assignAtomToSection(const DefinedAtom *atom) {
+  if (atom->contentType() == DefinedAtom::typeMachHeader) {
+    _machHeaderAliasAtoms.push_back(atom);
+    // Assign atom to this section with this offset.
+    AtomInfo ai = {atom, 0};
+    sectionForAtom(atom)->atomsAndOffsets.push_back(ai);
+  } else if (atom->contentType() == DefinedAtom::typeDSOHandle)
+    _machHeaderAliasAtoms.push_back(atom);
+  else
+    appendAtom(sectionForAtom(atom), atom);
+}
+
+SegmentInfo *Util::segmentForName(StringRef segName) {
+  for (SegmentInfo *si : _segmentInfos) {
+    if ( si->name.equals(segName) )
+      return si;
+  }
+  auto *info = new (_allocator) SegmentInfo(segName);
+
+  // Set the initial segment protection.
+  if (segName.equals("__TEXT"))
+    info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
+  else if (segName.equals("__PAGEZERO"))
+    info->init_access = 0;
+  else if (segName.equals("__LINKEDIT"))
+    info->init_access = VM_PROT_READ;
+  else {
+    // All others default to read-write
+    info->init_access = VM_PROT_READ | VM_PROT_WRITE;
+  }
+
+  // Set max segment protection
+  // Note, its overkill to use a switch statement here, but makes it so much
+  // easier to use switch coverage to catch new cases.
+  switch (_ctx.os()) {
+    case lld::MachOLinkingContext::OS::unknown:
+    case lld::MachOLinkingContext::OS::macOSX:
+    case lld::MachOLinkingContext::OS::iOS_simulator:
+      if (segName.equals("__PAGEZERO")) {
+        info->max_access = 0;
+        break;
+      }
+      // All others default to all
+      info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+      break;
+    case lld::MachOLinkingContext::OS::iOS:
+      // iPhoneOS always uses same protection for max and initial
+      info->max_access = info->init_access;
+      break;
+  }
+  _segmentInfos.push_back(info);
+  return info;
+}
+
+unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
+ return llvm::StringSwitch<unsigned>(seg->name)
+    .Case("__PAGEZERO",  1)
+    .Case("__TEXT",      2)
+    .Case("__DATA",      3)
+    .Default(100);
+}
+
+bool Util::SegmentSorter::operator()(const SegmentInfo *left,
+                                  const SegmentInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
+ return llvm::StringSwitch<unsigned>(sect->sectionName)
+    .Case("__text",         1)
+    .Case("__stubs",        2)
+    .Case("__stub_helper",  3)
+    .Case("__const",        4)
+    .Case("__cstring",      5)
+    .Case("__unwind_info",  98)
+    .Case("__eh_frame",     99)
+    .Default(10);
+}
+
+bool Util::TextSectionSorter::operator()(const SectionInfo *left,
+                                         const SectionInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+void Util::organizeSections() {
+  // NOTE!: Keep this in sync with assignAddressesToSections.
+  switch (_ctx.outputMachOType()) {
+    case llvm::MachO::MH_EXECUTE:
+      // Main executables, need a zero-page segment
+      segmentForName("__PAGEZERO");
+      // Fall into next case.
+    case llvm::MachO::MH_DYLIB:
+    case llvm::MachO::MH_BUNDLE:
+      // All dynamic code needs TEXT segment to hold the load commands.
+      segmentForName("__TEXT");
+      break;
+    default:
+      break;
+  }
+  segmentForName("__LINKEDIT");
+
+  // Group sections into segments.
+  for (SectionInfo *si : _sectionInfos) {
+    SegmentInfo *seg = segmentForName(si->segmentName);
+    seg->sections.push_back(si);
+  }
+  // Sort segments.
+  std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
+
+  // Sort sections within segments.
+  for (SegmentInfo *seg : _segmentInfos) {
+    if (seg->name.equals("__TEXT")) {
+      std::sort(seg->sections.begin(), seg->sections.end(),
+                TextSectionSorter());
+    }
+  }
+
+  // Record final section indexes.
+  uint32_t segmentIndex = 0;
+  uint32_t sectionIndex = 1;
+  for (SegmentInfo *seg : _segmentInfos) {
+    seg->normalizedSegmentIndex = segmentIndex++;
+    for (SectionInfo *sect : seg->sections)
+      sect->finalSectionIndex = sectionIndex++;
+  }
+}
+
+void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
+  seg->address = addr;
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = llvm::alignTo(addr, sect->alignment);
+    addr = sect->address + sect->size;
+  }
+  seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+// __TEXT segment lays out backwards so padding is at front after load commands.
+void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
+                                                               uint64_t &addr) {
+  seg->address = addr;
+  // Walks sections starting at end to calculate padding for start.
+  int64_t taddr = 0;
+  for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
+    SectionInfo *sect = *it;
+    taddr -= sect->size;
+    taddr = taddr & (0 - sect->alignment);
+  }
+  int64_t padding = taddr - hlcSize;
+  while (padding < 0)
+    padding += _ctx.pageSize();
+  // Start assigning section address starting at padded offset.
+  addr += (padding + hlcSize);
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = llvm::alignTo(addr, sect->alignment);
+    addr = sect->address + sect->size;
+  }
+  seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+void Util::assignAddressesToSections(const NormalizedFile &file) {
+  // NOTE!: Keep this in sync with organizeSections.
+  size_t hlcSize = headerAndLoadCommandsSize(file);
+  uint64_t address = 0;
+  for (SegmentInfo *seg : _segmentInfos) {
+    if (seg->name.equals("__PAGEZERO")) {
+      seg->size = _ctx.pageZeroSize();
+      address += seg->size;
+    }
+    else if (seg->name.equals("__TEXT")) {
+      // _ctx.baseAddress()  == 0 implies it was either unspecified or
+      // pageZeroSize is also 0. In either case resetting address is safe.
+      address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
+      layoutSectionsInTextSegment(hlcSize, seg, address);
+    } else
+      layoutSectionsInSegment(seg, address);
+
+    address = llvm::alignTo(address, _ctx.pageSize());
+  }
+  DEBUG_WITH_TYPE("WriterMachO-norm",
+    llvm::dbgs() << "assignAddressesToSections()\n";
+    for (SegmentInfo *sgi : _segmentInfos) {
+      llvm::dbgs()  << "   address=" << llvm::format("0x%08llX", sgi->address)
+                    << ", size="  << llvm::format("0x%08llX", sgi->size)
+                    << ", segment-name='" << sgi->name
+                    << "'\n";
+      for (SectionInfo *si : sgi->sections) {
+        llvm::dbgs()<< "      addr="  << llvm::format("0x%08llX", si->address)
+                    << ", size="  << llvm::format("0x%08llX", si->size)
+                    << ", section-name='" << si->sectionName
+                    << "\n";
+      }
+    }
+  );
+}
+
+void Util::copySegmentInfo(NormalizedFile &file) {
+  for (SegmentInfo *sgi : _segmentInfos) {
+    Segment seg;
+    seg.name    = sgi->name;
+    seg.address = sgi->address;
+    seg.size    = sgi->size;
+    seg.init_access  = sgi->init_access;
+    seg.max_access  = sgi->max_access;
+    file.segments.push_back(seg);
+  }
+}
+
+void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
+   // Add new empty section to end of file.sections.
+  Section temp;
+  file.sections.push_back(std::move(temp));
+  Section* normSect = &file.sections.back();
+  // Copy fields to normalized section.
+  normSect->segmentName   = si->segmentName;
+  normSect->sectionName   = si->sectionName;
+  normSect->type          = si->type;
+  normSect->attributes    = si->attributes;
+  normSect->address       = si->address;
+  normSect->alignment     = si->alignment;
+  // Record where normalized section is.
+  si->normalizedSectionIndex = file.sections.size()-1;
+}
+
+void Util::copySectionContent(NormalizedFile &file) {
+  const bool r = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+
+  // Utility function for ArchHandler to find address of atom in output file.
+  auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
+    auto pos = _atomToAddress.find(&atom);
+    assert(pos != _atomToAddress.end());
+    return pos->second;
+  };
+
+  auto sectionAddrForAtom = [&] (const Atom &atom) -> uint64_t {
+    for (const SectionInfo *sectInfo : _sectionInfos)
+      for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets)
+        if (atomInfo.atom == &atom)
+          return sectInfo->address;
+    llvm_unreachable("atom not assigned to section");
+  };
+
+  for (SectionInfo *si : _sectionInfos) {
+    Section *normSect = &file.sections[si->normalizedSectionIndex];
+    if (isZeroFillSection(si->type)) {
+      const uint8_t *empty = nullptr;
+      normSect->content = llvm::makeArrayRef(empty, si->size);
+      continue;
+    }
+    // Copy content from atoms to content buffer for section.
+    llvm::MutableArrayRef<uint8_t> sectionContent;
+    if (si->size) {
+      uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+      sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size);
+      normSect->content = sectionContent;
+    }
+    for (AtomInfo &ai : si->atomsAndOffsets) {
+      if (!ai.atom->size()) {
+        assert(ai.atom->begin() == ai.atom->end() &&
+               "Cannot have references without content");
+        continue;
+      }
+      auto atomContent = sectionContent.slice(ai.offsetInSection,
+                                              ai.atom->size());
+      _archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
+                                       sectionAddrForAtom, _ctx.baseAddress(),
+                                       atomContent);
+    }
+  }
+}
+
+void Util::copySectionInfo(NormalizedFile &file) {
+  file.sections.reserve(_sectionInfos.size());
+  // Write sections grouped by segment.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    for (SectionInfo *si : sgi->sections) {
+      appendSection(si, file);
+    }
+  }
+}
+
+void Util::updateSectionInfo(NormalizedFile &file) {
+  file.sections.reserve(_sectionInfos.size());
+  // sections grouped by segment.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
+    normSeg->address = sgi->address;
+    normSeg->size = sgi->size;
+    for (SectionInfo *si : sgi->sections) {
+      Section *normSect = &file.sections[si->normalizedSectionIndex];
+      normSect->address = si->address;
+    }
+  }
+}
+
+void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+  if (!_entryAtom) {
+    nFile.entryAddress = 0;
+    return;
+  }
+
+  if (_ctx.outputTypeHasEntry()) {
+    if (_archHandler.isThumbFunction(*_entryAtom))
+      nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
+    else
+      nFile.entryAddress = _atomToAddress[_entryAtom];
+  }
+}
+
+void Util::buildAtomToAddressMap() {
+  DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                   << "assign atom addresses:\n");
+  const bool lookForEntry = _ctx.outputTypeHasEntry();
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      _atomToAddress[info.atom] = sect->address + info.offsetInSection;
+      if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
+          (info.atom->size() != 0) &&
+          info.atom->name() == _ctx.entrySymbolName()) {
+        _entryAtom = info.atom;
+      }
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[info.atom])
+                      << llvm::format("    0x%09lX", info.atom)
+                      << ", file=#"
+                      << info.atom->file().ordinal()
+                      << ", atom=#"
+                      << info.atom->ordinal()
+                      << ", name="
+                      << info.atom->name()
+                      << ", type="
+                      << info.atom->contentType()
+                      << "\n");
+    }
+  }
+  DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                  << "assign header alias atom addresses:\n");
+  for (const Atom *atom : _machHeaderAliasAtoms) {
+    _atomToAddress[atom] = _ctx.baseAddress();
+#ifndef NDEBUG
+    if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[atom])
+                      << llvm::format("    0x%09lX", atom)
+                      << ", file=#"
+                      << definedAtom->file().ordinal()
+                      << ", atom=#"
+                      << definedAtom->ordinal()
+                      << ", name="
+                      << definedAtom->name()
+                      << ", type="
+                      << definedAtom->contentType()
+                      << "\n");
+    } else {
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[atom])
+                      << " atom=" << atom
+                      << " name=" << atom->name() << "\n");
+    }
+#endif
+  }
+}
+
+uint16_t Util::descBits(const DefinedAtom* atom) {
+  uint16_t desc = 0;
+  switch (atom->merge()) {
+  case lld::DefinedAtom::mergeNo:
+  case lld::DefinedAtom::mergeAsTentative:
+    break;
+  case lld::DefinedAtom::mergeAsWeak:
+  case lld::DefinedAtom::mergeAsWeakAndAddressUsed:
+    desc |= N_WEAK_DEF;
+    break;
+  case lld::DefinedAtom::mergeSameNameAndSize:
+  case lld::DefinedAtom::mergeByLargestSection:
+  case lld::DefinedAtom::mergeByContent:
+    llvm_unreachable("Unsupported DefinedAtom::merge()");
+    break;
+  }
+  if (atom->contentType() == lld::DefinedAtom::typeResolver)
+    desc |= N_SYMBOL_RESOLVER;
+  if (atom->contentType() == lld::DefinedAtom::typeMachHeader)
+    desc |= REFERENCED_DYNAMICALLY;
+  if (_archHandler.isThumbFunction(*atom))
+    desc |= N_ARM_THUMB_DEF;
+  if (atom->deadStrip() == DefinedAtom::deadStripNever) {
+    if ((atom->contentType() != DefinedAtom::typeInitializerPtr)
+     && (atom->contentType() != DefinedAtom::typeTerminatorPtr))
+    desc |= N_NO_DEAD_STRIP;
+  }
+  return desc;
+}
+
+bool Util::AtomSorter::operator()(const AtomAndIndex &left,
+                                  const AtomAndIndex &right) {
+  return (left.atom->name().compare(right.atom->name()) < 0);
+}
+
+llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom,
+                                       bool &inGlobalsRegion,
+                                       SymbolScope &scope) {
+  bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+  switch (atom->scope()) {
+  case Atom::scopeTranslationUnit:
+    scope = 0;
+    inGlobalsRegion = false;
+    return llvm::Error();
+  case Atom::scopeLinkageUnit:
+    if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
+        _ctx.exportSymbolNamed(atom->name())) {
+      return llvm::make_error<GenericError>(
+                          Twine("cannot export hidden symbol ") + atom->name());
+    }
+    if (rMode) {
+      if (_ctx.keepPrivateExterns()) {
+        // -keep_private_externs means keep in globals region as N_PEXT.
+        scope = N_PEXT | N_EXT;
+        inGlobalsRegion = true;
+        return llvm::Error();
+      }
+    }
+    // scopeLinkageUnit symbols are no longer global once linked.
+    scope = N_PEXT;
+    inGlobalsRegion = false;
+    return llvm::Error();
+  case Atom::scopeGlobal:
+    if (_ctx.exportRestrictMode()) {
+      if (_ctx.exportSymbolNamed(atom->name())) {
+        scope = N_EXT;
+        inGlobalsRegion = true;
+        return llvm::Error();
+      } else {
+        scope = N_PEXT;
+        inGlobalsRegion = false;
+        return llvm::Error();
+      }
+    } else {
+      scope = N_EXT;
+      inGlobalsRegion = true;
+      return llvm::Error();
+    }
+    break;
+  }
+  llvm_unreachable("atom->scope() unknown enum value");
+}
+
+llvm::Error Util::addSymbols(const lld::File &atomFile,
+                             NormalizedFile &file) {
+  bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+  // Mach-O symbol table has three regions: locals, globals, undefs.
+
+  // Add all local (non-global) symbols in address order
+  std::vector<AtomAndIndex> globals;
+  globals.reserve(512);
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (!atom->name().empty()) {
+        SymbolScope symbolScope;
+        bool inGlobalsRegion;
+        if (auto ec = getSymbolTableRegion(atom, inGlobalsRegion, symbolScope)){
+          return ec;
+        }
+        if (inGlobalsRegion) {
+          AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope };
+          globals.push_back(ai);
+        } else {
+          Symbol sym;
+          sym.name  = atom->name();
+          sym.type  = N_SECT;
+          sym.scope = symbolScope;
+          sym.sect  = sect->finalSectionIndex;
+          sym.desc  = descBits(atom);
+          sym.value = _atomToAddress[atom];
+          _atomToSymbolIndex[atom] = file.localSymbols.size();
+          file.localSymbols.push_back(sym);
+        }
+      } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){
+        // Create 'Lxxx' labels for anonymous atoms if archHandler says so.
+        static unsigned tempNum = 1;
+        char tmpName[16];
+        sprintf(tmpName, "L%04u", tempNum++);
+        StringRef tempRef(tmpName);
+        Symbol sym;
+        sym.name  = tempRef.copy(file.ownedAllocations);
+        sym.type  = N_SECT;
+        sym.scope = 0;
+        sym.sect  = sect->finalSectionIndex;
+        sym.desc  = 0;
+        sym.value = _atomToAddress[atom];
+        _atomToSymbolIndex[atom] = file.localSymbols.size();
+        file.localSymbols.push_back(sym);
+      }
+    }
+  }
+
+  // Sort global symbol alphabetically, then add to symbol table.
+  std::sort(globals.begin(), globals.end(), AtomSorter());
+  const uint32_t globalStartIndex = file.localSymbols.size();
+  for (AtomAndIndex &ai : globals) {
+    Symbol sym;
+    sym.name  = ai.atom->name();
+    sym.type  = N_SECT;
+    sym.scope = ai.scope;
+    sym.sect  = ai.index;
+    sym.desc  = descBits(static_cast<const DefinedAtom*>(ai.atom));
+    sym.value = _atomToAddress[ai.atom];
+    _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size();
+    file.globalSymbols.push_back(sym);
+  }
+
+  // Sort undefined symbol alphabetically, then add to symbol table.
+  std::vector<AtomAndIndex> undefs;
+  undefs.reserve(128);
+  for (const UndefinedAtom *atom : atomFile.undefined()) {
+    AtomAndIndex ai = { atom, 0, N_EXT };
+    undefs.push_back(ai);
+  }
+  for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
+    AtomAndIndex ai = { atom, 0, N_EXT };
+    undefs.push_back(ai);
+  }
+  std::sort(undefs.begin(), undefs.end(), AtomSorter());
+  const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
+  for (AtomAndIndex &ai : undefs) {
+    Symbol sym;
+    uint16_t desc = 0;
+    if (!rMode) {
+      uint8_t ordinal = 0;
+      if (!_ctx.useFlatNamespace())
+        ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom));
+      llvm::MachO::SET_LIBRARY_ORDINAL(desc, ordinal);
+    }
+    sym.name  = ai.atom->name();
+    sym.type  = N_UNDF;
+    sym.scope = ai.scope;
+    sym.sect  = 0;
+    sym.desc  = desc;
+    sym.value = 0;
+    _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
+    file.undefinedSymbols.push_back(sym);
+  }
+
+  return llvm::Error();
+}
+
+const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
+  for (const Reference *ref : *lpAtom) {
+    if (_archHandler.isLazyPointer(*ref)) {
+      return ref->target();
+    }
+  }
+  return nullptr;
+}
+
+const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
+  for (const Reference *ref : *stubAtom) {
+    if (const Atom *ta = ref->target()) {
+      if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
+        const Atom *target = targetOfLazyPointer(lpAtom);
+        if (target)
+          return target;
+      }
+    }
+  }
+  return nullptr;
+}
+
+void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    switch (si->type) {
+    case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        bool foundTarget = false;
+        for (const Reference *ref : *info.atom) {
+          const Atom *target = ref->target();
+          if (target) {
+            if (isa<const SharedLibraryAtom>(target)) {
+              uint32_t index = _atomToSymbolIndex[target];
+              normSect.indirectSymbols.push_back(index);
+              foundTarget = true;
+            } else {
+              normSect.indirectSymbols.push_back(
+                                            llvm::MachO::INDIRECT_SYMBOL_LOCAL);
+            }
+          }
+        }
+        if (!foundTarget) {
+          normSect.indirectSymbols.push_back(
+                                             llvm::MachO::INDIRECT_SYMBOL_ABS);
+        }
+      }
+      break;
+    case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfLazyPointer(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    case llvm::MachO::S_SYMBOL_STUBS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfStub(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
+  // Scan all imported symbols and build up list of dylibs they are from.
+  int ordinal = 1;
+  for (const SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) {
+    StringRef loadPath = slAtom->loadName();
+    DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
+    if (pos == _dylibInfo.end()) {
+      DylibInfo info;
+      bool flatNamespaceAtom = &slAtom->file() == _ctx.flatNamespaceFile();
+
+      // If we're in -flat_namespace mode (or this atom came from the flat
+      // namespace file under -undefined dynamic_lookup) then use the flat
+      // lookup ordinal.
+      if (flatNamespaceAtom || _ctx.useFlatNamespace())
+        info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+      else
+        info.ordinal = ordinal++;
+      info.hasWeak = slAtom->canBeNullAtRuntime();
+      info.hasNonWeak = !info.hasWeak;
+      _dylibInfo[loadPath] = info;
+
+      // Unless this was a flat_namespace atom, record the source dylib.
+      if (!flatNamespaceAtom) {
+        DependentDylib depInfo;
+        depInfo.path = loadPath;
+        depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+        depInfo.currentVersion = _ctx.dylibCurrentVersion(loadPath);
+        depInfo.compatVersion = _ctx.dylibCompatVersion(loadPath);
+        nFile.dependentDylibs.push_back(depInfo);
+      }
+    } else {
+      if ( slAtom->canBeNullAtRuntime() )
+        pos->second.hasWeak = true;
+      else
+        pos->second.hasNonWeak = true;
+    }
+  }
+  // Automatically weak link dylib in which all symbols are weak (canBeNull).
+  for (DependentDylib &dep : nFile.dependentDylibs) {
+    DylibInfo &info = _dylibInfo[dep.path];
+    if (info.hasWeak && !info.hasNonWeak)
+      dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
+    else if (_ctx.isUpwardDylib(dep.path))
+      dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB;
+  }
+}
+
+int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
+  return _dylibInfo[sa->loadName()].ordinal;
+}
+
+void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
+                                                  uint64_t &segmentStartAddr) {
+  segmentIndex = 0;
+  for (const SegmentInfo *seg : _segmentInfos) {
+    if ((seg->address <= sect->address)
+      && (seg->address+seg->size >= sect->address+sect->size)) {
+      segmentStartAddr = seg->address;
+      return;
+    }
+    ++segmentIndex;
+  }
+  llvm_unreachable("section not in any segment");
+}
+
+uint32_t Util::sectionIndexForAtom(const Atom *atom) {
+  uint64_t address = _atomToAddress[atom];
+  for (const SectionInfo *si : _sectionInfos) {
+    if ((si->address <= address) && (address < si->address+si->size))
+      return si->finalSectionIndex;
+  }
+  llvm_unreachable("atom not in any section");
+}
+
+void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
+  if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+    return;
+
+  // Utility function for ArchHandler to find symbol index for an atom.
+  auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+    auto pos = _atomToSymbolIndex.find(&atom);
+    assert(pos != _atomToSymbolIndex.end());
+    return pos->second;
+  };
+
+  // Utility function for ArchHandler to find section index for an atom.
+  auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+    return sectionIndexForAtom(&atom);
+  };
+
+  // Utility function for ArchHandler to find address of atom in output file.
+  auto addressForAtom = [&] (const Atom &atom) -> uint64_t {
+    auto pos = _atomToAddress.find(&atom);
+    assert(pos != _atomToAddress.end());
+    return pos->second;
+  };
+
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        // Skip emitting relocs for sections which are always able to be
+        // implicitly regenerated and where the relocation targets an address
+        // which is defined.
+        if (si->relocsToDefinedCanBeImplicit && isa<DefinedAtom>(ref->target()))
+          continue;
+        _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref,
+                                              symIndexForAtom,
+                                              sectIndexForAtom,
+                                              addressForAtom,
+                                              normSect.relocations);
+      }
+    }
+  }
+}
+
+void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) {
+  if (!_ctx.generateFunctionStartsLoadCommand())
+    return;
+  file.functionStarts.reserve(8192);
+  // Delta compress function starts, starting with the mach header symbol.
+  const uint64_t badAddress = ~0ULL;
+  uint64_t addr = badAddress;
+  for (SectionInfo *si : _sectionInfos) {
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      auto type = info.atom->contentType();
+      if (type == DefinedAtom::typeMachHeader) {
+        addr = _atomToAddress[info.atom];
+        continue;
+      }
+      if (type != DefinedAtom::typeCode)
+        continue;
+      assert(addr != badAddress && "Missing mach header symbol");
+      // Skip atoms which have 0 size.  This is so that LC_FUNCTION_STARTS
+      // can't spill in to the next section.
+      if (!info.atom->size())
+        continue;
+      uint64_t nextAddr = _atomToAddress[info.atom];
+      if (_archHandler.isThumbFunction(*info.atom))
+        nextAddr |= 1;
+      uint64_t delta = nextAddr - addr;
+      if (delta) {
+        ByteBuffer buffer;
+        buffer.append_uleb128(delta);
+        file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(),
+                                   buffer.bytes() + buffer.size());
+      }
+      addr = nextAddr;
+    }
+  }
+
+  // Null terminate, and pad to pointer size for this arch.
+  file.functionStarts.push_back(0);
+
+  auto size = file.functionStarts.size();
+  for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4);
+       i != e; ++i)
+    file.functionStarts.push_back(0);
+}
+
+void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+  if (!_ctx.generateDataInCodeLoadCommand())
+    return;
+  for (SectionInfo *si : _sectionInfos) {
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      // Atoms that contain data-in-code have "transition" references
+      // which mark a point where the embedded data starts of ends.
+      // This needs to be converted to the mach-o format which is an array
+      // of data-in-code ranges.
+      uint32_t startOffset = 0;
+      DataRegionType mode = DataRegionType(0);
+      for (const Reference *ref : *info.atom) {
+        if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+          continue;
+        if (_archHandler.isDataInCodeTransition(ref->kindValue())) {
+          DataRegionType nextMode = (DataRegionType)ref->addend();
+          if (mode != nextMode) {
+            if (mode != 0) {
+              // Found end data range, so make range entry.
+              DataInCode entry;
+              entry.offset = si->address + info.offsetInSection + startOffset;
+              entry.length = ref->offsetInAtom() - startOffset;
+              entry.kind   = mode;
+              file.dataInCode.push_back(entry);
+            }
+          }
+          mode = nextMode;
+          startOffset = ref->offsetInAtom();
+        }
+      }
+      if (mode != 0) {
+        // Function ends with data (no end transition).
+        DataInCode entry;
+        entry.offset = si->address + info.offsetInSection + startOffset;
+        entry.length = info.atom->size() - startOffset;
+        entry.kind   = mode;
+        file.dataInCode.push_back(entry);
+      }
+    }
+  }
+}
+
+void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
+                                                        NormalizedFile &nFile) {
+  if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  uint8_t segmentIndex;
+  uint64_t segmentStartAddr;
+  for (SectionInfo *sect : _sectionInfos) {
+    segIndexForSection(sect, segmentIndex, segmentStartAddr);
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
+                                - segmentStartAddr;
+        const Atom* targ = ref->target();
+        if (_archHandler.isPointer(*ref)) {
+          // A pointer to a DefinedAtom requires rebasing.
+          if (isa<DefinedAtom>(targ)) {
+            RebaseLocation rebase;
+            rebase.segIndex = segmentIndex;
+            rebase.segOffset = segmentOffset;
+            rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
+            nFile.rebasingInfo.push_back(rebase);
+          }
+          // A pointer to an SharedLibraryAtom requires binding.
+          if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+            BindLocation bind;
+            bind.segIndex = segmentIndex;
+            bind.segOffset = segmentOffset;
+            bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+            bind.canBeNull = sa->canBeNullAtRuntime();
+            bind.ordinal = dylibOrdinal(sa);
+            bind.symbolName = targ->name();
+            bind.addend = ref->addend();
+            nFile.bindingInfo.push_back(bind);
+          }
+        }
+        else if (_archHandler.isLazyPointer(*ref)) {
+          BindLocation bind;
+          if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+            bind.ordinal = dylibOrdinal(sa);
+          } else {
+            bind.ordinal = llvm::MachO::BIND_SPECIAL_DYLIB_SELF;
+          }
+          bind.segIndex = segmentIndex;
+          bind.segOffset = segmentOffset;
+          bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+          bind.canBeNull = false; //sa->canBeNullAtRuntime();
+          bind.symbolName = targ->name();
+          bind.addend = ref->addend();
+          nFile.lazyBindingInfo.push_back(bind);
+        }
+      }
+    }
+  }
+}
+
+void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
+  if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (atom->scope() != Atom::scopeGlobal)
+        continue;
+      if (_ctx.exportRestrictMode()) {
+        if (!_ctx.exportSymbolNamed(atom->name()))
+          continue;
+      }
+      Export exprt;
+      exprt.name = atom->name();
+      exprt.offset = _atomToAddress[atom] - _ctx.baseAddress();
+      exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+      if (atom->merge() == DefinedAtom::mergeAsWeak)
+        exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+      else
+        exprt.flags = 0;
+      exprt.otherOffset = 0;
+      exprt.otherName = StringRef();
+      nFile.exportInfo.push_back(exprt);
+    }
+  }
+}
+
+uint32_t Util::fileFlags() {
+  // FIXME: these need to determined at runtime.
+  if (_ctx.outputMachOType() == MH_OBJECT) {
+    return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0;
+  } else {
+    uint32_t flags = MH_DYLDLINK;
+    if (!_ctx.useFlatNamespace())
+        flags |= MH_TWOLEVEL | MH_NOUNDEFS;
+    if ((_ctx.outputMachOType() == MH_EXECUTE) && _ctx.PIE())
+      flags |= MH_PIE;
+    if (_hasTLVDescriptors)
+      flags |= (MH_PIE | MH_HAS_TLV_DESCRIPTORS);
+    return flags;
+  }
+}
+
+} // end anonymous namespace
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Convert a set of Atoms into a normalized mach-o file.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile,
+                                           const MachOLinkingContext &context) {
+  // The util object buffers info until the normalized file can be made.
+  Util util(context);
+  util.processDefinedAtoms(atomFile);
+  util.organizeSections();
+
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+  NormalizedFile &normFile = *f.get();
+  normFile.arch = context.arch();
+  normFile.fileType = context.outputMachOType();
+  normFile.flags = util.fileFlags();
+  normFile.stackSize = context.stackSize();
+  normFile.installName = context.installName();
+  normFile.currentVersion = context.currentVersion();
+  normFile.compatVersion = context.compatibilityVersion();
+  normFile.os = context.os();
+
+  // If we are emitting an object file, then the min version is the maximum
+  // of the min's of all the source files and the cmdline.
+  if (normFile.fileType == llvm::MachO::MH_OBJECT)
+    normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+  else
+    normFile.minOSverson = context.osMinVersion();
+
+  normFile.minOSVersionKind = util.minVersionCommandType();
+
+  normFile.sdkVersion = context.sdkVersion();
+  normFile.sourceVersion = context.sourceVersion();
+
+  if (context.generateVersionLoadCommand() &&
+      context.os() != MachOLinkingContext::OS::unknown)
+    normFile.hasMinVersionLoadCommand = true;
+  else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+           util.allSourceFilesHaveMinVersions() &&
+           ((normFile.os != MachOLinkingContext::OS::unknown) ||
+            util.minVersionCommandType())) {
+    // If we emit an object file, then it should contain a min version load
+    // command if all of the source files also contained min version commands.
+    // Also, we either need to have a platform, or found a platform from the
+    // source object files.
+    normFile.hasMinVersionLoadCommand = true;
+  }
+  normFile.generateDataInCodeLoadCommand =
+    context.generateDataInCodeLoadCommand();
+  normFile.pageSize = context.pageSize();
+  normFile.rpaths = context.rpaths();
+  util.addDependentDylibs(atomFile, normFile);
+  util.copySegmentInfo(normFile);
+  util.copySectionInfo(normFile);
+  util.assignAddressesToSections(normFile);
+  util.buildAtomToAddressMap();
+  util.updateSectionInfo(normFile);
+  util.copySectionContent(normFile);
+  if (auto ec = util.addSymbols(atomFile, normFile)) {
+    return std::move(ec);
+  }
+  util.addIndirectSymbols(atomFile, normFile);
+  util.addRebaseAndBindingInfo(atomFile, normFile);
+  util.addExportInfo(atomFile, normFile);
+  util.addSectionRelocs(atomFile, normFile);
+  util.addFunctionStarts(atomFile, normFile);
+  util.buildDataInCodeArray(atomFile, normFile);
+  util.copyEntryPointAddress(normFile);
+
+  return std::move(f);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
new file mode 100644 (file)
index 0000000..fc760a3
--- /dev/null
@@ -0,0 +1,1337 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory normalized mach-o to in-memory Atoms.
+///
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+///                        |
+///                        |
+///                        v
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+
+#include "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+#define DEBUG_TYPE "normalized-file-to-atoms"
+
+namespace lld {
+namespace mach_o {
+
+
+namespace { // anonymous
+
+
+#define ENTRY(seg, sect, type, atomType) \
+  {seg, sect, type, DefinedAtom::atomType }
+
+struct MachORelocatableSectionToAtomType {
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               sectionType;
+  DefinedAtom::ContentType  atomType;
+};
+
+const MachORelocatableSectionToAtomType sectsToAtomType[] = {
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeCode),
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeResolver),
+  ENTRY("__TEXT", "__cstring",        S_CSTRING_LITERALS, typeCString),
+  ENTRY("",       "",                 S_CSTRING_LITERALS, typeCString),
+  ENTRY("__TEXT", "__ustring",        S_REGULAR,          typeUTF16String),
+  ENTRY("__TEXT", "__const",          S_REGULAR,          typeConstant),
+  ENTRY("__TEXT", "__const_coal",     S_COALESCED,        typeConstant),
+  ENTRY("__TEXT", "__eh_frame",       S_COALESCED,        typeCFI),
+  ENTRY("__TEXT", "__eh_frame",       S_REGULAR,          typeCFI),
+  ENTRY("__TEXT", "__literal4",       S_4BYTE_LITERALS,   typeLiteral4),
+  ENTRY("__TEXT", "__literal8",       S_8BYTE_LITERALS,   typeLiteral8),
+  ENTRY("__TEXT", "__literal16",      S_16BYTE_LITERALS,  typeLiteral16),
+  ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR,          typeLSDA),
+  ENTRY("__DATA", "__data",           S_REGULAR,          typeData),
+  ENTRY("__DATA", "__datacoal_nt",    S_COALESCED,        typeData),
+  ENTRY("__DATA", "__const",          S_REGULAR,          typeConstData),
+  ENTRY("__DATA", "__cfstring",       S_REGULAR,          typeCFString),
+  ENTRY("__DATA", "__mod_init_func",  S_MOD_INIT_FUNC_POINTERS,
+                                                          typeInitializerPtr),
+  ENTRY("__DATA", "__mod_term_func",  S_MOD_TERM_FUNC_POINTERS,
+                                                          typeTerminatorPtr),
+  ENTRY("__DATA", "__got",            S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__bss",            S_ZEROFILL,         typeZeroFill),
+  ENTRY("",       "",                 S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__interposing",    S_INTERPOSING,      typeInterposingTuples),
+  ENTRY("__DATA", "__thread_vars",    S_THREAD_LOCAL_VARIABLES,
+                                                          typeThunkTLV),
+  ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
+  ENTRY("__DATA", "__thread_bss",     S_THREAD_LOCAL_ZEROFILL,
+                                                        typeTLVInitialZeroFill),
+  ENTRY("__DATA", "__objc_imageinfo", S_REGULAR,          typeObjCImageInfo),
+  ENTRY("__DATA", "__objc_catlist",   S_REGULAR,          typeObjC2CategoryList),
+  ENTRY("",       "",                 S_INTERPOSING,      typeInterposingTuples),
+  ENTRY("__LD",   "__compact_unwind", S_REGULAR,
+                                                         typeCompactUnwindInfo),
+  ENTRY("",       "",                 S_REGULAR,          typeUnknown)
+};
+#undef ENTRY
+
+
+/// Figures out ContentType of a mach-o section.
+DefinedAtom::ContentType atomTypeFromSection(const Section &section,
+                                             bool &customSectionName) {
+  // First look for match of name and type. Empty names in table are wildcards.
+  customSectionName = false;
+  for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+                                 p->atomType != DefinedAtom::typeUnknown; ++p) {
+    if (p->sectionType != section.type)
+      continue;
+    if (!p->segmentName.equals(section.segmentName) && !p->segmentName.empty())
+      continue;
+    if (!p->sectionName.equals(section.sectionName) && !p->sectionName.empty())
+      continue;
+    customSectionName = p->segmentName.empty() && p->sectionName.empty();
+    return p->atomType;
+  }
+  // Look for code denoted by section attributes
+  if (section.attributes & S_ATTR_PURE_INSTRUCTIONS)
+    return DefinedAtom::typeCode;
+
+  return DefinedAtom::typeUnknown;
+}
+
+enum AtomizeModel {
+  atomizeAtSymbols,
+  atomizeFixedSize,
+  atomizePointerSize,
+  atomizeUTF8,
+  atomizeUTF16,
+  atomizeCFI,
+  atomizeCU,
+  atomizeCFString
+};
+
+/// Returns info on how to atomize a section of the specified ContentType.
+void sectionParseInfo(DefinedAtom::ContentType atomType,
+                      unsigned int &sizeMultiple,
+                      DefinedAtom::Scope &scope,
+                      DefinedAtom::Merge &merge,
+                      AtomizeModel &atomizeModel) {
+  struct ParseInfo {
+    DefinedAtom::ContentType  atomType;
+    unsigned int              sizeMultiple;
+    DefinedAtom::Scope        scope;
+    DefinedAtom::Merge        merge;
+    AtomizeModel              atomizeModel;
+  };
+
+  #define ENTRY(type, size, scope, merge, model) \
+    {DefinedAtom::type, size, DefinedAtom::scope, DefinedAtom::merge, model }
+
+  static const ParseInfo parseInfo[] = {
+    ENTRY(typeCode,              1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeData,              1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeConstData,         1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeZeroFill,          1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeConstant,          1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeCString,           1, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeUTF8),
+    ENTRY(typeUTF16String,       1, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeUTF16),
+    ENTRY(typeCFI,               4, scopeTranslationUnit, mergeNo,
+                                                            atomizeCFI),
+    ENTRY(typeLiteral4,          4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeLiteral8,          8, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeLiteral16,        16, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeCFString,          4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeCFString),
+    ENTRY(typeInitializerPtr,    4, scopeTranslationUnit, mergeNo,
+                                                            atomizePointerSize),
+    ENTRY(typeTerminatorPtr,     4, scopeTranslationUnit, mergeNo,
+                                                            atomizePointerSize),
+    ENTRY(typeCompactUnwindInfo, 4, scopeTranslationUnit, mergeNo,
+                                                            atomizeCU),
+    ENTRY(typeGOT,               4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizePointerSize),
+    ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent,
+                                                            atomizePointerSize),
+    ENTRY(typeUnknown,           1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols)
+  };
+  #undef ENTRY
+  const int tableLen = sizeof(parseInfo) / sizeof(ParseInfo);
+  for (int i=0; i < tableLen; ++i) {
+    if (parseInfo[i].atomType == atomType) {
+      sizeMultiple = parseInfo[i].sizeMultiple;
+      scope        = parseInfo[i].scope;
+      merge        = parseInfo[i].merge;
+      atomizeModel = parseInfo[i].atomizeModel;
+      return;
+    }
+  }
+
+  // Unknown type is atomized by symbols.
+  sizeMultiple = 1;
+  scope = DefinedAtom::scopeGlobal;
+  merge = DefinedAtom::mergeNo;
+  atomizeModel = atomizeAtSymbols;
+}
+
+
+Atom::Scope atomScope(uint8_t scope) {
+  switch (scope) {
+  case N_EXT:
+    return Atom::scopeGlobal;
+  case N_PEXT:
+  case N_PEXT | N_EXT:
+    return Atom::scopeLinkageUnit;
+  case 0:
+    return Atom::scopeTranslationUnit;
+  }
+  llvm_unreachable("unknown scope value!");
+}
+
+void appendSymbolsInSection(const std::vector<Symbol> &inSymbols,
+                            uint32_t sectionIndex,
+                            SmallVector<const Symbol *, 64> &outSyms) {
+  for (const Symbol &sym : inSymbols) {
+    // Only look at definition symbols.
+    if ((sym.type & N_TYPE) != N_SECT)
+      continue;
+    if (sym.sect != sectionIndex)
+      continue;
+    outSyms.push_back(&sym);
+  }
+}
+
+void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
+                    MachOFile &file, uint64_t symbolAddr, StringRef symbolName,
+                    uint16_t symbolDescFlags, Atom::Scope symbolScope,
+                    uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) {
+  // Mach-O symbol table does have size in it. Instead the size is the
+  // difference between this and the next symbol.
+  uint64_t size = nextSymbolAddr - symbolAddr;
+  uint64_t offset = symbolAddr - section.address;
+  bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable;
+  if (isZeroFillSection(section.type)) {
+    file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size,
+                                noDeadStrip, copyRefs, &section);
+  } else {
+    DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
+                              ? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
+    bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
+    if (atomType == DefinedAtom::typeUnknown) {
+      // Mach-O needs a segment and section name.  Concatentate those two
+      // with a / separator (e.g. "seg/sect") to fit into the lld model
+      // of just a section name.
+      std::string segSectName = section.segmentName.str()
+                                + "/" + section.sectionName.str();
+      file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
+                                         merge, thumb, noDeadStrip, offset,
+                                         size, segSectName, true, &section);
+    } else {
+      if ((atomType == lld::DefinedAtom::typeCode) &&
+          (symbolDescFlags & N_SYMBOL_RESOLVER)) {
+        atomType = lld::DefinedAtom::typeResolver;
+      }
+      file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
+                          offset, size, thumb, noDeadStrip, copyRefs, &section);
+    }
+  }
+}
+
+llvm::Error processSymboledSection(DefinedAtom::ContentType atomType,
+                                   const Section &section,
+                                   const NormalizedFile &normalizedFile,
+                                   MachOFile &file, bool scatterable,
+                                   bool copyRefs) {
+  // Find section's index.
+  uint32_t sectIndex = 1;
+  for (auto &sect : normalizedFile.sections) {
+    if (&sect == &section)
+      break;
+    ++sectIndex;
+  }
+
+  // Find all symbols in this section.
+  SmallVector<const Symbol *, 64> symbols;
+  appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols);
+  appendSymbolsInSection(normalizedFile.localSymbols,  sectIndex, symbols);
+
+  // Sort symbols.
+  std::sort(symbols.begin(), symbols.end(),
+            [](const Symbol *lhs, const Symbol *rhs) -> bool {
+              if (lhs == rhs)
+                return false;
+              // First by address.
+              uint64_t lhsAddr = lhs->value;
+              uint64_t rhsAddr = rhs->value;
+              if (lhsAddr != rhsAddr)
+                return lhsAddr < rhsAddr;
+               // If same address, one is an alias so sort by scope.
+              Atom::Scope lScope = atomScope(lhs->scope);
+              Atom::Scope rScope = atomScope(rhs->scope);
+              if (lScope != rScope)
+                return lScope < rScope;
+              // If same address and scope, see if one might be better as
+              // the alias.
+              bool lPrivate = (lhs->name.front() == 'l');
+              bool rPrivate = (rhs->name.front() == 'l');
+              if (lPrivate != rPrivate)
+                return lPrivate;
+              // If same address and scope, sort by name.
+              return lhs->name < rhs->name;
+            });
+
+  // Debug logging of symbols.
+  //for (const Symbol *sym : symbols)
+  //  llvm::errs() << "  sym: "
+  //    << llvm::format("0x%08llx ", (uint64_t)sym->value)
+  //    << ", " << sym->name << "\n";
+
+  // If section has no symbols and no content, there are no atoms.
+  if (symbols.empty() && section.content.empty())
+    return llvm::Error();
+
+  if (symbols.empty()) {
+    // Section has no symbols, put all content in one anoymous atom.
+    atomFromSymbol(atomType, section, file, section.address, StringRef(),
+                  0, Atom::scopeTranslationUnit,
+                  section.address + section.content.size(),
+                  scatterable, copyRefs);
+  }
+  else if (symbols.front()->value != section.address) {
+    // Section has anonymous content before first symbol.
+    atomFromSymbol(atomType, section, file, section.address, StringRef(),
+                   0, Atom::scopeTranslationUnit, symbols.front()->value,
+                   scatterable, copyRefs);
+  }
+
+  const Symbol *lastSym = nullptr;
+  for (const Symbol *sym : symbols) {
+    if (lastSym != nullptr) {
+      // Ignore any assembler added "ltmpNNN" symbol at start of section
+      // if there is another symbol at the start.
+      if ((lastSym->value != sym->value)
+          || lastSym->value != section.address
+          || !lastSym->name.startswith("ltmp")) {
+        atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+                       lastSym->desc, atomScope(lastSym->scope), sym->value,
+                       scatterable, copyRefs);
+      }
+    }
+    lastSym = sym;
+  }
+  if (lastSym != nullptr) {
+    atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+                   lastSym->desc, atomScope(lastSym->scope),
+                   section.address + section.content.size(),
+                   scatterable, copyRefs);
+  }
+
+  // If object built without .subsections_via_symbols, add reference chain.
+  if (!scatterable) {
+    MachODefinedAtom *prevAtom = nullptr;
+    file.eachAtomInSection(section,
+                           [&](MachODefinedAtom *atom, uint64_t offset)->void {
+      if (prevAtom)
+        prevAtom->addReference(Reference::KindNamespace::all,
+                               Reference::KindArch::all,
+                               Reference::kindLayoutAfter, 0, atom, 0);
+      prevAtom = atom;
+    });
+  }
+
+  return llvm::Error();
+}
+
+llvm::Error processSection(DefinedAtom::ContentType atomType,
+                           const Section &section,
+                           bool customSectionName,
+                           const NormalizedFile &normalizedFile,
+                           MachOFile &file, bool scatterable,
+                           bool copyRefs) {
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+
+  // Get info on how to atomize section.
+  unsigned int       sizeMultiple;
+  DefinedAtom::Scope scope;
+  DefinedAtom::Merge merge;
+  AtomizeModel       atomizeModel;
+  sectionParseInfo(atomType, sizeMultiple, scope, merge, atomizeModel);
+
+  // Validate section size.
+  if ((section.content.size() % sizeMultiple) != 0)
+    return llvm::make_error<GenericError>(Twine("Section ")
+                                          + section.segmentName
+                                          + "/" + section.sectionName
+                                          + " has size ("
+                                          + Twine(section.content.size())
+                                          + ") which is not a multiple of "
+                                          + Twine(sizeMultiple));
+
+  if (atomizeModel == atomizeAtSymbols) {
+    // Break section up into atoms each with a fixed size.
+    return processSymboledSection(atomType, section, normalizedFile, file,
+                                  scatterable, copyRefs);
+  } else {
+    unsigned int size;
+    for (unsigned int offset = 0, e = section.content.size(); offset != e;) {
+      switch (atomizeModel) {
+      case atomizeFixedSize:
+        // Break section up into atoms each with a fixed size.
+        size = sizeMultiple;
+        break;
+      case atomizePointerSize:
+        // Break section up into atoms each the size of a pointer.
+        size = is64 ? 8 : 4;
+        break;
+      case atomizeUTF8:
+        // Break section up into zero terminated c-strings.
+        size = 0;
+        for (unsigned int i = offset; i < e; ++i) {
+          if (section.content[i] == 0) {
+            size = i + 1 - offset;
+            break;
+          }
+        }
+        break;
+      case atomizeUTF16:
+        // Break section up into zero terminated UTF16 strings.
+        size = 0;
+        for (unsigned int i = offset; i < e; i += 2) {
+          if ((section.content[i] == 0) && (section.content[i + 1] == 0)) {
+            size = i + 2 - offset;
+            break;
+          }
+        }
+        break;
+      case atomizeCFI:
+        // Break section up into dwarf unwind CFIs (FDE or CIE).
+        size = read32(&section.content[offset], isBig) + 4;
+        if (offset+size > section.content.size()) {
+          return llvm::make_error<GenericError>(Twine("Section ")
+                                                + section.segmentName
+                                                + "/" + section.sectionName
+                                                + " is malformed.  Size of CFI "
+                                                "starting at offset ("
+                                                + Twine(offset)
+                                                + ") is past end of section.");
+        }
+        break;
+      case atomizeCU:
+        // Break section up into compact unwind entries.
+        size = is64 ? 32 : 20;
+        break;
+      case atomizeCFString:
+        // Break section up into NS/CFString objects.
+        size = is64 ? 32 : 16;
+        break;
+      case atomizeAtSymbols:
+        break;
+      }
+      if (size == 0) {
+        return llvm::make_error<GenericError>(Twine("Section ")
+                                              + section.segmentName
+                                              + "/" + section.sectionName
+                                              + " is malformed.  The last atom "
+                                              "is not zero terminated.");
+      }
+      if (customSectionName) {
+        // Mach-O needs a segment and section name.  Concatentate those two
+        // with a / separator (e.g. "seg/sect") to fit into the lld model
+        // of just a section name.
+        std::string segSectName = section.segmentName.str()
+                                  + "/" + section.sectionName.str();
+        file.addDefinedAtomInCustomSection(StringRef(), scope, atomType,
+                                           merge, false, false, offset,
+                                           size, segSectName, true, &section);
+      } else {
+        file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
+                            false, false, copyRefs, &section);
+      }
+      offset += size;
+    }
+  }
+  return llvm::Error();
+}
+
+const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
+                                          uint64_t address) {
+  for (const Section &s : normalizedFile.sections) {
+    uint64_t sAddr = s.address;
+    if ((sAddr <= address) && (address < sAddr+s.content.size())) {
+      return &s;
+    }
+  }
+  return nullptr;
+}
+
+const MachODefinedAtom *
+findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
+                        uint64_t addr, Reference::Addend *addend) {
+  const Section *sect = nullptr;
+  sect = findSectionCoveringAddress(normalizedFile, addr);
+  if (!sect)
+    return nullptr;
+
+  uint32_t offsetInTarget;
+  uint64_t offsetInSect = addr - sect->address;
+  auto atom =
+      file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+  *addend = offsetInTarget;
+  return atom;
+}
+
+// Walks all relocations for a section in a normalized .o file and
+// creates corresponding lld::Reference objects.
+llvm::Error convertRelocs(const Section &section,
+                          const NormalizedFile &normalizedFile,
+                          bool scatterable,
+                          MachOFile &file,
+                          ArchHandler &handler) {
+  // Utility function for ArchHandler to find atom by its address.
+  auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
+                         const lld::Atom **atom, Reference::Addend *addend)
+                         -> llvm::Error {
+    if (sectIndex > normalizedFile.sections.size())
+      return llvm::make_error<GenericError>(Twine("out of range section "
+                                     "index (") + Twine(sectIndex) + ")");
+    const Section *sect = nullptr;
+    if (sectIndex == 0) {
+      sect = findSectionCoveringAddress(normalizedFile, addr);
+      if (!sect)
+        return llvm::make_error<GenericError>(Twine("address (" + Twine(addr)
+                                       + ") is not in any section"));
+    } else {
+      sect = &normalizedFile.sections[sectIndex-1];
+    }
+    uint32_t offsetInTarget;
+    uint64_t offsetInSect = addr - sect->address;
+    *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+    *addend = offsetInTarget;
+    return llvm::Error();
+  };
+
+  // Utility function for ArchHandler to find atom by its symbol index.
+  auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
+                           -> llvm::Error {
+    // Find symbol from index.
+    const Symbol *sym = nullptr;
+    uint32_t numLocal  = normalizedFile.localSymbols.size();
+    uint32_t numGlobal = normalizedFile.globalSymbols.size();
+    uint32_t numUndef  = normalizedFile.undefinedSymbols.size();
+    if (symbolIndex < numLocal) {
+      sym = &normalizedFile.localSymbols[symbolIndex];
+    } else if (symbolIndex < numLocal+numGlobal) {
+      sym = &normalizedFile.globalSymbols[symbolIndex-numLocal];
+    } else if (symbolIndex < numLocal+numGlobal+numUndef) {
+      sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
+    } else {
+      return llvm::make_error<GenericError>(Twine("symbol index (")
+                                     + Twine(symbolIndex) + ") out of range");
+    }
+    // Find atom from symbol.
+    if ((sym->type & N_TYPE) == N_SECT) {
+      if (sym->sect > normalizedFile.sections.size())
+        return llvm::make_error<GenericError>(Twine("symbol section index (")
+                                        + Twine(sym->sect) + ") out of range ");
+      const Section &symSection = normalizedFile.sections[sym->sect-1];
+      uint64_t targetOffsetInSect = sym->value - symSection.address;
+      MachODefinedAtom *target = file.findAtomCoveringAddress(symSection,
+                                                            targetOffsetInSect);
+      if (target) {
+        *result = target;
+        return llvm::Error();
+      }
+      return llvm::make_error<GenericError>("no atom found for defined symbol");
+    } else if ((sym->type & N_TYPE) == N_UNDF) {
+      const lld::Atom *target = file.findUndefAtom(sym->name);
+      if (target) {
+        *result = target;
+        return llvm::Error();
+      }
+      return llvm::make_error<GenericError>("no undefined atom found for sym");
+    } else {
+      // Search undefs
+      return llvm::make_error<GenericError>("no atom found for symbol");
+    }
+  };
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  // Use old-school iterator so that paired relocations can be grouped.
+  for (auto it=section.relocations.begin(), e=section.relocations.end();
+                                                                it != e; ++it) {
+    const Relocation &reloc = *it;
+    // Find atom this relocation is in.
+    if (reloc.offset > section.content.size())
+      return llvm::make_error<GenericError>(
+                                    Twine("r_address (") + Twine(reloc.offset)
+                                    + ") is larger than section size ("
+                                    + Twine(section.content.size()) + ")");
+    uint32_t offsetInAtom;
+    MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section,
+                                                            reloc.offset,
+                                                            &offsetInAtom);
+    assert(inAtom && "r_address in range, should have found atom");
+    uint64_t fixupAddress = section.address + reloc.offset;
+
+    const lld::Atom *target = nullptr;
+    Reference::Addend addend = 0;
+    Reference::KindValue kind;
+    if (handler.isPairedReloc(reloc)) {
+      // Handle paired relocations together.
+      const Relocation &reloc2 = *++it;
+      auto relocErr = handler.getPairReferenceInfo(
+          reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
+          atomByAddr, atomBySymbol, &kind, &target, &addend);
+      if (relocErr) {
+        return handleErrors(std::move(relocErr),
+                            [&](std::unique_ptr<GenericError> GE) {
+          return llvm::make_error<GenericError>(
+            Twine("bad relocation (") + GE->getMessage()
+             + ") in section "
+             + section.segmentName + "/" + section.sectionName
+             + " (r1_address=" + Twine::utohexstr(reloc.offset)
+             + ", r1_type=" + Twine(reloc.type)
+             + ", r1_extern=" + Twine(reloc.isExtern)
+             + ", r1_length=" + Twine((int)reloc.length)
+             + ", r1_pcrel=" + Twine(reloc.pcRel)
+             + (!reloc.scattered ? (Twine(", r1_symbolnum=")
+                                    + Twine(reloc.symbol))
+                                 : (Twine(", r1_scattered=1, r1_value=")
+                                    + Twine(reloc.value)))
+             + ")"
+             + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
+             + ", r2_type=" + Twine(reloc2.type)
+             + ", r2_extern=" + Twine(reloc2.isExtern)
+             + ", r2_length=" + Twine((int)reloc2.length)
+             + ", r2_pcrel=" + Twine(reloc2.pcRel)
+             + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
+                                     + Twine(reloc2.symbol))
+                                  : (Twine(", r2_scattered=1, r2_value=")
+                                     + Twine(reloc2.value)))
+             + ")" );
+          });
+      }
+    }
+    else {
+      // Use ArchHandler to convert relocation record into information
+      // needed to instantiate an lld::Reference object.
+      auto relocErr = handler.getReferenceInfo(
+          reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
+          atomBySymbol, &kind, &target, &addend);
+      if (relocErr) {
+        return handleErrors(std::move(relocErr),
+                            [&](std::unique_ptr<GenericError> GE) {
+          return llvm::make_error<GenericError>(
+            Twine("bad relocation (") + GE->getMessage()
+             + ") in section "
+             + section.segmentName + "/" + section.sectionName
+             + " (r_address=" + Twine::utohexstr(reloc.offset)
+             + ", r_type=" + Twine(reloc.type)
+             + ", r_extern=" + Twine(reloc.isExtern)
+             + ", r_length=" + Twine((int)reloc.length)
+             + ", r_pcrel=" + Twine(reloc.pcRel)
+             + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+                                 : (Twine(", r_scattered=1, r_value=")
+                                    + Twine(reloc.value)))
+             + ")" );
+          });
+      }
+    }
+    // Instantiate an lld::Reference object and add to its atom.
+    inAtom->addReference(Reference::KindNamespace::mach_o,
+                         handler.kindArch(),
+                         kind, offsetInAtom, target, addend);
+  }
+
+  return llvm::Error();
+}
+
+bool isDebugInfoSection(const Section &section) {
+  if ((section.attributes & S_ATTR_DEBUG) == 0)
+    return false;
+  return section.segmentName.equals("__DWARF");
+}
+
+static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
+  if (is64)
+    return read64(addr, isBig);
+
+  int32_t res = read32(addr, isBig);
+  return res;
+}
+
+/// --- Augmentation String Processing ---
+
+struct CIEInfo {
+  bool _augmentationDataPresent = false;
+  bool _mayHaveEH = false;
+  uint32_t _offsetOfLSDA = ~0U;
+  uint32_t _offsetOfPersonality = ~0U;
+  uint32_t _offsetOfFDEPointerEncoding = ~0U;
+  uint32_t _augmentationDataLength = ~0U;
+};
+
+typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
+
+static llvm::Error processAugmentationString(const uint8_t *augStr,
+                                             CIEInfo &cieInfo,
+                                             unsigned &len) {
+
+  if (augStr[0] == '\0') {
+    len = 1;
+    return llvm::Error();
+  }
+
+  if (augStr[0] != 'z')
+    return llvm::make_error<GenericError>("expected 'z' at start of "
+                                          "augmentation string");
+
+  cieInfo._augmentationDataPresent = true;
+  uint64_t idx = 1;
+
+  uint32_t offsetInAugmentationData = 0;
+  while (augStr[idx] != '\0') {
+    if (augStr[idx] == 'L') {
+      cieInfo._offsetOfLSDA = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data.
+      ++offsetInAugmentationData;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'P') {
+      cieInfo._offsetOfPersonality = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data for the encoding,
+      // then a number of bytes for the pointer data.
+      // FIXME: We are assuming 4 is correct here for the pointer size as we
+      // always currently use delta32ToGOT.
+      offsetInAugmentationData += 5;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'R') {
+      cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data.
+      ++offsetInAugmentationData;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'e') {
+      if (augStr[idx + 1] != 'h')
+        return llvm::make_error<GenericError>("expected 'eh' in "
+                                              "augmentation string");
+      cieInfo._mayHaveEH = true;
+      idx += 2;
+      continue;
+    }
+    ++idx;
+  }
+
+  cieInfo._augmentationDataLength = offsetInAugmentationData;
+
+  len = idx + 1;
+  return llvm::Error();
+}
+
+static llvm::Error processCIE(const NormalizedFile &normalizedFile,
+                              MachOFile &file,
+                              mach_o::ArchHandler &handler,
+                              const Section *ehFrameSection,
+                              MachODefinedAtom *atom,
+                              uint64_t offset,
+                              CIEInfoMap &cieInfos) {
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  const uint8_t *frameData = atom->rawContent().data();
+
+  CIEInfo cieInfo;
+
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieIDField = size == 0xffffffffU
+                          ? sizeof(uint32_t) + sizeof(uint64_t)
+                          : sizeof(uint32_t);
+  uint64_t versionField = cieIDField + sizeof(uint32_t);
+  uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+
+  unsigned augmentationStringLength = 0;
+  if (auto err = processAugmentationString(frameData + augmentationStringField,
+                                           cieInfo, augmentationStringLength))
+    return err;
+
+  if (cieInfo._offsetOfPersonality != ~0U) {
+    // If we have augmentation data for the personality function, then we may
+    // need to implicitly generate its relocation.
+
+    // Parse the EH Data field which is pointer sized.
+    uint64_t EHDataField = augmentationStringField + augmentationStringLength;
+    const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+    unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0);
+
+    // Parse Code Align Factor which is a ULEB128.
+    uint64_t CodeAlignField = EHDataField + EHDataFieldSize;
+    unsigned lengthFieldSize = 0;
+    llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize);
+
+    // Parse Data Align Factor which is a SLEB128.
+    uint64_t DataAlignField = CodeAlignField + lengthFieldSize;
+    llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize);
+
+    // Parse Return Address Register which is a byte.
+    uint64_t ReturnAddressField = DataAlignField + lengthFieldSize;
+
+    // Parse the augmentation length which is a ULEB128.
+    uint64_t AugmentationLengthField = ReturnAddressField + 1;
+    uint64_t AugmentationLength =
+      llvm::decodeULEB128(frameData + AugmentationLengthField,
+                          &lengthFieldSize);
+
+    if (AugmentationLength != cieInfo._augmentationDataLength)
+      return llvm::make_error<GenericError>("CIE augmentation data length "
+                                            "mismatch");
+
+    // Get the start address of the augmentation data.
+    uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize;
+
+    // Parse the personality function from the augmentation data.
+    uint64_t PersonalityField =
+      AugmentationDataField + cieInfo._offsetOfPersonality;
+
+    // Parse the personality encoding.
+    // FIXME: Verify that this is a 32-bit pcrel offset.
+    uint64_t PersonalityFunctionField = PersonalityField + 1;
+
+    if (atom->begin() != atom->end()) {
+      // If we have an explicit relocation, then make sure it matches this
+      // offset as this is where we'd expect it to be applied to.
+      DefinedAtom::reference_iterator CurrentRef = atom->begin();
+      if (CurrentRef->offsetInAtom() != PersonalityFunctionField)
+        return llvm::make_error<GenericError>("CIE personality reloc at "
+                                              "wrong offset");
+
+      if (++CurrentRef != atom->end())
+        return llvm::make_error<GenericError>("CIE contains too many relocs");
+    } else {
+      // Implicitly generate the personality function reloc.  It's assumed to
+      // be a delta32 offset to a GOT entry.
+      // FIXME: Parse the encoding and check this.
+      int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig);
+      uint64_t funcAddress = ehFrameSection->address + offset +
+                             PersonalityFunctionField;
+      funcAddress += funcDelta;
+
+      const MachODefinedAtom *func = nullptr;
+      Reference::Addend addend;
+      func = findAtomCoveringAddress(normalizedFile, file, funcAddress,
+                                     &addend);
+      atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+                         handler.unwindRefToPersonalityFunctionKind(),
+                         PersonalityFunctionField, func, addend);
+    }
+  } else if (atom->begin() != atom->end()) {
+    // Otherwise, we expect there to be no relocations in this atom as the only
+    // relocation would have been to the personality function.
+    return llvm::make_error<GenericError>("unexpected relocation in CIE");
+  }
+
+
+  cieInfos[atom] = std::move(cieInfo);
+
+  return llvm::Error();
+}
+
+static llvm::Error processFDE(const NormalizedFile &normalizedFile,
+                              MachOFile &file,
+                              mach_o::ArchHandler &handler,
+                              const Section *ehFrameSection,
+                              MachODefinedAtom *atom,
+                              uint64_t offset,
+                              const CIEInfoMap &cieInfos) {
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+  // Compiler wasn't lazy and actually told us what it meant.
+  // Unfortunately, the compiler may not have generated references for all of
+  // [cie, func, lsda] and so we still need to parse the FDE and add references
+  // for any the compiler didn't generate.
+  if (atom->begin() != atom->end())
+    atom->sortReferences();
+
+  DefinedAtom::reference_iterator CurrentRef = atom->begin();
+
+  // This helper returns the reference (if one exists) at the offset we are
+  // currently processing.  It automatically increments the ref iterator if we
+  // do return a ref, and throws an error if we pass over a ref without
+  // comsuming it.
+  auto currentRefGetter = [&CurrentRef,
+                           &atom](uint64_t Offset)->const Reference* {
+    // If there are no more refs found, then we are done.
+    if (CurrentRef == atom->end())
+      return nullptr;
+
+    const Reference *Ref = *CurrentRef;
+
+    // If we haven't reached the offset for this reference, then return that
+    // we don't yet have a reference to process.
+    if (Offset < Ref->offsetInAtom())
+      return nullptr;
+
+    // If the offset is equal, then we want to process this ref.
+    if (Offset == Ref->offsetInAtom()) {
+      ++CurrentRef;
+      return Ref;
+    }
+
+    // The current ref is at an offset which is earlier than the current
+    // offset, then we failed to consume it when we should have.  In this case
+    // throw an error.
+    llvm::report_fatal_error("Skipped reference when processing FDE");
+  };
+
+  // Helper to either get the reference at this current location, and verify
+  // that it is of the expected type, or add a reference of that type.
+  // Returns the reference target.
+  auto verifyOrAddReference = [&](uint64_t targetAddress,
+                                  Reference::KindValue refKind,
+                                  uint64_t refAddress,
+                                  bool allowsAddend)->const Atom* {
+    if (auto *ref = currentRefGetter(refAddress)) {
+      // The compiler already emitted a relocation for the CIE ref.  This should
+      // have been converted to the correct type of reference in
+      // get[Pair]ReferenceInfo().
+      assert(ref->kindValue() == refKind &&
+             "Incorrect EHFrame reference kind");
+      return ref->target();
+    }
+    Reference::Addend addend;
+    auto *target = findAtomCoveringAddress(normalizedFile, file,
+                                           targetAddress, &addend);
+    atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+                       refKind, refAddress, target, addend);
+
+    if (!allowsAddend)
+      assert(!addend && "EHFrame reference cannot have addend");
+    return target;
+  };
+
+  const uint8_t *startFrameData = atom->rawContent().data();
+  const uint8_t *frameData = startFrameData;
+
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieFieldInFDE = size == 0xffffffffU
+    ? sizeof(uint32_t) + sizeof(uint64_t)
+    : sizeof(uint32_t);
+
+  // Linker needs to fixup a reference from the FDE to its parent CIE (a
+  // 32-bit byte offset backwards in the __eh_frame section).
+  uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+  uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
+  cieAddress -= cieDelta;
+
+  auto *cieRefTarget = verifyOrAddReference(cieAddress,
+                                            handler.unwindRefToCIEKind(),
+                                            cieFieldInFDE, false);
+  const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget);
+  assert(cie && cie->contentType() == DefinedAtom::typeCFI &&
+         "FDE's CIE field does not point at the start of a CIE.");
+
+  const CIEInfo &cieInfo = cieInfos.find(cie)->second;
+
+  // Linker needs to fixup reference from the FDE to the function it's
+  // describing. FIXME: there are actually different ways to do this, and the
+  // particular method used is specified in the CIE's augmentation fields
+  // (hopefully)
+  uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+  int64_t functionFromFDE = readSPtr(is64, isBig,
+                                     frameData + rangeFieldInFDE);
+  uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+  rangeStart += functionFromFDE;
+
+  verifyOrAddReference(rangeStart,
+                       handler.unwindRefToFunctionKind(),
+                       rangeFieldInFDE, true);
+
+  // Handle the augmentation data if there is any.
+  if (cieInfo._augmentationDataPresent) {
+    // First process the augmentation data length field.
+    uint64_t augmentationDataLengthFieldInFDE =
+      rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
+    unsigned lengthFieldSize = 0;
+    uint64_t augmentationDataLength =
+      llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
+                          &lengthFieldSize);
+
+    if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) {
+
+      // Look at the augmentation data field.
+      uint64_t augmentationDataFieldInFDE =
+        augmentationDataLengthFieldInFDE + lengthFieldSize;
+
+      int64_t lsdaFromFDE = readSPtr(is64, isBig,
+                                     frameData + augmentationDataFieldInFDE);
+      uint64_t lsdaStart =
+        ehFrameSection->address + offset + augmentationDataFieldInFDE +
+        lsdaFromFDE;
+
+      verifyOrAddReference(lsdaStart,
+                           handler.unwindRefToFunctionKind(),
+                           augmentationDataFieldInFDE, true);
+    }
+  }
+
+  return llvm::Error();
+}
+
+llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile,
+                                 MachOFile &file,
+                                 mach_o::ArchHandler &handler) {
+
+  const Section *ehFrameSection = nullptr;
+  for (auto &section : normalizedFile.sections)
+    if (section.segmentName == "__TEXT" &&
+        section.sectionName == "__eh_frame") {
+      ehFrameSection = &section;
+      break;
+    }
+
+  // No __eh_frame so nothing to do.
+  if (!ehFrameSection)
+    return llvm::Error();
+
+  llvm::Error ehFrameErr;
+  CIEInfoMap cieInfos;
+
+  file.eachAtomInSection(*ehFrameSection,
+                         [&](MachODefinedAtom *atom, uint64_t offset) -> void {
+    assert(atom->contentType() == DefinedAtom::typeCFI);
+
+    // Bail out if we've encountered an error.
+    if (ehFrameErr)
+      return;
+
+    const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+    if (ArchHandler::isDwarfCIE(isBig, atom))
+      ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection,
+                              atom, offset, cieInfos);
+    else
+      ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
+                              atom, offset, cieInfos);
+  });
+
+  return ehFrameErr;
+}
+
+llvm::Error parseObjCImageInfo(const Section &sect,
+                               const NormalizedFile &normalizedFile,
+                               MachOFile &file) {
+
+  //   struct objc_image_info  {
+  //           uint32_t        version;        // initially 0
+  //           uint32_t        flags;
+  //   };
+
+  ArrayRef<uint8_t> content = sect.content;
+  if (content.size() != 8)
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " should be 8 bytes in size");
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  uint32_t version = read32(content.data(), isBig);
+  if (version)
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " should have version=0");
+
+  uint32_t flags = read32(content.data() + 4, isBig);
+  if (flags & (MachOLinkingContext::objc_supports_gc |
+               MachOLinkingContext::objc_gc_only))
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " uses GC.  This is not supported");
+
+  if (flags & MachOLinkingContext::objc_retainReleaseForSimulator)
+    file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator);
+  else
+    file.setObjcConstraint(MachOLinkingContext::objc_retainRelease);
+
+  file.setSwiftVersion((flags >> 8) & 0xFF);
+
+  return llvm::Error();
+}
+
+
+/// Converts normalized mach-o file into an lld::File and lld::Atoms.
+llvm::Expected<std::unique_ptr<lld::File>>
+objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+              bool copyRefs) {
+  std::unique_ptr<MachOFile> file(new MachOFile(path));
+  if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs))
+    return std::move(ec);
+  return std::unique_ptr<File>(std::move(file));
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+             bool copyRefs) {
+  // Instantiate SharedLibraryFile object.
+  std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
+  if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs))
+    return std::move(ec);
+  return std::unique_ptr<File>(std::move(file));
+}
+
+} // anonymous namespace
+
+namespace normalized {
+
+static bool isObjCImageInfo(const Section &sect) {
+  return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") ||
+    (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo");
+}
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+                        const NormalizedFile &normalizedFile,
+                        bool copyRefs) {
+  DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+                    << file->path() << "\n");
+  bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
+
+  // Create atoms from each section.
+  for (auto &sect : normalizedFile.sections) {
+    DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump());
+    if (isDebugInfoSection(sect))
+      continue;
+
+
+    // If the file contains an objc_image_info struct, then we should parse the
+    // ObjC flags and Swift version.
+    if (isObjCImageInfo(sect)) {
+      if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file))
+        return ec;
+      // We then skip adding atoms for this section as we use the ObjCPass to
+      // re-emit this data after it has been aggregated for all files.
+      continue;
+    }
+
+    bool customSectionName;
+    DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
+                                                            customSectionName);
+    if (auto ec =  processSection(atomType, sect, customSectionName,
+                                  normalizedFile, *file, scatterable, copyRefs))
+      return ec;
+  }
+  // Create atoms from undefined symbols.
+  for (auto &sym : normalizedFile.undefinedSymbols) {
+    // Undefinded symbols with n_value != 0 are actually tentative definitions.
+    if (sym.value == Hex64(0)) {
+      file->addUndefinedAtom(sym.name, copyRefs);
+    } else {
+      file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
+                                DefinedAtom::Alignment(1 << (sym.desc >> 8)),
+                                copyRefs);
+    }
+  }
+
+  // Convert mach-o relocations to References
+  std::unique_ptr<mach_o::ArchHandler> handler
+                                     = ArchHandler::create(normalizedFile.arch);
+  for (auto &sect : normalizedFile.sections) {
+    if (isDebugInfoSection(sect))
+      continue;
+    if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable,
+                                       *file, *handler))
+      return ec;
+  }
+
+  // Add additional arch-specific References
+  file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void {
+    handler->addAdditionalReferences(*atom);
+  });
+
+  // Each __eh_frame section needs references to both __text (the function we're
+  // providing unwind info for) and itself (FDE -> CIE). These aren't
+  // represented in the relocations on some architectures, so we have to add
+  // them back in manually there.
+  if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler))
+    return ec;
+
+  // Process mach-o data-in-code regions array. That information is encoded in
+  // atoms as References at each transition point.
+  unsigned nextIndex = 0;
+  for (const DataInCode &entry : normalizedFile.dataInCode) {
+    ++nextIndex;
+    const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
+    if (!s) {
+      return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address ("
+                                                  + Twine(entry.offset)
+                                                  + ") is not in any section"));
+    }
+    uint64_t offsetInSect = entry.offset - s->address;
+    uint32_t offsetInAtom;
+    MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
+                                                           &offsetInAtom);
+    if (offsetInAtom + entry.length > atom->size()) {
+      return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry "
+                                                  "(offset="
+                                                  + Twine(entry.offset)
+                                                  + ", length="
+                                                  + Twine(entry.length)
+                                                  + ") crosses atom boundary."));
+    }
+    // Add reference that marks start of data-in-code.
+    atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+                       handler->dataInCodeTransitionStart(*atom),
+                       offsetInAtom, atom, entry.kind);
+
+    // Peek at next entry, if it starts where this one ends, skip ending ref.
+    if (nextIndex < normalizedFile.dataInCode.size()) {
+      const DataInCode &nextEntry = normalizedFile.dataInCode[nextIndex];
+      if (nextEntry.offset == (entry.offset + entry.length))
+        continue;
+    }
+
+    // If data goes to end of function, skip ending ref.
+    if ((offsetInAtom + entry.length) == atom->size())
+      continue;
+
+    // Add reference that marks end of data-in-code.
+    atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+                       handler->dataInCodeTransitionEnd(*atom),
+                       offsetInAtom+entry.length, atom, 0);
+  }
+
+  // Cache some attributes on the file for use later.
+  file->setFlags(normalizedFile.flags);
+  file->setArch(normalizedFile.arch);
+  file->setOS(normalizedFile.os);
+  file->setMinVersion(normalizedFile.minOSverson);
+  file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
+
+  // Sort references in each atom to their canonical order.
+  for (const DefinedAtom* defAtom : file->defined()) {
+    reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
+  }
+  return llvm::Error();
+}
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+                       const NormalizedFile &normalizedFile,
+                       bool copyRefs) {
+  file->setInstallName(normalizedFile.installName);
+  file->setCompatVersion(normalizedFile.compatVersion);
+  file->setCurrentVersion(normalizedFile.currentVersion);
+
+  // Tell MachODylibFile object about all symbols it exports.
+  if (!normalizedFile.exportInfo.empty()) {
+    // If exports trie exists, use it instead of traditional symbol table.
+    for (const Export &exp : normalizedFile.exportInfo) {
+      bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+      // StringRefs from export iterator are ephemeral, so force copy.
+      file->addExportedSymbol(exp.name, weakDef, true);
+    }
+  } else {
+    for (auto &sym : normalizedFile.globalSymbols) {
+      assert((sym.scope & N_EXT) && "only expect external symbols here");
+      bool weakDef = (sym.desc & N_WEAK_DEF);
+      file->addExportedSymbol(sym.name, weakDef, copyRefs);
+    }
+  }
+  // Tell MachODylibFile object about all dylibs it re-exports.
+  for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
+    if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
+      file->addReExportedDylib(dep.path);
+  }
+  return llvm::Error();
+}
+
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+                                          StringRef &segmentName,
+                                          StringRef &sectionName,
+                                          SectionType &sectionType,
+                                          SectionAttr &sectionAttrs,
+                                          bool &relocsToDefinedCanBeImplicit) {
+
+  for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+                                 p->atomType != DefinedAtom::typeUnknown; ++p) {
+    if (p->atomType != atomType)
+      continue;
+    // Wild carded entries are ignored for reverse lookups.
+    if (p->segmentName.empty() || p->sectionName.empty())
+      continue;
+    segmentName = p->segmentName;
+    sectionName = p->sectionName;
+    sectionType = p->sectionType;
+    sectionAttrs = 0;
+    relocsToDefinedCanBeImplicit = false;
+    if (atomType == DefinedAtom::typeCode)
+      sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+    if (atomType == DefinedAtom::typeCFI)
+      relocsToDefinedCanBeImplicit = true;
+    return;
+  }
+  llvm_unreachable("content type not yet supported");
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+                  bool copyRefs) {
+  switch (normalizedFile.fileType) {
+  case MH_DYLIB:
+  case MH_DYLIB_STUB:
+    return dylibToAtoms(normalizedFile, path, copyRefs);
+  case MH_OBJECT:
+    return objectToAtoms(normalizedFile, path, copyRefs);
+  default:
+    llvm_unreachable("unhandled MachO file type!");
+  }
+}
+
+#ifndef NDEBUG
+void Section::dump(llvm::raw_ostream &OS) const {
+  OS << "Section (\"" << segmentName << ", " << sectionName << "\"";
+  OS << ", addr: " << llvm::format_hex(address, 16, true);
+  OS << ", size: " << llvm::format_hex(content.size(), 8, true) << ")\n";
+}
+#endif
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
new file mode 100644 (file)
index 0000000..66be771
--- /dev/null
@@ -0,0 +1,843 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation uses YAML I/O to
+/// provide the convert between YAML and the normalized mach-o (NM).
+///
+///                  +------------+         +------+
+///                  | normalized |   <->   | yaml |
+///                  +------------+         +------+
+
+#include "MachONormalizedFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+
+using llvm::StringRef;
+using namespace llvm::yaml;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using lld::YamlContext;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
+LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
+LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
+
+
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// A vector of Sections is a sequence.
+template<>
+struct SequenceTraits< std::vector<Section> > {
+  static size_t size(IO &io, std::vector<Section> &seq) {
+    return seq.size();
+  }
+  static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+template<>
+struct SequenceTraits< std::vector<Symbol> > {
+  static size_t size(IO &io, std::vector<Symbol> &seq) {
+    return seq.size();
+  }
+  static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// A vector of Relocations is a sequence.
+template<>
+struct SequenceTraits< Relocations > {
+  static size_t size(IO &io, Relocations &seq) {
+    return seq.size();
+  }
+  static Relocation& element(IO &io, Relocations &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// The content for a section is represented as a flow sequence of hex bytes.
+template<>
+struct SequenceTraits< ContentBytes > {
+  static size_t size(IO &io, ContentBytes &seq) {
+    return seq.size();
+  }
+  static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+// The indirect symbols for a section is represented as a flow sequence
+// of numbers (symbol table indexes).
+template<>
+struct SequenceTraits< IndirectSymbols > {
+  static size_t size(IO &io, IndirectSymbols &seq) {
+    return seq.size();
+  }
+  static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
+    io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
+    io.enumCase(value, "ppc",    lld::MachOLinkingContext::arch_ppc);
+    io.enumCase(value, "x86",    lld::MachOLinkingContext::arch_x86);
+    io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
+    io.enumCase(value, "armv6",  lld::MachOLinkingContext::arch_armv6);
+    io.enumCase(value, "armv7",  lld::MachOLinkingContext::arch_armv7);
+    io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
+    io.enumCase(value, "arm64",  lld::MachOLinkingContext::arch_arm64);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
+    io.enumCase(value, "unknown",
+                          lld::MachOLinkingContext::OS::unknown);
+    io.enumCase(value, "Mac OS X",
+                          lld::MachOLinkingContext::OS::macOSX);
+    io.enumCase(value, "iOS",
+                          lld::MachOLinkingContext::OS::iOS);
+    io.enumCase(value, "iOS Simulator",
+                          lld::MachOLinkingContext::OS::iOS_simulator);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<HeaderFileType> {
+  static void enumeration(IO &io, HeaderFileType &value) {
+    io.enumCase(value, "MH_OBJECT",   llvm::MachO::MH_OBJECT);
+    io.enumCase(value, "MH_DYLIB",    llvm::MachO::MH_DYLIB);
+    io.enumCase(value, "MH_EXECUTE",  llvm::MachO::MH_EXECUTE);
+    io.enumCase(value, "MH_BUNDLE",   llvm::MachO::MH_BUNDLE);
+  }
+};
+
+
+template <>
+struct ScalarBitSetTraits<FileFlags> {
+  static void bitset(IO &io, FileFlags &value) {
+    io.bitSetCase(value, "MH_TWOLEVEL",
+                          llvm::MachO::MH_TWOLEVEL);
+    io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",
+                          llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<SectionType> {
+  static void enumeration(IO &io, SectionType &value) {
+    io.enumCase(value, "S_REGULAR",
+                        llvm::MachO::S_REGULAR);
+    io.enumCase(value, "S_ZEROFILL",
+                        llvm::MachO::S_ZEROFILL);
+    io.enumCase(value, "S_CSTRING_LITERALS",
+                        llvm::MachO::S_CSTRING_LITERALS);
+    io.enumCase(value, "S_4BYTE_LITERALS",
+                        llvm::MachO::S_4BYTE_LITERALS);
+    io.enumCase(value, "S_8BYTE_LITERALS",
+                        llvm::MachO::S_8BYTE_LITERALS);
+    io.enumCase(value, "S_LITERAL_POINTERS",
+                        llvm::MachO::S_LITERAL_POINTERS);
+    io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS",
+                        llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_LAZY_SYMBOL_POINTERS",
+                        llvm::MachO::S_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_SYMBOL_STUBS",
+                        llvm::MachO::S_SYMBOL_STUBS);
+    io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS",
+                        llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
+    io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS",
+                        llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
+    io.enumCase(value, "S_COALESCED",
+                        llvm::MachO::S_COALESCED);
+    io.enumCase(value, "S_GB_ZEROFILL",
+                        llvm::MachO::S_GB_ZEROFILL);
+    io.enumCase(value, "S_INTERPOSING",
+                        llvm::MachO::S_INTERPOSING);
+    io.enumCase(value, "S_16BYTE_LITERALS",
+                        llvm::MachO::S_16BYTE_LITERALS);
+    io.enumCase(value, "S_DTRACE_DOF",
+                        llvm::MachO::S_DTRACE_DOF);
+    io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS",
+                        llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_REGULAR",
+                        llvm::MachO::S_THREAD_LOCAL_REGULAR);
+    io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL",
+                        llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLES",
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLES);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS",
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS",
+                        llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SectionAttr> {
+  static void bitset(IO &io, SectionAttr &value) {
+    io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS",
+                          llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",
+                          llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",
+                          llvm::MachO::S_ATTR_NO_DEAD_STRIP);
+    io.bitSetCase(value, "S_ATTR_EXT_RELOC",
+                          llvm::MachO::S_ATTR_EXT_RELOC);
+    io.bitSetCase(value, "S_ATTR_LOC_RELOC",
+                          llvm::MachO::S_ATTR_LOC_RELOC);
+  }
+};
+
+/// This is a custom formatter for SectionAlignment.  Values are
+/// the power to raise by, ie, the n in 2^n.
+template <> struct ScalarTraits<SectionAlignment> {
+  static void output(const SectionAlignment &value, void *ctxt,
+                     raw_ostream &out) {
+    out << llvm::format("%d", (uint32_t)value);
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt,
+                         SectionAlignment &value) {
+    uint32_t alignment;
+    if (scalar.getAsInteger(0, alignment)) {
+      return "malformed alignment value";
+    }
+    if (!llvm::isPowerOf2_32(alignment))
+      return "alignment must be a power of 2";
+    value = alignment;
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <>
+struct ScalarEnumerationTraits<NListType> {
+  static void enumeration(IO &io, NListType &value) {
+    io.enumCase(value, "N_UNDF",  llvm::MachO::N_UNDF);
+    io.enumCase(value, "N_ABS",   llvm::MachO::N_ABS);
+    io.enumCase(value, "N_SECT",  llvm::MachO::N_SECT);
+    io.enumCase(value, "N_PBUD",  llvm::MachO::N_PBUD);
+    io.enumCase(value, "N_INDR",  llvm::MachO::N_INDR);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolScope> {
+  static void bitset(IO &io, SymbolScope &value) {
+    io.bitSetCase(value, "N_EXT",   llvm::MachO::N_EXT);
+    io.bitSetCase(value, "N_PEXT",  llvm::MachO::N_PEXT);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolDesc> {
+  static void bitset(IO &io, SymbolDesc &value) {
+    io.bitSetCase(value, "N_NO_DEAD_STRIP",   llvm::MachO::N_NO_DEAD_STRIP);
+    io.bitSetCase(value, "N_WEAK_REF",        llvm::MachO::N_WEAK_REF);
+    io.bitSetCase(value, "N_WEAK_DEF",        llvm::MachO::N_WEAK_DEF);
+    io.bitSetCase(value, "N_ARM_THUMB_DEF",   llvm::MachO::N_ARM_THUMB_DEF);
+    io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Section> {
+  struct NormalizedContentBytes;
+  static void mapping(IO &io, Section &sect) {
+    io.mapRequired("segment",         sect.segmentName);
+    io.mapRequired("section",         sect.sectionName);
+    io.mapRequired("type",            sect.type);
+    io.mapOptional("attributes",      sect.attributes);
+    io.mapOptional("alignment",       sect.alignment, (SectionAlignment)1);
+    io.mapRequired("address",         sect.address);
+    if (isZeroFillSection(sect.type)) {
+      // S_ZEROFILL sections use "size:" instead of "content:"
+      uint64_t size = sect.content.size();
+      io.mapOptional("size",          size);
+      if (!io.outputting()) {
+        uint8_t *bytes = nullptr;
+        sect.content = makeArrayRef(bytes, size);
+      }
+    } else {
+      MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
+        io, sect.content);
+      io.mapOptional("content",         content->_normalizedContent);
+    }
+    io.mapOptional("relocations",     sect.relocations);
+    io.mapOptional("indirect-syms",   sect.indirectSymbols);
+  }
+
+  struct NormalizedContent {
+    NormalizedContent(IO &io) : _io(io) {}
+    NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
+      // When writing yaml, copy content byte array to Hex8 vector.
+      for (auto &c : content) {
+        _normalizedContent.push_back(c);
+      }
+    }
+    ArrayRef<uint8_t> denormalize(IO &io) {
+      // When reading yaml, allocate byte array owned by NormalizedFile and
+      // copy Hex8 vector to byte array.
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      NormalizedFile *file = info->_normalizeMachOFile;
+      assert(file != nullptr);
+      size_t size = _normalizedContent.size();
+      if (!size)
+        return None;
+      uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
+      std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
+      return makeArrayRef(bytes, size);
+    }
+
+    IO                &_io;
+    ContentBytes       _normalizedContent;
+  };
+};
+
+
+template <>
+struct MappingTraits<Relocation> {
+  static void mapping(IO &io, Relocation &reloc) {
+    io.mapRequired("offset",    reloc.offset);
+    io.mapOptional("scattered", reloc.scattered, false);
+    io.mapRequired("type",      reloc.type);
+    io.mapRequired("length",    reloc.length);
+    io.mapRequired("pc-rel",    reloc.pcRel);
+    if ( !reloc.scattered )
+     io.mapRequired("extern",   reloc.isExtern);
+    if ( reloc.scattered )
+     io.mapRequired("value",    reloc.value);
+    if ( !reloc.scattered )
+     io.mapRequired("symbol",   reloc.symbol);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<RelocationInfoType> {
+  static void enumeration(IO &io, RelocationInfoType &value) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    assert(info != nullptr);
+    NormalizedFile *file = info->_normalizeMachOFile;
+    assert(file != nullptr);
+    switch (file->arch) {
+    case lld::MachOLinkingContext::arch_x86_64:
+      io.enumCase(value, "X86_64_RELOC_UNSIGNED",
+                                  llvm::MachO::X86_64_RELOC_UNSIGNED);
+      io.enumCase(value, "X86_64_RELOC_SIGNED",
+                                  llvm::MachO::X86_64_RELOC_SIGNED);
+      io.enumCase(value, "X86_64_RELOC_BRANCH",
+                                  llvm::MachO::X86_64_RELOC_BRANCH);
+      io.enumCase(value, "X86_64_RELOC_GOT_LOAD",
+                                  llvm::MachO::X86_64_RELOC_GOT_LOAD);
+      io.enumCase(value, "X86_64_RELOC_GOT",
+                                  llvm::MachO::X86_64_RELOC_GOT);
+      io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",
+                                  llvm::MachO::X86_64_RELOC_SUBTRACTOR);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_1",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_1);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_2",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_2);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_4",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_4);
+      io.enumCase(value, "X86_64_RELOC_TLV",
+                                  llvm::MachO::X86_64_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_x86:
+      io.enumCase(value, "GENERIC_RELOC_VANILLA",
+                                  llvm::MachO::GENERIC_RELOC_VANILLA);
+      io.enumCase(value, "GENERIC_RELOC_PAIR",
+                                  llvm::MachO::GENERIC_RELOC_PAIR);
+      io.enumCase(value, "GENERIC_RELOC_SECTDIFF",
+                                  llvm::MachO::GENERIC_RELOC_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",
+                                  llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_TLV",
+                                  llvm::MachO::GENERIC_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_armv6:
+    case lld::MachOLinkingContext::arch_armv7:
+    case lld::MachOLinkingContext::arch_armv7s:
+       io.enumCase(value, "ARM_RELOC_VANILLA",
+                                  llvm::MachO::ARM_RELOC_VANILLA);
+      io.enumCase(value, "ARM_RELOC_PAIR",
+                                  llvm::MachO::ARM_RELOC_PAIR);
+      io.enumCase(value, "ARM_RELOC_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_BR24",
+                                  llvm::MachO::ARM_RELOC_BR24);
+      io.enumCase(value, "ARM_THUMB_RELOC_BR22",
+                                  llvm::MachO::ARM_THUMB_RELOC_BR22);
+      io.enumCase(value, "ARM_RELOC_HALF",
+                                  llvm::MachO::ARM_RELOC_HALF);
+      io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+      break;
+    case lld::MachOLinkingContext::arch_arm64:
+      io.enumCase(value, "ARM64_RELOC_UNSIGNED",
+                                  llvm::MachO::ARM64_RELOC_UNSIGNED);
+      io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
+                                  llvm::MachO::ARM64_RELOC_SUBTRACTOR);
+      io.enumCase(value, "ARM64_RELOC_BRANCH26",
+                                  llvm::MachO::ARM64_RELOC_BRANCH26);
+      io.enumCase(value, "ARM64_RELOC_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
+                                  llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
+      io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_ADDEND",
+                                  llvm::MachO::ARM64_RELOC_ADDEND);
+      break;
+    default:
+      llvm_unreachable("unknown architecture");
+    }
+ }
+};
+
+
+template <>
+struct MappingTraits<Symbol> {
+  static void mapping(IO &io, Symbol& sym) {
+    io.mapRequired("name",    sym.name);
+    io.mapRequired("type",    sym.type);
+    io.mapOptional("scope",   sym.scope, SymbolScope(0));
+    io.mapOptional("sect",    sym.sect, (uint8_t)0);
+    if (sym.type == llvm::MachO::N_UNDF) {
+      // In undef symbols, desc field contains alignment/ordinal info
+      // which is better represented as a hex vaule.
+      uint16_t t1 = sym.desc;
+      Hex16 t2 = t1;
+      io.mapOptional("desc",  t2, Hex16(0));
+      sym.desc = t2;
+    } else {
+      // In defined symbols, desc fit is a set of option bits.
+      io.mapOptional("desc",    sym.desc, SymbolDesc(0));
+    }
+    io.mapRequired("value",  sym.value);
+  }
+};
+
+// Custom mapping for VMProtect (e.g. "r-x").
+template <>
+struct ScalarTraits<VMProtect> {
+  static void output(const VMProtect &value, void*, raw_ostream &out) {
+    out << ( (value & llvm::MachO::VM_PROT_READ)    ? 'r' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_WRITE)   ? 'w' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
+  }
+  static StringRef input(StringRef scalar, void*, VMProtect &value) {
+    value = 0;
+    if (scalar.size() != 3)
+      return "segment access protection must be three chars (e.g. \"r-x\")";
+    switch (scalar[0]) {
+    case 'r':
+      value = llvm::MachO::VM_PROT_READ;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection first char must be 'r' or '-'";
+    }
+    switch (scalar[1]) {
+    case 'w':
+      value = value | llvm::MachO::VM_PROT_WRITE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection second char must be 'w' or '-'";
+    }
+    switch (scalar[2]) {
+    case 'x':
+      value = value | llvm::MachO::VM_PROT_EXECUTE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection third char must be 'x' or '-'";
+    }
+    // Return the empty string on success,
+    return StringRef();
+  }
+  static bool mustQuote(StringRef) { return false; }
+};
+
+
+template <>
+struct MappingTraits<Segment> {
+  static void mapping(IO &io, Segment& seg) {
+    io.mapRequired("name",            seg.name);
+    io.mapRequired("address",         seg.address);
+    io.mapRequired("size",            seg.size);
+    io.mapRequired("init-access",     seg.init_access);
+    io.mapRequired("max-access",      seg.max_access);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<LoadCommandType> {
+  static void enumeration(IO &io, LoadCommandType &value) {
+    io.enumCase(value, "LC_LOAD_DYLIB",
+                        llvm::MachO::LC_LOAD_DYLIB);
+    io.enumCase(value, "LC_LOAD_WEAK_DYLIB",
+                        llvm::MachO::LC_LOAD_WEAK_DYLIB);
+    io.enumCase(value, "LC_REEXPORT_DYLIB",
+                        llvm::MachO::LC_REEXPORT_DYLIB);
+    io.enumCase(value, "LC_LOAD_UPWARD_DYLIB",
+                        llvm::MachO::LC_LOAD_UPWARD_DYLIB);
+    io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
+                        llvm::MachO::LC_LAZY_LOAD_DYLIB);
+    io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+                        llvm::MachO::LC_VERSION_MIN_MACOSX);
+    io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+                        llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+    io.enumCase(value, "LC_VERSION_MIN_TVOS",
+                        llvm::MachO::LC_VERSION_MIN_TVOS);
+    io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+                        llvm::MachO::LC_VERSION_MIN_WATCHOS);
+  }
+};
+
+template <>
+struct MappingTraits<DependentDylib> {
+  static void mapping(IO &io, DependentDylib& dylib) {
+    io.mapRequired("path",            dylib.path);
+    io.mapOptional("kind",            dylib.kind,
+                                      llvm::MachO::LC_LOAD_DYLIB);
+    io.mapOptional("compat-version",  dylib.compatVersion,
+                                      PackedVersion(0x10000));
+    io.mapOptional("current-version", dylib.currentVersion,
+                                      PackedVersion(0x10000));
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<RebaseType> {
+  static void enumeration(IO &io, RebaseType &value) {
+    io.enumCase(value, "REBASE_TYPE_POINTER",
+                        llvm::MachO::REBASE_TYPE_POINTER);
+    io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",
+                        llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
+    io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",
+                        llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
+  }
+};
+
+
+template <>
+struct MappingTraits<RebaseLocation> {
+  static void mapping(IO &io, RebaseLocation& rebase) {
+    io.mapRequired("segment-index",   rebase.segIndex);
+    io.mapRequired("segment-offset",  rebase.segOffset);
+    io.mapOptional("kind",            rebase.kind,
+                                      llvm::MachO::REBASE_TYPE_POINTER);
+  }
+};
+
+
+
+template <>
+struct ScalarEnumerationTraits<BindType> {
+  static void enumeration(IO &io, BindType &value) {
+    io.enumCase(value, "BIND_TYPE_POINTER",
+                        llvm::MachO::BIND_TYPE_POINTER);
+    io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",
+                        llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
+    io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",
+                        llvm::MachO::BIND_TYPE_TEXT_PCREL32);
+  }
+};
+
+template <>
+struct MappingTraits<BindLocation> {
+  static void mapping(IO &io, BindLocation &bind) {
+    io.mapRequired("segment-index",   bind.segIndex);
+    io.mapRequired("segment-offset",  bind.segOffset);
+    io.mapOptional("kind",            bind.kind,
+                                      llvm::MachO::BIND_TYPE_POINTER);
+    io.mapOptional("can-be-null",     bind.canBeNull, false);
+    io.mapRequired("ordinal",         bind.ordinal);
+    io.mapRequired("symbol-name",     bind.symbolName);
+    io.mapOptional("addend",          bind.addend, Hex64(0));
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<ExportSymbolKind> {
+  static void enumeration(IO &io, ExportSymbolKind &value) {
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<ExportFlags> {
+  static void bitset(IO &io, ExportFlags &value) {
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Export> {
+  static void mapping(IO &io, Export &exp) {
+    io.mapRequired("name",         exp.name);
+    io.mapOptional("offset",       exp.offset);
+    io.mapOptional("kind",         exp.kind,
+                                llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    if (!io.outputting() || exp.flags)
+      io.mapOptional("flags",      exp.flags);
+    io.mapOptional("other",        exp.otherOffset, Hex32(0));
+    io.mapOptional("other-name",   exp.otherName, StringRef());
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<DataRegionType> {
+  static void enumeration(IO &io, DataRegionType &value) {
+    io.enumCase(value, "DICE_KIND_DATA",
+                        llvm::MachO::DICE_KIND_DATA);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE8",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE8);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE16",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE16);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE32",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE32);
+    io.enumCase(value, "DICE_KIND_ABS_JUMP_TABLE32",
+                        llvm::MachO::DICE_KIND_ABS_JUMP_TABLE32);
+  }
+};
+
+template <>
+struct MappingTraits<DataInCode> {
+  static void mapping(IO &io, DataInCode &entry) {
+    io.mapRequired("offset",       entry.offset);
+    io.mapRequired("length",       entry.length);
+    io.mapRequired("kind",         entry.kind);
+  }
+};
+
+template <>
+struct ScalarTraits<PackedVersion> {
+  static void output(const PackedVersion &value, void*, raw_ostream &out) {
+    out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
+    if (value & 0xFF) {
+      out << llvm::format(".%d", (value & 0xFF));
+    }
+  }
+  static StringRef input(StringRef scalar, void*, PackedVersion &result) {
+    uint32_t value;
+    if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
+      return "malformed version number";
+    result = value;
+    // Return the empty string on success,
+    return StringRef();
+  }
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <>
+struct MappingTraits<NormalizedFile> {
+  static void mapping(IO &io, NormalizedFile &file) {
+    io.mapRequired("arch",             file.arch);
+    io.mapRequired("file-type",        file.fileType);
+    io.mapOptional("flags",            file.flags);
+    io.mapOptional("dependents",       file.dependentDylibs);
+    io.mapOptional("install-name",     file.installName,    StringRef());
+    io.mapOptional("compat-version",   file.compatVersion,  PackedVersion(0x10000));
+    io.mapOptional("current-version",  file.currentVersion, PackedVersion(0x10000));
+    io.mapOptional("has-UUID",         file.hasUUID,        true);
+    io.mapOptional("rpaths",           file.rpaths);
+    io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
+    io.mapOptional("stack-size",       file.stackSize,      Hex64(0));
+    io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
+    io.mapOptional("OS",               file.os);
+    io.mapOptional("min-os-version",   file.minOSverson,    PackedVersion(0));
+    io.mapOptional("min-os-version-kind",   file.minOSVersionKind, (LoadCommandType)0);
+    io.mapOptional("sdk-version",      file.sdkVersion,     PackedVersion(0));
+    io.mapOptional("segments",         file.segments);
+    io.mapOptional("sections",         file.sections);
+    io.mapOptional("local-symbols",    file.localSymbols);
+    io.mapOptional("global-symbols",   file.globalSymbols);
+    io.mapOptional("undefined-symbols",file.undefinedSymbols);
+    io.mapOptional("page-size",        file.pageSize,       Hex32(4096));
+    io.mapOptional("rebasings",        file.rebasingInfo);
+    io.mapOptional("bindings",         file.bindingInfo);
+    io.mapOptional("weak-bindings",    file.weakBindingInfo);
+    io.mapOptional("lazy-bindings",    file.lazyBindingInfo);
+    io.mapOptional("exports",          file.exportInfo);
+    io.mapOptional("dataInCode",       file.dataInCode);
+  }
+  static StringRef validate(IO &io, NormalizedFile &file) {
+    return StringRef();
+  }
+};
+
+} // namespace llvm
+} // namespace yaml
+
+
+namespace lld {
+namespace mach_o {
+
+/// Handles !mach-o tagged yaml documents.
+bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
+                                                 const lld::File *&file) const {
+  if (!io.mapTag("!mach-o"))
+    return false;
+  // Step 1: parse yaml into normalized mach-o struct.
+  NormalizedFile nf;
+  YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+  assert(info != nullptr);
+  assert(info->_normalizeMachOFile == nullptr);
+  info->_normalizeMachOFile = &nf;
+  MappingTraits<NormalizedFile>::mapping(io, nf);
+  // Step 2: parse normalized mach-o struct into atoms.
+  auto fileOrError = normalizedToAtoms(nf, info->_path, true);
+
+  // Check that we parsed successfully.
+  if (!fileOrError) {
+    std::string buffer;
+    llvm::raw_string_ostream stream(buffer);
+    handleAllErrors(fileOrError.takeError(),
+                    [&](const llvm::ErrorInfoBase &EI) {
+      EI.log(stream);
+      stream << "\n";
+    });
+    io.setError(stream.str());
+    return false;
+  }
+
+  if (nf.arch != _arch) {
+    io.setError(Twine("file is wrong architecture. Expected ("
+                      + MachOLinkingContext::nameFromArch(_arch)
+                      + ") found ("
+                      + MachOLinkingContext::nameFromArch(nf.arch)
+                      + ")"));
+    return false;
+  }
+  info->_normalizeMachOFile = nullptr;
+  file = fileOrError->release();
+  return true;
+}
+
+
+
+namespace normalized {
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  // Create YAML Input parser.
+  YamlContext yamlContext;
+  yamlContext._normalizeMachOFile = f.get();
+  llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+  // Fill NormalizedFile by parsing yaml.
+  yin >> *f;
+
+  // Return error if there were parsing problems.
+  if (auto ec = yin.error())
+    return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
+                                          + ec.message());
+
+  // Hand ownership of instantiated NormalizedFile to caller.
+  return std::move(f);
+}
+
+
+/// Writes a yaml encoded mach-o files from an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
+  // YAML I/O is not const aware, so need to cast away ;-(
+  NormalizedFile *f = const_cast<NormalizedFile*>(&file);
+
+  // Create yaml Output writer, using yaml options for context.
+  YamlContext yamlContext;
+  yamlContext._normalizeMachOFile = f;
+  llvm::yaml::Output yout(out, &yamlContext);
+
+  // Stream out yaml.
+  yout << *f;
+
+  return std::error_code();
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
new file mode 100644 (file)
index 0000000..cd01d4a
--- /dev/null
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/MachO/MachOPasses.h -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_PASSES_H
+#define LLD_READER_WRITER_MACHO_PASSES_H
+
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_PASSES_H
diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp
new file mode 100644 (file)
index 0000000..ba24b3f
--- /dev/null
@@ -0,0 +1,128 @@
+//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// ObjC Image Info Atom created by the ObjC pass.
+///
+class ObjCImageInfoAtom : public SimpleDefinedAtom {
+public:
+  ObjCImageInfoAtom(const File &file,
+                    MachOLinkingContext::ObjCConstraint objCConstraint,
+                    uint32_t swiftVersion)
+      : SimpleDefinedAtom(file) {
+
+    Data.info.version = 0;
+
+    switch (objCConstraint) {
+    case MachOLinkingContext::objc_unknown:
+      llvm_unreachable("Shouldn't run the objc pass without a constraint");
+    case MachOLinkingContext::objc_supports_gc:
+    case MachOLinkingContext::objc_gc_only:
+      llvm_unreachable("GC is not supported");
+    case MachOLinkingContext::objc_retainReleaseForSimulator:
+      // The retain/release for simulator flag is already the correct
+      // encoded value for the data so just set it here.
+      Data.info.flags = (uint32_t)objCConstraint;
+      break;
+    case MachOLinkingContext::objc_retainRelease:
+      // We don't need to encode this flag, so just leave the flags as 0.
+      Data.info.flags = 0;
+      break;
+    }
+
+    Data.info.flags |= (swiftVersion << 8);
+  }
+
+  ~ObjCImageInfoAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeObjCImageInfo;
+  }
+
+  Alignment alignment() const override {
+    return 4;
+  }
+
+  uint64_t size() const override {
+    return 8;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR__;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(Data.bytes, size());
+  }
+
+private:
+
+  struct objc_image_info  {
+    uint32_t   version;
+    uint32_t   flags;
+  };
+
+  union {
+    objc_image_info info;
+    uint8_t bytes[8];
+  } Data;
+};
+
+class ObjCPass : public Pass {
+public:
+  ObjCPass(const MachOLinkingContext &context)
+      : _ctx(context),
+        _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Add the image info.
+    mergedFile.addAtom(*getImageInfo());
+
+    return llvm::Error();
+  }
+
+private:
+
+  const DefinedAtom* getImageInfo() {
+    return new (_file.allocator()) ObjCImageInfoAtom(_file,
+                                                     _ctx.objcConstraint(),
+                                                     _ctx.swiftVersion());
+  }
+
+  const MachOLinkingContext   &_ctx;
+  MachOFile                   &_file;
+};
+
+
+
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<ObjCPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h
new file mode 100644 (file)
index 0000000..49e65f6
--- /dev/null
@@ -0,0 +1,102 @@
+//===---- lib/ReaderWriter/MachO/SectCreateFile.h ---------------*- c++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+#define LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class SectCreateFile : public File {
+public:
+  class SectCreateAtom : public SimpleDefinedAtom {
+  public:
+    SectCreateAtom(const File &file, StringRef segName, StringRef sectName,
+                   std::unique_ptr<MemoryBuffer> content)
+      : SimpleDefinedAtom(file),
+        _combinedName((segName + "/" + sectName).str()),
+        _content(std::move(content)) {}
+
+    ~SectCreateAtom() override = default;
+
+    uint64_t size() const override { return _content->getBufferSize(); }
+
+    Scope scope() const override { return scopeGlobal; }
+
+    ContentType contentType() const override { return typeSectCreate; }
+
+    SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+    StringRef customSectionName() const override { return _combinedName; }
+
+    DeadStripKind deadStrip() const override { return deadStripNever; }
+
+    ArrayRef<uint8_t> rawContent() const override {
+      const uint8_t *data =
+        reinterpret_cast<const uint8_t*>(_content->getBufferStart());
+      return ArrayRef<uint8_t>(data, _content->getBufferSize());
+    }
+
+    StringRef segmentName() const { return _segName; }
+    StringRef sectionName() const { return _sectName; }
+
+  private:
+    std::string _combinedName;
+    StringRef _segName;
+    StringRef _sectName;
+    std::unique_ptr<MemoryBuffer> _content;
+  };
+
+  SectCreateFile() : File("sectcreate", kindSectCreateObject) {}
+
+  void addSection(StringRef seg, StringRef sect,
+                  std::unique_ptr<MemoryBuffer> content) {
+    _definedAtoms.push_back(
+      new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+private:
+  AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
new file mode 100644 (file)
index 0000000..cd53671
--- /dev/null
@@ -0,0 +1,129 @@
+//===- lib/ReaderWriter/MachO/ShimPass.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates branch-sites whose target is a different mode
+// (thumb vs arm).
+//
+// Arm code has two instruction encodings thumb and arm.  When branching from
+// one code encoding to another, you need to use an instruction that switches
+// the instruction mode.  Usually the transition only happens at call sites, and
+// the linker can transform a BL instruction in BLX (or vice versa).  But if the
+// compiler did a tail call optimization and a function ends with a branch (not
+// branch and link), there is no pc-rel BX instruction.
+//
+// The ShimPass looks for pc-rel B instructions that will need to switch mode.
+// For those cases it synthesizes a shim which does the transition, then
+// modifies the original atom with the B instruction to target to the shim atom.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+class ShimPass : public Pass {
+public:
+  ShimPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _stubInfo(_archHandler.stubInfo()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at non-call branches.
+        if (!_archHandler.isNonCallBranch(*ref))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+        if (const lld::DefinedAtom *daTarget = dyn_cast<DefinedAtom>(target)) {
+          bool atomIsThumb = _archHandler.isThumbFunction(*atom);
+          bool targetIsThumb = _archHandler.isThumbFunction(*daTarget);
+          if (atomIsThumb != targetIsThumb)
+            updateBranchToUseShim(atomIsThumb, *daTarget, ref);
+        }
+      }
+    }
+    // Exit early if no shims needed.
+    if (_targetToShim.empty())
+      return llvm::Error();
+
+    // Sort shim atoms so the layout order is stable.
+    std::vector<const DefinedAtom *> shims;
+    shims.reserve(_targetToShim.size());
+    for (auto element : _targetToShim) {
+      shims.push_back(element.second);
+    }
+    std::sort(shims.begin(), shims.end(),
+              [](const DefinedAtom *l, const DefinedAtom *r) {
+                return (l->name() < r->name());
+              });
+
+    // Add all shims to master file.
+    for (const DefinedAtom *shim : shims)
+      mergedFile.addAtom(*shim);
+
+    return llvm::Error();
+  }
+
+private:
+
+  void updateBranchToUseShim(bool thumbToArm, const DefinedAtom& target,
+                             const Reference *ref) {
+    // Make file-format specific stub and other support atoms.
+    const DefinedAtom *shim = this->getShim(thumbToArm, target);
+    assert(shim != nullptr);
+    // Switch branch site to target shim atom.
+    const_cast<Reference *>(ref)->setTarget(shim);
+  }
+
+  const DefinedAtom* getShim(bool thumbToArm, const DefinedAtom& target) {
+    auto pos = _targetToShim.find(&target);
+    if ( pos != _targetToShim.end() ) {
+      // Reuse an existing shim.
+      assert(pos->second != nullptr);
+      return pos->second;
+    } else {
+      // There is no existing shim, so create a new one.
+      const DefinedAtom *shim = _archHandler.createShim(_file, thumbToArm,
+                                                        target);
+       _targetToShim[&target] = shim;
+       return shim;
+    }
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                            &_archHandler;
+  const ArchHandler::StubInfo                    &_stubInfo;
+  MachOFile                                      &_file;
+  llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
+};
+
+
+
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<ShimPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
new file mode 100644 (file)
index 0000000..d53b78b
--- /dev/null
@@ -0,0 +1,379 @@
+//===- lib/ReaderWriter/MachO/StubsPass.cpp ---------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates call-sites which have references to shared library
+// atoms to instead have a reference to a stub (PLT entry) for the specified
+// symbol.  Each file format defines a subclass of StubsPass which implements
+// the abstract methods for creating the file format specific StubAtoms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+//  Lazy Pointer Atom created by the stubs pass.
+//
+class LazyPointerAtom : public SimpleDefinedAtom {
+public:
+  LazyPointerAtom(const File &file, bool is64)
+    : SimpleDefinedAtom(file), _is64(is64) { }
+
+  ~LazyPointerAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeLazyPointer;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+};
+
+//
+//  NonLazyPointer (GOT) Atom created by the stubs pass.
+//
+class NonLazyPointerAtom : public SimpleDefinedAtom {
+public:
+  NonLazyPointerAtom(const File &file, bool is64, ContentType contentType)
+    : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { }
+
+  ~NonLazyPointerAtom() override = default;
+
+  ContentType contentType() const override {
+    return _contentType;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+  const ContentType _contentType;
+};
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+  StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+
+  ~StubAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStub;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.codeAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+//
+// Stub Helper Atom created by the stubs pass.
+//
+class StubHelperAtom : public SimpleDefinedAtom {
+public:
+  StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ~StubHelperAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.codeAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperBytes,
+                              _stubInfo.stubHelperSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+//
+// Stub Helper Common Atom created by the stubs pass.
+//
+class StubHelperCommonAtom : public SimpleDefinedAtom {
+public:
+  StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ~StubHelperCommonAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.stubHelperCommonAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperCommonSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes,
+                        _stubInfo.stubHelperCommonSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+class StubsPass : public Pass {
+public:
+  StubsPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _stubInfo(_archHandler.stubInfo()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Skip this pass if output format uses text relocations instead of stubs.
+    if (!this->noTextRelocs())
+      return llvm::Error();
+
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at call-sites.
+        if (!this->isCallSite(*ref))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+        if (isa<SharedLibraryAtom>(target)) {
+          // Calls to shared libraries go through stubs.
+          _targetToUses[target].push_back(ref);
+          continue;
+        }
+        const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+        if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){
+          // Calls to interposable functions in same linkage unit must also go
+          // through a stub.
+          assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+          _targetToUses[target].push_back(ref);
+        }
+      }
+    }
+
+    // Exit early if no stubs needed.
+    if (_targetToUses.empty())
+      return llvm::Error();
+
+    // First add help-common and GOT slots used by lazy binding.
+    SimpleDefinedAtom *helperCommonAtom =
+        new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
+    SimpleDefinedAtom *helperCacheNLPAtom =
+        new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+                                    _stubInfo.stubHelperImageCacheContentType);
+    SimpleDefinedAtom *helperBinderNLPAtom =
+        new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+                                    _stubInfo.stubHelperImageCacheContentType);
+    addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+                 helperCacheNLPAtom);
+    addOptReference(
+        helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+        _stubInfo.optStubHelperCommonReferenceToCache, helperCacheNLPAtom);
+    addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+                 helperBinderNLPAtom);
+    addOptReference(
+        helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+        _stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom);
+    mergedFile.addAtom(*helperCommonAtom);
+    mergedFile.addAtom(*helperBinderNLPAtom);
+    mergedFile.addAtom(*helperCacheNLPAtom);
+
+    // Add reference to dyld_stub_binder in libSystem.dylib
+    auto I = std::find_if(
+        mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(),
+        [&](const SharedLibraryAtom *atom) {
+          return atom->name().equals(_stubInfo.binderSymbolName);
+        });
+    assert(I != mergedFile.sharedLibrary().end() &&
+           "dyld_stub_binder not found");
+    addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I);
+
+    // Sort targets by name, so stubs and lazy pointers are consistent
+    std::vector<const Atom *> targetsNeedingStubs;
+    for (auto it : _targetToUses)
+      targetsNeedingStubs.push_back(it.first);
+    std::sort(targetsNeedingStubs.begin(), targetsNeedingStubs.end(),
+              [](const Atom * left, const Atom * right) {
+      return (left->name().compare(right->name()) < 0);
+    });
+
+    // Make and append stubs, lazy pointers, and helpers in alphabetical order.
+    unsigned lazyOffset = 0;
+    for (const Atom *target : targetsNeedingStubs) {
+      auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
+      auto *lp =
+          new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit());
+      auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
+
+      addReference(stub, _stubInfo.stubReferenceToLP, lp);
+      addOptReference(stub, _stubInfo.stubReferenceToLP,
+                      _stubInfo.optStubReferenceToLP, lp);
+      addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
+      addReference(lp, _stubInfo.lazyPointerReferenceToFinal, target);
+      addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
+      addReferenceAddend(helper, _stubInfo.stubHelperReferenceToImm, helper,
+                         lazyOffset);
+      addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon,
+                   helperCommonAtom);
+
+      mergedFile.addAtom(*stub);
+      mergedFile.addAtom(*lp);
+      mergedFile.addAtom(*helper);
+
+      // Update each reference to use stub.
+      for (const Reference *ref : _targetToUses[target]) {
+        assert(ref->target() == target);
+        // Switch call site to reference stub atom instead.
+        const_cast<Reference *>(ref)->setTarget(stub);
+      }
+
+      // Calculate new offset
+      lazyOffset += target->name().size() + 12;
+    }
+
+    return llvm::Error();
+  }
+
+private:
+  bool noTextRelocs() {
+    return true;
+  }
+
+  bool isCallSite(const Reference &ref) {
+    return _archHandler.isCallSite(ref);
+  }
+
+  void addReference(SimpleDefinedAtom* atom,
+                    const ArchHandler::ReferenceInfo &refInfo,
+                    const lld::Atom* target) {
+    atom->addReference(Reference::KindNamespace::mach_o,
+                      refInfo.arch, refInfo.kind, refInfo.offset,
+                      target, refInfo.addend);
+  }
+
+  void addReferenceAddend(SimpleDefinedAtom *atom,
+                          const ArchHandler::ReferenceInfo &refInfo,
+                          const lld::Atom *target, uint64_t addend) {
+    atom->addReference(Reference::KindNamespace::mach_o, refInfo.arch,
+                       refInfo.kind, refInfo.offset, target, addend);
+  }
+
+   void addOptReference(SimpleDefinedAtom* atom,
+                    const ArchHandler::ReferenceInfo &refInfo,
+                    const ArchHandler::OptionalRefInfo &optRef,
+                    const lld::Atom* target) {
+      if (!optRef.used)
+        return;
+    atom->addReference(Reference::KindNamespace::mach_o,
+                      refInfo.arch, optRef.kind, optRef.offset,
+                      target, optRef.addend);
+  }
+
+  typedef llvm::DenseMap<const Atom*,
+                         llvm::SmallVector<const Reference *, 8>> TargetToUses;
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                            &_archHandler;
+  const ArchHandler::StubInfo                    &_stubInfo;
+  MachOFile                                      &_file;
+  TargetToUses                                    _targetToUses;
+};
+
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp
new file mode 100644 (file)
index 0000000..7a8496c
--- /dev/null
@@ -0,0 +1,141 @@
+//===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all TLV references to real references.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// TLVP Entry Atom created by the TLV pass.
+//
+class TLVPEntryAtom : public SimpleDefinedAtom {
+public:
+  TLVPEntryAtom(const File &file, bool is64, StringRef name)
+      : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+
+  ~TLVPEntryAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeTLVInitializerPtr;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+  StringRef slotName() const {
+    return _name;
+  }
+
+private:
+  const bool _is64;
+  StringRef _name;
+};
+
+class TLVPass : public Pass {
+public:
+  TLVPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    bool allowTLV = _ctx.minOS("10.7", "1.0");
+
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        if (!_archHandler.isTLVAccess(*ref))
+          continue;
+
+        if (!allowTLV)
+          return llvm::make_error<GenericError>(
+            "targeted OS version does not support use of thread local "
+            "variables in " + atom->name() + " for architecture " +
+            _ctx.archName());
+
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+
+        const DefinedAtom *tlvpEntry = makeTLVPEntry(target);
+        const_cast<Reference*>(ref)->setTarget(tlvpEntry);
+        _archHandler.updateReferenceToTLV(ref);
+      }
+    }
+
+    std::vector<const TLVPEntryAtom*> entries;
+    entries.reserve(_targetToTLVP.size());
+    for (auto &it : _targetToTLVP)
+      entries.push_back(it.second);
+    std::sort(entries.begin(), entries.end(),
+              [](const TLVPEntryAtom *lhs, const TLVPEntryAtom *rhs) {
+                return (lhs->slotName().compare(rhs->slotName()) < 0);
+              });
+
+    for (const TLVPEntryAtom *slot : entries)
+      mergedFile.addAtom(*slot);
+
+    return llvm::Error();
+  }
+
+  const DefinedAtom *makeTLVPEntry(const Atom *target) {
+    auto pos = _targetToTLVP.find(target);
+
+    if (pos != _targetToTLVP.end())
+      return pos->second;
+
+    auto *tlvpEntry = new (_file.allocator())
+      TLVPEntryAtom(_file, _ctx.is64Bit(), target->name());
+    _targetToTLVP[target] = tlvpEntry;
+    const ArchHandler::ReferenceInfo &nlInfo =
+      _archHandler.stubInfo().nonLazyPointerReferenceToBinder;
+    tlvpEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+                            nlInfo.kind, 0, target, 0);
+    return tlvpEntry;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler &_archHandler;
+  MachOFile           &_file;
+  llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
+};
+
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsTLVPass());
+  pm.add(llvm::make_unique<TLVPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
new file mode 100644 (file)
index 0000000..f08487f
--- /dev/null
@@ -0,0 +1,71 @@
+//===- lib/ReaderWriter/MachO/WriterMachO.cpp -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExecutableAtoms.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using lld::mach_o::normalized::NormalizedFile;
+
+namespace lld {
+namespace mach_o {
+
+class MachOWriter : public Writer {
+public:
+  MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
+
+  llvm::Error writeFile(const lld::File &file, StringRef path) override {
+    // Construct empty normalized file from atoms.
+    llvm::Expected<std::unique_ptr<NormalizedFile>> nFile =
+        normalized::normalizedFromAtoms(file, _ctx);
+    if (auto ec = nFile.takeError())
+      return ec;
+
+    // For testing, write out yaml form of normalized file.
+    if (_ctx.printAtoms()) {
+      std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
+      if (auto ec = yamlWriter->writeFile(file, "-"))
+        return ec;
+    }
+
+    // Write normalized file as mach-o binary.
+    return writeBinary(*nFile->get(), path);
+  }
+
+  void createImplicitFiles(std::vector<std::unique_ptr<File>> &r) override {
+    // When building main executables, add _main as required entry point.
+    if (_ctx.outputTypeHasEntry())
+      r.emplace_back(new CEntryFile(_ctx));
+    // If this can link with dylibs, need helper function (dyld_stub_binder).
+    if (_ctx.needsStubsPass())
+      r.emplace_back(new StubHelperFile(_ctx));
+    // Final linked images can access a symbol for their mach_header.
+    if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+      r.emplace_back(new MachHeaderAliasFile(_ctx));
+  }
+private:
+  const MachOLinkingContext &_ctx;
+ };
+
+
+} // namespace mach_o
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &context) {
+  return std::unique_ptr<Writer>(new lld::mach_o::MachOWriter(context));
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/YAML/CMakeLists.txt b/lib/ReaderWriter/YAML/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5c25444
--- /dev/null
@@ -0,0 +1,6 @@
+add_lld_library(lldYAML
+  ReaderWriterYAML.cpp
+  LINK_LIBS
+    lldCore
+    LLVMSupport
+  )
diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
new file mode 100644 (file)
index 0000000..ee2a9ec
--- /dev/null
@@ -0,0 +1,1399 @@
+//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using llvm::yaml::MappingTraits;
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::ScalarTraits;
+using llvm::yaml::IO;
+using llvm::yaml::SequenceTraits;
+using llvm::yaml::DocumentListTraits;
+
+using namespace lld;
+
+/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O.  This
+/// file just defines template specializations on the lld types which control
+/// how the mapping is done to and from YAML.
+
+namespace {
+
+/// Used when writing yaml files.
+/// In most cases, atoms names are unambiguous, so references can just
+/// use the atom name as the target (e.g. target: foo).  But in a few
+/// cases that does not work, so ref-names are added.  These are labels
+/// used only in yaml.  The labels do not exist in the Atom model.
+///
+/// One need for ref-names are when atoms have no user supplied name
+/// (e.g. c-string literal).  Another case is when two object files with
+/// identically named static functions are merged (ld -r) into one object file.
+/// In that case referencing the function by name is ambiguous, so a unique
+/// ref-name is added.
+class RefNameBuilder {
+public:
+  RefNameBuilder(const lld::File &file)
+      : _collisionCount(0), _unnamedCounter(0) {
+    // visit all atoms
+    for (const lld::DefinedAtom *atom : file.defined()) {
+      // Build map of atoms names to detect duplicates
+      if (!atom->name().empty())
+        buildDuplicateNameMap(*atom);
+
+      // Find references to unnamed atoms and create ref-names for them.
+      for (const lld::Reference *ref : *atom) {
+        // create refname for any unnamed reference target
+        const lld::Atom *target = ref->target();
+        if ((target != nullptr) && target->name().empty()) {
+          std::string storage;
+          llvm::raw_string_ostream buffer(storage);
+          buffer << llvm::format("L%03d", _unnamedCounter++);
+          StringRef newName = copyString(buffer.str());
+          _refNames[target] = newName;
+          DEBUG_WITH_TYPE("WriterYAML",
+                          llvm::dbgs() << "unnamed atom: creating ref-name: '"
+                                       << newName << "' ("
+                                       << (const void *)newName.data() << ", "
+                                       << newName.size() << ")\n");
+        }
+      }
+    }
+    for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
+      buildDuplicateNameMap(*undefAtom);
+    }
+    for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
+      buildDuplicateNameMap(*shlibAtom);
+    }
+    for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
+      if (!absAtom->name().empty())
+        buildDuplicateNameMap(*absAtom);
+    }
+  }
+
+  void buildDuplicateNameMap(const lld::Atom &atom) {
+    assert(!atom.name().empty());
+    NameToAtom::iterator pos = _nameMap.find(atom.name());
+    if (pos != _nameMap.end()) {
+      // Found name collision, give each a unique ref-name.
+      std::string Storage;
+      llvm::raw_string_ostream buffer(Storage);
+      buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
+      StringRef newName = copyString(buffer.str());
+      _refNames[&atom] = newName;
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "name collsion: creating ref-name: '"
+                                   << newName << "' ("
+                                   << (const void *)newName.data()
+                                   << ", " << newName.size() << ")\n");
+      const lld::Atom *prevAtom = pos->second;
+      AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
+      if (pos2 == _refNames.end()) {
+        // Only create ref-name for previous if none already created.
+        std::string Storage2;
+        llvm::raw_string_ostream buffer2(Storage2);
+        buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
+        StringRef newName2 = copyString(buffer2.str());
+        _refNames[prevAtom] = newName2;
+        DEBUG_WITH_TYPE("WriterYAML",
+                        llvm::dbgs() << "name collsion: creating ref-name: '"
+                                     << newName2 << "' ("
+                                     << (const void *)newName2.data() << ", "
+                                     << newName2.size() << ")\n");
+      }
+    } else {
+      // First time we've seen this name, just add it to map.
+      _nameMap[atom.name()] = &atom;
+      DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+                                        << "atom name seen for first time: '"
+                                        << atom.name() << "' ("
+                                        << (const void *)atom.name().data()
+                                        << ", " << atom.name().size() << ")\n");
+    }
+  }
+
+  bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
+
+  StringRef refName(const lld::Atom *atom) {
+    return _refNames.find(atom)->second;
+  }
+
+private:
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+  typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
+
+  // Allocate a new copy of this string in _storage, so the strings
+  // can be freed when RefNameBuilder is destroyed.
+  StringRef copyString(StringRef str) {
+    char *s = _storage.Allocate<char>(str.size());
+    memcpy(s, str.data(), str.size());
+    return StringRef(s, str.size());
+  }
+
+  unsigned int                         _collisionCount;
+  unsigned int                         _unnamedCounter;
+  NameToAtom                           _nameMap;
+  AtomToRefName                        _refNames;
+  llvm::BumpPtrAllocator               _storage;
+};
+
+/// Used when reading yaml files to find the target of a reference
+/// that could be a name or ref-name.
+class RefNameResolver {
+public:
+  RefNameResolver(const lld::File *file, IO &io);
+
+  const lld::Atom *lookup(StringRef name) const {
+    NameToAtom::const_iterator pos = _nameMap.find(name);
+    if (pos != _nameMap.end())
+      return pos->second;
+    _io.setError(Twine("no such atom name: ") + name);
+    return nullptr;
+  }
+
+private:
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+  void add(StringRef name, const lld::Atom *atom) {
+    if (_nameMap.count(name)) {
+      _io.setError(Twine("duplicate atom name: ") + name);
+    } else {
+      _nameMap[name] = atom;
+    }
+  }
+
+  IO &_io;
+  NameToAtom _nameMap;
+};
+
+/// Mapping of Atoms.
+template <typename T> class AtomList {
+  using Ty = std::vector<OwningAtomPtr<T>>;
+
+public:
+  typename Ty::iterator begin() { return _atoms.begin(); }
+  typename Ty::iterator end() { return _atoms.end(); }
+  Ty _atoms;
+};
+
+/// Mapping of kind: field in yaml files.
+enum FileKinds {
+  fileKindObjectAtoms, // atom based object file encoded in yaml
+  fileKindArchive,     // static archive library encoded in yaml
+  fileKindObjectMachO  // mach-o object files encoded in yaml
+};
+
+struct ArchMember {
+  FileKinds         _kind;
+  StringRef         _name;
+  const lld::File  *_content;
+};
+
+// The content bytes in a DefinedAtom are just uint8_t but we want
+// special formatting, so define a strong type.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
+
+// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
+// more readable than just true/false.
+LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
+
+// lld::Reference::Kind is a tuple of <namespace, arch, value>.
+// For yaml, we just want one string that encapsulates the tuple.
+struct RefKind {
+  Reference::KindNamespace  ns;
+  Reference::KindArch       arch;
+  Reference::KindValue      value;
+};
+
+} // end anonymous namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
+LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
+// Always write DefinedAtoms content bytes as a flow sequence.
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// This is a custom formatter for RefKind
+template <> struct ScalarTraits<RefKind> {
+  static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
+    assert(ctxt != nullptr);
+    YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+    assert(info->_registry);
+    StringRef str;
+    if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
+                                               str))
+      out << str;
+    else
+      out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
+    assert(ctxt != nullptr);
+    YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+    assert(info->_registry);
+    if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
+                                                 kind.value))
+      return StringRef();
+    return StringRef("unknown reference kind");
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<lld::File::Kind> {
+  static void enumeration(IO &io, lld::File::Kind &value) {
+    io.enumCase(value, "error-object",   lld::File::kindErrorObject);
+    io.enumCase(value, "object",         lld::File::kindMachObject);
+    io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
+    io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
+  static void enumeration(IO &io, lld::Atom::Scope &value) {
+    io.enumCase(value, "global", lld::Atom::scopeGlobal);
+    io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
+    io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
+  static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
+    io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
+    io.enumCase(value, "custom",  lld::DefinedAtom::sectionCustomPreferred);
+    io.enumCase(value, "custom-required",
+                                 lld::DefinedAtom::sectionCustomRequired);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
+  static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
+    io.enumCase(value, "no",           DefinedAtom::interposeNo);
+    io.enumCase(value, "yes",          DefinedAtom::interposeYes);
+    io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
+  static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
+    io.enumCase(value, "no",           lld::DefinedAtom::mergeNo);
+    io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
+    io.enumCase(value, "as-weak",      lld::DefinedAtom::mergeAsWeak);
+    io.enumCase(value, "as-addressed-weak",
+                                   lld::DefinedAtom::mergeAsWeakAndAddressUsed);
+    io.enumCase(value, "by-content",   lld::DefinedAtom::mergeByContent);
+    io.enumCase(value, "same-name-and-size",
+                lld::DefinedAtom::mergeSameNameAndSize);
+    io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
+  static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
+    io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
+    io.enumCase(value, "never",  lld::DefinedAtom::deadStripNever);
+    io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
+  static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
+    io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
+    io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
+  static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
+    io.enumCase(value, "none", lld::DefinedAtom::codeNA);
+    io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
+    io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
+    io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
+    io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
+    io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
+    io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
+    io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
+    io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
+  static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
+    io.enumCase(value, "---",     lld::DefinedAtom::perm___);
+    io.enumCase(value, "r--",     lld::DefinedAtom::permR__);
+    io.enumCase(value, "r-x",     lld::DefinedAtom::permR_X);
+    io.enumCase(value, "rw-",     lld::DefinedAtom::permRW_);
+    io.enumCase(value, "rwx",     lld::DefinedAtom::permRWX);
+    io.enumCase(value, "rw-l",    lld::DefinedAtom::permRW_L);
+    io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
+  static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
+    io.enumCase(value, "unknown",         DefinedAtom::typeUnknown);
+    io.enumCase(value, "code",            DefinedAtom::typeCode);
+    io.enumCase(value, "stub",            DefinedAtom::typeStub);
+    io.enumCase(value, "constant",        DefinedAtom::typeConstant);
+    io.enumCase(value, "data",            DefinedAtom::typeData);
+    io.enumCase(value, "quick-data",      DefinedAtom::typeDataFast);
+    io.enumCase(value, "zero-fill",       DefinedAtom::typeZeroFill);
+    io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
+    io.enumCase(value, "const-data",      DefinedAtom::typeConstData);
+    io.enumCase(value, "got",             DefinedAtom::typeGOT);
+    io.enumCase(value, "resolver",        DefinedAtom::typeResolver);
+    io.enumCase(value, "branch-island",   DefinedAtom::typeBranchIsland);
+    io.enumCase(value, "branch-shim",     DefinedAtom::typeBranchShim);
+    io.enumCase(value, "stub-helper",     DefinedAtom::typeStubHelper);
+    io.enumCase(value, "c-string",        DefinedAtom::typeCString);
+    io.enumCase(value, "utf16-string",    DefinedAtom::typeUTF16String);
+    io.enumCase(value, "unwind-cfi",      DefinedAtom::typeCFI);
+    io.enumCase(value, "unwind-lsda",     DefinedAtom::typeLSDA);
+    io.enumCase(value, "const-4-byte",    DefinedAtom::typeLiteral4);
+    io.enumCase(value, "const-8-byte",    DefinedAtom::typeLiteral8);
+    io.enumCase(value, "const-16-byte",   DefinedAtom::typeLiteral16);
+    io.enumCase(value, "lazy-pointer",    DefinedAtom::typeLazyPointer);
+    io.enumCase(value, "lazy-dylib-pointer",
+                                          DefinedAtom::typeLazyDylibPointer);
+    io.enumCase(value, "cfstring",        DefinedAtom::typeCFString);
+    io.enumCase(value, "initializer-pointer",
+                                          DefinedAtom::typeInitializerPtr);
+    io.enumCase(value, "terminator-pointer",
+                                          DefinedAtom::typeTerminatorPtr);
+    io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
+    io.enumCase(value, "objc-class-pointer",
+                                          DefinedAtom::typeObjCClassPtr);
+    io.enumCase(value, "objc-category-list",
+                                          DefinedAtom::typeObjC2CategoryList);
+    io.enumCase(value, "objc-image-info",
+                                          DefinedAtom::typeObjCImageInfo);
+    io.enumCase(value, "objc-method-list",
+                                          DefinedAtom::typeObjCMethodList);
+    io.enumCase(value, "objc-class1",     DefinedAtom::typeObjC1Class);
+    io.enumCase(value, "dtraceDOF",       DefinedAtom::typeDTraceDOF);
+    io.enumCase(value, "interposing-tuples",
+                                          DefinedAtom::typeInterposingTuples);
+    io.enumCase(value, "lto-temp",        DefinedAtom::typeTempLTO);
+    io.enumCase(value, "compact-unwind",  DefinedAtom::typeCompactUnwindInfo);
+    io.enumCase(value, "unwind-info",     DefinedAtom::typeProcessedUnwindInfo);
+    io.enumCase(value, "tlv-thunk",       DefinedAtom::typeThunkTLV);
+    io.enumCase(value, "tlv-data",        DefinedAtom::typeTLVInitialData);
+    io.enumCase(value, "tlv-zero-fill",   DefinedAtom::typeTLVInitialZeroFill);
+    io.enumCase(value, "tlv-initializer-ptr",
+                                          DefinedAtom::typeTLVInitializerPtr);
+    io.enumCase(value, "mach_header",     DefinedAtom::typeMachHeader);
+    io.enumCase(value, "dso_handle",      DefinedAtom::typeDSOHandle);
+    io.enumCase(value, "sectcreate",      DefinedAtom::typeSectCreate);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
+  static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
+    io.enumCase(value, "never",       lld::UndefinedAtom::canBeNullNever);
+    io.enumCase(value, "at-runtime",  lld::UndefinedAtom::canBeNullAtRuntime);
+    io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
+  static void enumeration(IO &io, ShlibCanBeNull &value) {
+    io.enumCase(value, "never",      false);
+    io.enumCase(value, "at-runtime", true);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
+  static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
+    io.enumCase(value, "code",    lld::SharedLibraryAtom::Type::Code);
+    io.enumCase(value, "data",    lld::SharedLibraryAtom::Type::Data);
+    io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
+  }
+};
+
+/// This is a custom formatter for lld::DefinedAtom::Alignment.  Values look
+/// like:
+///     8           # 8-byte aligned
+///     7 mod 16    # 16-byte aligned plus 7 bytes
+template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
+  static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
+                     raw_ostream &out) {
+    if (value.modulus == 0) {
+      out << llvm::format("%d", value.value);
+    } else {
+      out << llvm::format("%d mod %d", value.modulus, value.value);
+    }
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt,
+                         lld::DefinedAtom::Alignment &value) {
+    value.modulus = 0;
+    size_t modStart = scalar.find("mod");
+    if (modStart != StringRef::npos) {
+      StringRef modStr = scalar.slice(0, modStart);
+      modStr = modStr.rtrim();
+      unsigned int modulus;
+      if (modStr.getAsInteger(0, modulus)) {
+        return "malformed alignment modulus";
+      }
+      value.modulus = modulus;
+      scalar = scalar.drop_front(modStart + 3);
+      scalar = scalar.ltrim();
+    }
+    unsigned int power;
+    if (scalar.getAsInteger(0, power)) {
+      return "malformed alignment power";
+    }
+    value.value = power;
+    if (value.modulus >= power) {
+      return "malformed alignment, modulus too large for power";
+    }
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<FileKinds> {
+  static void enumeration(IO &io, FileKinds &value) {
+    io.enumCase(value, "object",        fileKindObjectAtoms);
+    io.enumCase(value, "archive",       fileKindArchive);
+    io.enumCase(value, "object-mach-o", fileKindObjectMachO);
+  }
+};
+
+template <> struct MappingTraits<ArchMember> {
+  static void mapping(IO &io, ArchMember &member) {
+    io.mapOptional("kind",    member._kind, fileKindObjectAtoms);
+    io.mapOptional("name",    member._name);
+    io.mapRequired("content", member._content);
+  }
+};
+
+// Declare that an AtomList is a yaml sequence.
+template <typename T> struct SequenceTraits<AtomList<T> > {
+  static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
+  static T *&element(IO &io, AtomList<T> &seq, size_t index) {
+    if (index >= seq._atoms.size())
+      seq._atoms.resize(index + 1);
+    return seq._atoms[index].get();
+  }
+};
+
+// Declare that an AtomRange is a yaml sequence.
+template <typename T> struct SequenceTraits<File::AtomRange<T> > {
+  static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
+  static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
+    assert(io.outputting() && "AtomRange only used when outputting");
+    assert(index < seq.size() && "Out of range access");
+    return seq[index].get();
+  }
+};
+
+// Used to allow DefinedAtom content bytes to be a flow sequence of
+// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
+template <> struct ScalarTraits<ImplicitHex8> {
+  static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
+    uint8_t num = val;
+    out << llvm::format("%02X", num);
+  }
+
+  static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
+    unsigned long long n;
+    if (getAsUnsignedInteger(str, 16, n))
+      return "invalid two-digit-hex number";
+    if (n > 0xFF)
+      return "out of range two-digit-hex number";
+    val = n;
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+// YAML conversion for std::vector<const lld::File*>
+template <> struct DocumentListTraits<std::vector<const lld::File *> > {
+  static size_t size(IO &io, std::vector<const lld::File *> &seq) {
+    return seq.size();
+  }
+  static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
+                                   size_t index) {
+    if (index >= seq.size())
+      seq.resize(index + 1);
+    return seq[index];
+  }
+};
+
+// YAML conversion for const lld::File*
+template <> struct MappingTraits<const lld::File *> {
+
+  class NormArchiveFile : public lld::ArchiveLibraryFile {
+  public:
+    NormArchiveFile(IO &io) : ArchiveLibraryFile(""), _path() {}
+    NormArchiveFile(IO &io, const lld::File *file)
+        : ArchiveLibraryFile(file->path()), _path(file->path()) {
+      // If we want to support writing archives, this constructor would
+      // need to populate _members.
+    }
+
+    const lld::File *denormalize(IO &io) { return this; }
+
+    const AtomRange<lld::DefinedAtom> defined() const override {
+      return _noDefinedAtoms;
+    }
+
+    const AtomRange<lld::UndefinedAtom> undefined() const override {
+      return _noUndefinedAtoms;
+    }
+
+    const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+      return _noSharedLibraryAtoms;
+    }
+
+    const AtomRange<lld::AbsoluteAtom> absolute() const override {
+      return _noAbsoluteAtoms;
+    }
+
+    void clearAtoms() override {
+      _noDefinedAtoms.clear();
+      _noUndefinedAtoms.clear();
+      _noSharedLibraryAtoms.clear();
+      _noAbsoluteAtoms.clear();
+    }
+
+    File *find(StringRef name) override {
+      for (const ArchMember &member : _members)
+        for (const lld::DefinedAtom *atom : member._content->defined())
+          if (name == atom->name())
+            return const_cast<File *>(member._content);
+      return nullptr;
+    }
+
+    std::error_code
+    parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+      return std::error_code();
+    }
+
+    StringRef               _path;
+    std::vector<ArchMember> _members;
+  };
+
+  class NormalizedFile : public lld::File {
+  public:
+    NormalizedFile(IO &io)
+      : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
+        _definedAtomsRef(_definedAtoms._atoms),
+        _undefinedAtomsRef(_undefinedAtoms._atoms),
+        _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
+        _absoluteAtomsRef(_absoluteAtoms._atoms) {}
+    NormalizedFile(IO &io, const lld::File *file)
+        : File(file->path(), kindNormalizedObject), _io(io),
+          _rnb(new RefNameBuilder(*file)), _path(file->path()),
+        _definedAtomsRef(file->defined()),
+        _undefinedAtomsRef(file->undefined()),
+        _sharedLibraryAtomsRef(file->sharedLibrary()),
+        _absoluteAtomsRef(file->absolute()) {
+    }
+
+    ~NormalizedFile() override {
+    }
+
+    const lld::File *denormalize(IO &io);
+
+    const AtomRange<lld::DefinedAtom> defined() const override {
+      return _definedAtomsRef;
+    }
+
+    const AtomRange<lld::UndefinedAtom> undefined() const override {
+      return _undefinedAtomsRef;
+    }
+
+    const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+      return _sharedLibraryAtomsRef;
+    }
+
+    const AtomRange<lld::AbsoluteAtom> absolute() const override {
+      return _absoluteAtomsRef;
+    }
+
+    void clearAtoms() override {
+      _definedAtoms._atoms.clear();
+      _undefinedAtoms._atoms.clear();
+      _sharedLibraryAtoms._atoms.clear();
+      _absoluteAtoms._atoms.clear();
+    }
+
+    // Allocate a new copy of this string in _storage, so the strings
+    // can be freed when File is destroyed.
+    StringRef copyString(StringRef str) {
+      char *s = _storage.Allocate<char>(str.size());
+      memcpy(s, str.data(), str.size());
+      return StringRef(s, str.size());
+    }
+
+    IO                                  &_io;
+    std::unique_ptr<RefNameBuilder> _rnb;
+    StringRef                            _path;
+    AtomList<lld::DefinedAtom>           _definedAtoms;
+    AtomList<lld::UndefinedAtom>         _undefinedAtoms;
+    AtomList<lld::SharedLibraryAtom>     _sharedLibraryAtoms;
+    AtomList<lld::AbsoluteAtom>          _absoluteAtoms;
+    AtomRange<lld::DefinedAtom>          _definedAtomsRef;
+    AtomRange<lld::UndefinedAtom>        _undefinedAtomsRef;
+    AtomRange<lld::SharedLibraryAtom>    _sharedLibraryAtomsRef;
+    AtomRange<lld::AbsoluteAtom>         _absoluteAtomsRef;
+    llvm::BumpPtrAllocator               _storage;
+  };
+
+  static void mapping(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    assert(info != nullptr);
+    // Let any register tag handler process this.
+    if (info->_registry && info->_registry->handleTaggedDoc(io, file))
+      return;
+    // If no registered handler claims this tag and there is no tag,
+    // grandfather in as "!native".
+    if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
+      mappingAtoms(io, file);
+  }
+
+  static void mappingAtoms(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedFile, const lld::File *>
+      keys(io, file, nullptr);
+    assert(info != nullptr);
+    info->_file = keys.operator->();
+
+    io.mapOptional("path",                 keys->_path);
+
+    if (io.outputting()) {
+      io.mapOptional("defined-atoms",        keys->_definedAtomsRef);
+      io.mapOptional("undefined-atoms",      keys->_undefinedAtomsRef);
+      io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
+      io.mapOptional("absolute-atoms",       keys->_absoluteAtomsRef);
+    } else {
+      io.mapOptional("defined-atoms",        keys->_definedAtoms);
+      io.mapOptional("undefined-atoms",      keys->_undefinedAtoms);
+      io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+      io.mapOptional("absolute-atoms",       keys->_absoluteAtoms);
+    }
+  }
+
+  static void mappingArchive(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormArchiveFile, const lld::File *>
+      keys(io, file, &info->_file->allocator());
+
+    io.mapOptional("path",    keys->_path);
+    io.mapOptional("members", keys->_members);
+  }
+};
+
+// YAML conversion for const lld::Reference*
+template <> struct MappingTraits<const lld::Reference *> {
+
+  class NormalizedReference : public lld::Reference {
+  public:
+    NormalizedReference(IO &io)
+        : lld::Reference(lld::Reference::KindNamespace::all,
+                         lld::Reference::KindArch::all, 0),
+          _target(nullptr), _targetName(), _offset(0), _addend(0), _tag(0) {}
+
+    NormalizedReference(IO &io, const lld::Reference *ref)
+        : lld::Reference(ref->kindNamespace(), ref->kindArch(),
+                         ref->kindValue()),
+          _target(nullptr), _targetName(targetName(io, ref)),
+          _offset(ref->offsetInAtom()), _addend(ref->addend()),
+          _tag(ref->tag()) {
+      _mappedKind.ns = ref->kindNamespace();
+      _mappedKind.arch = ref->kindArch();
+      _mappedKind.value = ref->kindValue();
+    }
+
+    const lld::Reference *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_targetName.empty())
+        _targetName = f->copyString(_targetName);
+      DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+                                        << "created Reference to name: '"
+                                        << _targetName << "' ("
+                                        << (const void *)_targetName.data()
+                                        << ", " << _targetName.size() << ")\n");
+      setKindNamespace(_mappedKind.ns);
+      setKindArch(_mappedKind.arch);
+      setKindValue(_mappedKind.value);
+      return this;
+    }
+    void bind(const RefNameResolver &);
+    static StringRef targetName(IO &io, const lld::Reference *ref);
+
+    uint64_t offsetInAtom() const override { return _offset; }
+    const lld::Atom *target() const override { return _target; }
+    Addend addend() const override { return _addend; }
+    void setAddend(Addend a) override { _addend = a; }
+    void setTarget(const lld::Atom *a) override { _target = a; }
+
+    const lld::Atom *_target;
+    StringRef        _targetName;
+    uint32_t         _offset;
+    Addend           _addend;
+    RefKind          _mappedKind;
+    uint32_t         _tag;
+  };
+
+  static void mapping(IO &io, const lld::Reference *&ref) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
+        io, ref, &info->_file->allocator());
+
+    io.mapRequired("kind",   keys->_mappedKind);
+    io.mapOptional("offset", keys->_offset);
+    io.mapOptional("target", keys->_targetName);
+    io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
+    io.mapOptional("tag",    keys->_tag, 0u);
+  }
+};
+
+// YAML conversion for const lld::DefinedAtom*
+template <> struct MappingTraits<const lld::DefinedAtom *> {
+
+  class NormalizedAtom : public lld::DefinedAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _name(), _refName(), _contentType(),
+          _alignment(1), _content(), _references() {
+      static uint32_t ordinalCounter = 1;
+      _ordinal = ordinalCounter++;
+    }
+    NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()), _refName(),
+          _scope(atom->scope()), _interpose(atom->interposable()),
+          _merge(atom->merge()), _contentType(atom->contentType()),
+          _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
+          _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
+          _codeModel(atom->codeModel()),
+          _permissions(atom->permissions()), _size(atom->size()),
+          _sectionName(atom->customSectionName()),
+          _sectionSize(atom->sectionSize()) {
+      for (const lld::Reference *r : *atom)
+        _references.push_back(r);
+      if (!atom->occupiesDiskSpace())
+        return;
+      ArrayRef<uint8_t> cont = atom->rawContent();
+      _content.reserve(cont.size());
+      for (uint8_t x : cont)
+        _content.push_back(x);
+    }
+
+    ~NormalizedAtom() override = default;
+
+    const lld::DefinedAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+      if (!_refName.empty())
+        _refName = f->copyString(_refName);
+      if (!_sectionName.empty())
+        _sectionName = f->copyString(_sectionName);
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created DefinedAtom named: '" << _name
+                                   << "' (" << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+
+    void bind(const RefNameResolver &);
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    uint64_t size() const override { return _size; }
+    Scope scope() const override { return _scope; }
+    Interposable interposable() const override { return _interpose; }
+    Merge merge() const override { return _merge; }
+    ContentType contentType() const override { return _contentType; }
+    Alignment alignment() const override { return _alignment; }
+    SectionChoice sectionChoice() const override { return _sectionChoice; }
+    StringRef customSectionName() const override { return _sectionName; }
+    uint64_t sectionSize() const override { return _sectionSize; }
+    DeadStripKind deadStrip() const override { return _deadStrip; }
+    DynamicExport dynamicExport() const override { return _dynamicExport; }
+    CodeModel codeModel() const override { return _codeModel; }
+    ContentPermissions permissions() const override { return _permissions; }
+    ArrayRef<uint8_t> rawContent() const override {
+      if (!occupiesDiskSpace())
+        return ArrayRef<uint8_t>();
+      return ArrayRef<uint8_t>(
+          reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
+    }
+
+    uint64_t ordinal() const override { return _ordinal; }
+
+    reference_iterator begin() const override {
+      uintptr_t index = 0;
+      const void *it = reinterpret_cast<const void *>(index);
+      return reference_iterator(*this, it);
+    }
+    reference_iterator end() const override {
+      uintptr_t index = _references.size();
+      const void *it = reinterpret_cast<const void *>(index);
+      return reference_iterator(*this, it);
+    }
+    const lld::Reference *derefIterator(const void *it) const override {
+      uintptr_t index = reinterpret_cast<uintptr_t>(it);
+      assert(index < _references.size());
+      return _references[index];
+    }
+    void incrementIterator(const void *&it) const override {
+      uintptr_t index = reinterpret_cast<uintptr_t>(it);
+      ++index;
+      it = reinterpret_cast<const void *>(index);
+    }
+
+    void addReference(Reference::KindNamespace ns,
+                      Reference::KindArch arch,
+                      Reference::KindValue kindValue, uint64_t off,
+                      const Atom *target, Reference::Addend a) override {
+      assert(target && "trying to create reference to nothing");
+      auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
+                                                           off, target, a);
+      _references.push_back(node);
+    }
+
+    const lld::File                    &_file;
+    StringRef                           _name;
+    StringRef                           _refName;
+    Scope                               _scope;
+    Interposable                        _interpose;
+    Merge                               _merge;
+    ContentType                         _contentType;
+    Alignment                           _alignment;
+    SectionChoice                       _sectionChoice;
+    DeadStripKind                       _deadStrip;
+    DynamicExport                       _dynamicExport;
+    CodeModel                           _codeModel;
+    ContentPermissions                  _permissions;
+    uint32_t                            _ordinal;
+    std::vector<ImplicitHex8>           _content;
+    uint64_t                            _size;
+    StringRef                           _sectionName;
+    uint64_t                            _sectionSize;
+    std::vector<const lld::Reference *> _references;
+  };
+
+  static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
+        io, atom, &info->_file->allocator());
+    if (io.outputting()) {
+      // If writing YAML, check if atom needs a ref-name.
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      assert(info != nullptr);
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      assert(f);
+      assert(f->_rnb);
+      if (f->_rnb->hasRefName(atom)) {
+        keys->_refName = f->_rnb->refName(atom);
+      }
+    }
+
+    io.mapOptional("name",             keys->_name,    StringRef());
+    io.mapOptional("ref-name",         keys->_refName, StringRef());
+    io.mapOptional("scope",            keys->_scope,
+                                         DefinedAtom::scopeTranslationUnit);
+    io.mapOptional("type",             keys->_contentType,
+                                         DefinedAtom::typeCode);
+    io.mapOptional("content",          keys->_content);
+    io.mapOptional("size",             keys->_size, (uint64_t)keys->_content.size());
+    io.mapOptional("interposable",     keys->_interpose,
+                                         DefinedAtom::interposeNo);
+    io.mapOptional("merge",            keys->_merge, DefinedAtom::mergeNo);
+    io.mapOptional("alignment",        keys->_alignment,
+                                         DefinedAtom::Alignment(1));
+    io.mapOptional("section-choice",   keys->_sectionChoice,
+                                         DefinedAtom::sectionBasedOnContent);
+    io.mapOptional("section-name",     keys->_sectionName, StringRef());
+    io.mapOptional("section-size",     keys->_sectionSize, (uint64_t)0);
+    io.mapOptional("dead-strip",       keys->_deadStrip,
+                                         DefinedAtom::deadStripNormal);
+    io.mapOptional("dynamic-export",   keys->_dynamicExport,
+                                         DefinedAtom::dynamicExportNormal);
+    io.mapOptional("code-model",       keys->_codeModel, DefinedAtom::codeNA);
+    // default permissions based on content type
+    io.mapOptional("permissions",      keys->_permissions,
+                                         DefinedAtom::permissions(
+                                                          keys->_contentType));
+    io.mapOptional("references",       keys->_references);
+  }
+};
+
+template <> struct MappingTraits<lld::DefinedAtom *> {
+  static void mapping(IO &io, lld::DefinedAtom *&atom) {
+    const lld::DefinedAtom *atomPtr = atom;
+    MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::DefinedAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::UndefinedAtom*
+template <> struct MappingTraits<const lld::UndefinedAtom *> {
+
+  class NormalizedAtom : public lld::UndefinedAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {}
+
+    NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _canBeNull(atom->canBeNull()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::UndefinedAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created UndefinedAtom named: '" << _name
+                      << "' (" << (const void *)_name.data() << ", "
+                      << _name.size() << ")\n");
+      return this;
+    }
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    CanBeNull canBeNull() const override { return _canBeNull; }
+
+    const lld::File     &_file;
+    StringRef            _name;
+    CanBeNull            _canBeNull;
+  };
+
+  static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
+        io, atom, &info->_file->allocator());
+
+    io.mapRequired("name",        keys->_name);
+    io.mapOptional("can-be-null", keys->_canBeNull,
+                                  lld::UndefinedAtom::canBeNullNever);
+  }
+};
+
+template <> struct MappingTraits<lld::UndefinedAtom *> {
+  static void mapping(IO &io, lld::UndefinedAtom *&atom) {
+    const lld::UndefinedAtom *atomPtr = atom;
+    MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::UndefinedAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::SharedLibraryAtom*
+template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
+  class NormalizedAtom : public lld::SharedLibraryAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _name(), _loadName(), _canBeNull(false),
+          _type(Type::Unknown), _size(0) {}
+    NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
+          _type(atom->type()), _size(atom->size()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::SharedLibraryAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+      if (!_loadName.empty())
+        _loadName = f->copyString(_loadName);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created SharedLibraryAtom named: '"
+                                   << _name << "' ("
+                                   << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    StringRef loadName() const override { return _loadName; }
+    bool canBeNullAtRuntime() const override { return _canBeNull; }
+    Type type() const override { return _type; }
+    uint64_t size() const override { return _size; }
+
+    const lld::File &_file;
+    StringRef        _name;
+    StringRef        _loadName;
+    ShlibCanBeNull   _canBeNull;
+    Type             _type;
+    uint64_t         _size;
+  };
+
+  static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
+
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
+    keys(io, atom, &info->_file->allocator());
+
+    io.mapRequired("name",        keys->_name);
+    io.mapOptional("load-name",   keys->_loadName);
+    io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
+    io.mapOptional("type",        keys->_type, SharedLibraryAtom::Type::Code);
+    io.mapOptional("size",        keys->_size, uint64_t(0));
+  }
+};
+
+template <> struct MappingTraits<lld::SharedLibraryAtom *> {
+  static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
+    const lld::SharedLibraryAtom *atomPtr = atom;
+    MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::AbsoluteAtom*
+template <> struct MappingTraits<const lld::AbsoluteAtom *> {
+
+  class NormalizedAtom : public lld::AbsoluteAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _name(), _scope(), _value(0) {}
+    NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _scope(atom->scope()), _value(atom->value()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::AbsoluteAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created AbsoluteAtom named: '" << _name
+                                   << "' (" << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    uint64_t value() const override { return _value; }
+    Scope scope() const override { return _scope; }
+
+    const lld::File &_file;
+    StringRef        _name;
+    StringRef        _refName;
+    Scope            _scope;
+    Hex64            _value;
+  };
+
+  static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
+        io, atom, &info->_file->allocator());
+
+    if (io.outputting()) {
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      assert(f);
+      assert(f->_rnb);
+      if (f->_rnb->hasRefName(atom)) {
+        keys->_refName = f->_rnb->refName(atom);
+      }
+    }
+
+    io.mapRequired("name",     keys->_name);
+    io.mapOptional("ref-name", keys->_refName, StringRef());
+    io.mapOptional("scope",    keys->_scope);
+    io.mapRequired("value",    keys->_value);
+  }
+};
+
+template <> struct MappingTraits<lld::AbsoluteAtom *> {
+  static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
+    const lld::AbsoluteAtom *atomPtr = atom;
+    MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
+  }
+};
+
+} // end namespace llvm
+} // end namespace yaml
+
+RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
+  typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+  NormalizedAtom;
+  for (const lld::DefinedAtom *a : file->defined()) {
+    const auto *na = (const NormalizedAtom *)a;
+    if (!na->_refName.empty())
+      add(na->_refName, a);
+    else if (!na->_name.empty())
+      add(na->_name, a);
+  }
+
+  for (const lld::UndefinedAtom *a : file->undefined())
+    add(a->name(), a);
+
+  for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
+    add(a->name(), a);
+
+  typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
+  for (const lld::AbsoluteAtom *a : file->absolute()) {
+    const auto *na = (const NormAbsAtom *)a;
+    if (na->_refName.empty())
+      add(na->_name, a);
+    else
+      add(na->_refName, a);
+  }
+}
+
+inline const lld::File *
+MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
+  typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+  NormalizedAtom;
+
+  RefNameResolver nameResolver(this, io);
+  // Now that all atoms are parsed, references can be bound.
+  for (const lld::DefinedAtom *a : this->defined()) {
+    auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
+    normAtom->bind(nameResolver);
+  }
+
+  return this;
+}
+
+inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
+    const RefNameResolver &resolver) {
+  typedef MappingTraits<const lld::Reference *>::NormalizedReference
+  NormalizedReference;
+  for (const lld::Reference *ref : _references) {
+    auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
+    normRef->bind(resolver);
+  }
+}
+
+inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
+    const RefNameResolver &resolver) {
+  _target = resolver.lookup(_targetName);
+}
+
+inline StringRef
+MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
+    IO &io, const lld::Reference *ref) {
+  if (ref->target() == nullptr)
+    return StringRef();
+  YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+  assert(info != nullptr);
+  typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+  NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+  RefNameBuilder &rnb = *f->_rnb;
+  if (rnb.hasRefName(ref->target()))
+    return rnb.refName(ref->target());
+  return ref->target()->name();
+}
+
+namespace lld {
+namespace yaml {
+
+class Writer : public lld::Writer {
+public:
+  Writer(const LinkingContext &context) : _ctx(context) {}
+
+  llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
+    // Create stream to path.
+    std::error_code ec;
+    llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
+    if (ec)
+      return llvm::errorCodeToError(ec);
+
+    // Create yaml Output writer, using yaml options for context.
+    YamlContext yamlContext;
+    yamlContext._ctx = &_ctx;
+    yamlContext._registry = &_ctx.registry();
+    llvm::yaml::Output yout(out, &yamlContext);
+
+    // Write yaml output.
+    const lld::File *fileRef = &file;
+    yout << fileRef;
+
+    return llvm::Error();
+  }
+
+private:
+  const LinkingContext &_ctx;
+};
+
+} // end namespace yaml
+
+namespace {
+
+/// Handles !native tagged yaml documents.
+class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+    if (io.mapTag("!native")) {
+      MappingTraits<const lld::File *>::mappingAtoms(io, file);
+      return true;
+    }
+    return false;
+  }
+};
+
+/// Handles !archive tagged yaml documents.
+class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+    if (io.mapTag("!archive")) {
+      MappingTraits<const lld::File *>::mappingArchive(io, file);
+      return true;
+    }
+    return false;
+  }
+};
+
+class YAMLReader : public Reader {
+public:
+  YAMLReader(const Registry &registry) : _registry(registry) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    StringRef name = mb.getBufferIdentifier();
+    return name.endswith(".objtxt") || name.endswith(".yaml");
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const class Registry &) const override {
+    // Create YAML Input Reader.
+    YamlContext yamlContext;
+    yamlContext._registry = &_registry;
+    yamlContext._path = mb->getBufferIdentifier();
+    llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+    // Fill vector with File objects created by parsing yaml.
+    std::vector<const lld::File *> createdFiles;
+    yin >> createdFiles;
+    assert(createdFiles.size() == 1);
+
+    // Error out now if there were parsing errors.
+    if (yin.error())
+      return make_error_code(lld::YamlReaderError::illegal_value);
+
+    std::shared_ptr<MemoryBuffer> smb(mb.release());
+    const File *file = createdFiles[0];
+    // Note: loadFile() should return vector of *const* File
+    File *f = const_cast<File *>(file);
+    f->setLastError(std::error_code());
+    f->setSharedMemoryBuffer(smb);
+    return std::unique_ptr<File>(f);
+  }
+
+private:
+  const Registry &_registry;
+};
+
+} // end anonymous namespace
+
+void Registry::addSupportYamlFiles() {
+  add(std::unique_ptr<Reader>(new YAMLReader(*this)));
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                                    new NativeYamlIOTaggedDocumentHandler()));
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                                    new ArchiveYamlIOTaggedDocumentHandler()));
+}
+
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
+  return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
+}
+
+} // end namespace lld
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..88cd128
--- /dev/null
@@ -0,0 +1,47 @@
+set(LLVM_SOURCE_DIR "${LLVM_MAIN_SRC_DIR}")
+set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
+set(LLVM_BUILD_MODE "%(build_mode)s")
+set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}/%(build_config)s")
+set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/%(build_config)s")
+set(CLANG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+set(CLANG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
+if(BUILD_SHARED_LIBS)
+  set(ENABLE_SHARED 1)
+else()
+  set(ENABLE_SHARED 0)
+endif(BUILD_SHARED_LIBS)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  )
+
+set(LLD_TEST_DEPS
+  FileCheck not llvm-ar llvm-as llvm-dis llvm-nm llc
+  lld llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml
+  llvm-mc llvm-nm llvm-lib
+  )
+if (LLVM_INCLUDE_TESTS)
+  set(LLD_TEST_DEPS ${LLD_TEST_DEPS} LLDUnitTests)
+endif()
+
+set(LLD_TEST_PARAMS
+  lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  )
+
+add_lit_testsuite(check-lld "Running lld test suite"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  PARAMS lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+       lld_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  DEPENDS ${LLD_TEST_DEPS}
+  )
+
+set_target_properties(check-lld PROPERTIES FOLDER "lld tests")
+
+# Add a legacy target spelling: lld-test
+add_custom_target(lld-test)
+add_dependencies(lld-test check-lld)
+set_target_properties(lld-test PROPERTIES FOLDER "lld tests")
diff --git a/test/COFF/Inputs/armnt-executable.obj.yaml b/test/COFF/Inputs/armnt-executable.obj.yaml
new file mode 100644 (file)
index 0000000..5c42b90
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '7047'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          2
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/armnt-executable.s b/test/COFF/Inputs/armnt-executable.s
new file mode 100644 (file)
index 0000000..7e1a8ce
--- /dev/null
@@ -0,0 +1,13 @@
+# void mainCRTStartup() {}
+       .syntax unified
+       .thumb
+       .text
+       .def mainCRTStartup
+               .scl 2
+               .type 32
+       .endef
+       .global mainCRTStartup
+       .align 2
+       .thumb_func
+mainCRTStartup:
+       bx lr
diff --git a/test/COFF/Inputs/conflict.ll b/test/COFF/Inputs/conflict.ll
new file mode 100644 (file)
index 0000000..8cd7d70
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
diff --git a/test/COFF/Inputs/entry-mangled.ll b/test/COFF/Inputs/entry-mangled.ll
new file mode 100644 (file)
index 0000000..b6fac21
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc18.0.0"
+
+define void @"\01?main@@YAHXZ"() {
+  ret void
+}
diff --git a/test/COFF/Inputs/export.ll b/test/COFF/Inputs/export.ll
new file mode 100644 (file)
index 0000000..d254683
--- /dev/null
@@ -0,0 +1,18 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @_DllMainCRTStartup() {
+  ret void
+}
+
+define void @exportfn1() {
+  ret void
+}
+
+define void @exportfn2() {
+  ret void
+}
+
+define dllexport void @exportfn3() {
+  ret void
+}
diff --git a/test/COFF/Inputs/export.yaml b/test/COFF/Inputs/export.yaml
new file mode 100644 (file)
index 0000000..1ccf090
--- /dev/null
@@ -0,0 +1,57 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f6578706f72743a6578706f7274666e3300  # /export:exportfn3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _DllMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           8
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn2
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn3
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?mangled@@YAHXZ'
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/export2.yaml b/test/COFF/Inputs/export2.yaml
new file mode 100644 (file)
index 0000000..37fa4c7
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '?mangled2@@YAHXZ'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/hello32.yaml b/test/COFF/Inputs/hello32.yaml
new file mode 100644 (file)
index 0000000..09e76f1
--- /dev/null
@@ -0,0 +1,82 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     33DB538D0500000000508D05000000005053E80000000050E800000000
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      caption
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  19
+        SymbolName:      '_MessageBoxA@16'
+        Type:            IMAGE_REL_I386_REL32
+      - VirtualAddress:  25
+        SymbolName:      '_ExitProcess@4'
+        Type:            IMAGE_REL_I386_REL32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     48656C6C6F0048656C6C6F20576F726C642100
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          29
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          19
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '_ExitProcess@4'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '_MessageBoxA@16'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '_main@0'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/hello64.asm b/test/COFF/Inputs/hello64.asm
new file mode 100644 (file)
index 0000000..6605213
--- /dev/null
@@ -0,0 +1,24 @@
+;; ml64 hello64.asm /link /subsystem:windows /defaultlib:kernel32 \
+;;    /defaultlib:user32 /out:hello64.exe /entry:main
+
+extern ExitProcess : PROC
+extern MessageBoxA : PROC
+extern ImportByOrdinal: PROC
+
+.data
+        caption db 'Hello', 0
+        message db 'Hello World!', 0
+
+.code
+main PROC
+        sub rsp,28h
+        mov rcx, 0
+        lea rdx, message
+        lea r8, caption
+        mov r9d, 0
+        call MessageBoxA
+        mov ecx, 0
+        call ExitProcess
+        call ImportByOrdinal
+main ENDP
+END
diff --git a/test/COFF/Inputs/hello64.obj b/test/COFF/Inputs/hello64.obj
new file mode 100644 (file)
index 0000000..90c1ce4
Binary files /dev/null and b/test/COFF/Inputs/hello64.obj differ
diff --git a/test/COFF/Inputs/import.yaml b/test/COFF/Inputs/import.yaml
new file mode 100644 (file)
index 0000000..4934001
--- /dev/null
@@ -0,0 +1,41 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn2
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/imports-mangle.lib b/test/COFF/Inputs/imports-mangle.lib
new file mode 100644 (file)
index 0000000..f3c722a
Binary files /dev/null and b/test/COFF/Inputs/imports-mangle.lib differ
diff --git a/test/COFF/Inputs/include1a.yaml b/test/COFF/Inputs/include1a.yaml
new file mode 100644 (file)
index 0000000..f61e0e0
--- /dev/null
@@ -0,0 +1,33 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a666f6f00  # /include:foo
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/include1b.yaml b/test/COFF/Inputs/include1b.yaml
new file mode 100644 (file)
index 0000000..78d1b92
--- /dev/null
@@ -0,0 +1,33 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a62617200  # /include:bar
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/include1c.yaml b/test/COFF/Inputs/include1c.yaml
new file mode 100644 (file)
index 0000000..6cf9db6
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            bar
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/library.lib b/test/COFF/Inputs/library.lib
new file mode 100755 (executable)
index 0000000..2f4207d
Binary files /dev/null and b/test/COFF/Inputs/library.lib differ
diff --git a/test/COFF/Inputs/lto-chkstk-chkstk.s b/test/COFF/Inputs/lto-chkstk-chkstk.s
new file mode 100644 (file)
index 0000000..292b30d
--- /dev/null
@@ -0,0 +1,3 @@
+.globl __chkstk
+__chkstk:
+ret
diff --git a/test/COFF/Inputs/lto-chkstk-foo.s b/test/COFF/Inputs/lto-chkstk-foo.s
new file mode 100644 (file)
index 0000000..a69f870
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret
diff --git a/test/COFF/Inputs/lto-comdat1.ll b/test/COFF/Inputs/lto-comdat1.ll
new file mode 100644 (file)
index 0000000..7a9f50c
--- /dev/null
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define void @f1() {
+  call void @comdat()
+  ret void
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-comdat2.ll b/test/COFF/Inputs/lto-comdat2.ll
new file mode 100644 (file)
index 0000000..c2af2a4
--- /dev/null
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define void @f2() {
+  call void @comdat()
+  ret void
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-dep.ll b/test/COFF/Inputs/lto-dep.ll
new file mode 100644 (file)
index 0000000..d6d47f2
--- /dev/null
@@ -0,0 +1,10 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
+
+define internal void @internal() {
+  ret void
+}
diff --git a/test/COFF/Inputs/machine-x64.yaml b/test/COFF/Inputs/machine-x64.yaml
new file mode 100644 (file)
index 0000000..36bdfe6
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/machine-x86.yaml b/test/COFF/Inputs/machine-x86.yaml
new file mode 100644 (file)
index 0000000..197143b
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/manifestinput.test b/test/COFF/Inputs/manifestinput.test
new file mode 100644 (file)
index 0000000..c657392
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type='win32'
+                        name='Microsoft.Windows.Common-Controls'
+                        version='6.0.0.0'
+                        processorArchitecture='*'
+                        publicKeyToken='6595b64144ccf1df'
+                        language='*' />
+    </dependentAssembly>
+  </dependency>
+</assembly>
diff --git a/test/COFF/Inputs/resource.res b/test/COFF/Inputs/resource.res
new file mode 100644 (file)
index 0000000..f1c799f
Binary files /dev/null and b/test/COFF/Inputs/resource.res differ
diff --git a/test/COFF/Inputs/ret42.lib b/test/COFF/Inputs/ret42.lib
new file mode 100644 (file)
index 0000000..f60a9cd
Binary files /dev/null and b/test/COFF/Inputs/ret42.lib differ
diff --git a/test/COFF/Inputs/ret42.obj b/test/COFF/Inputs/ret42.obj
new file mode 100644 (file)
index 0000000..1765f0e
Binary files /dev/null and b/test/COFF/Inputs/ret42.obj differ
diff --git a/test/COFF/Inputs/ret42.yaml b/test/COFF/Inputs/ret42.yaml
new file mode 100644 (file)
index 0000000..b980901
--- /dev/null
@@ -0,0 +1,45 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     ''
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/std32.lib b/test/COFF/Inputs/std32.lib
new file mode 100644 (file)
index 0000000..7401ff3
Binary files /dev/null and b/test/COFF/Inputs/std32.lib differ
diff --git a/test/COFF/Inputs/std64.lib b/test/COFF/Inputs/std64.lib
new file mode 100644 (file)
index 0000000..bbd223c
Binary files /dev/null and b/test/COFF/Inputs/std64.lib differ
diff --git a/test/COFF/Inputs/weak-external.ll b/test/COFF/Inputs/weak-external.ll
new file mode 100644 (file)
index 0000000..4775d50
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @g() {
+  ret void
+}
diff --git a/test/COFF/Inputs/weak-external2.ll b/test/COFF/Inputs/weak-external2.ll
new file mode 100644 (file)
index 0000000..2102c3b
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @f() {
+  ret void
+}
diff --git a/test/COFF/Inputs/weak-external3.ll b/test/COFF/Inputs/weak-external3.ll
new file mode 100644 (file)
index 0000000..f9a5136
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+@f = weak alias void(), void()* @g
+
+define void @g() {
+  ret void
+}
diff --git a/test/COFF/alternatename.test b/test/COFF/alternatename.test
new file mode 100644 (file)
index 0000000..1be61ad
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /entry:foo /subsystem:console \
+# RUN:   /alternatename:foo=main /out:%t.exe %t.obj
+# RUN: lld-link /entry:foo /subsystem:console \
+# RUN:   /alternatename:foo=main \
+# RUN:   /alternatename:foo=main \
+# RUN:   /alternatename:nosuchsym1=nosuchsym2 \
+# RUN:   /out:%t.exe %t.obj
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /subsystem:console /out:%t.exe %t.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     ''
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f616c7465726e6174656e616d653a666f6f3d6d61696e00  # /alternatename:foo=main
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/ar-comdat.test b/test/COFF/ar-comdat.test
new file mode 100644 (file)
index 0000000..5420b5b
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: yaml2obj %s > %t1.obj
+# RUN: yaml2obj %s > %t2.obj
+# RUN: llvm-lib /out:%t.lib %t1.obj %t2.obj
+# RUN: lld-link /out:%t.exe /lldmap:%t.map /entry:main /subsystem:console %p/Inputs/ret42.obj %t.lib
+# RUN: FileCheck %s < %t.map
+
+# CHECK-NOT: .lib
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+symbols:
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            x
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-blx23t.test b/test/COFF/armnt-blx23t.test
new file mode 100644 (file)
index 0000000..5caf6eb
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 2d e9 00 48   push.w {r11, lr}
+# BEFORE:        8: eb 46         mov r11, sp
+# BEFORE:        a: 20 20         movs r0, #32
+# BEFORE:        c: 00 f0 00 f8   bl #0
+# BEFORE:       10: 01 30         adds r0, #1
+# BEFORE:       12: bd e8 00 88   pop.w {r11, pc}
+
+# AFTER: Disassembly of section .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 2d e9 00 48   push.w {r11, lr}
+# AFTER:     1008: eb 46         mov r11, sp
+# AFTER:     100a: 20 20         movs r0, #32
+# AFTER:     100c: ff f7 f8 ff   bl #-16
+# AFTER:     1010: 01 30         adds r0, #1
+# AFTER:     1012: bd e8 00 88   pop.w {r11, pc}
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF2DE90048EB46202000F000F80130BDE80088
+    Relocations:
+      - VirtualAddress:  12
+        SymbolName:      identity
+        Type:            21
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          22
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            identity
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-branch24t.test b/test/COFF/armnt-branch24t.test
new file mode 100644 (file)
index 0000000..6e1114c
--- /dev/null
@@ -0,0 +1,59 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 20 20         movs r0, #32
+# BEFORE:        6: 00 f0 00 b8   b.w #0
+
+# AFTER: Disassembly of section .text:
+# AFTER: .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 20 20         movs r0, #32
+# AFTER:     1006: ff f7 fb bf   b.w #-10
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF202000F000B8
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      identity
+        Type:            20
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          10
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            identity
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-entry-point.test b/test/COFF/armnt-entry-point.test
new file mode 100644 (file)
index 0000000..7b1bd10
--- /dev/null
@@ -0,0 +1,5 @@
+# RUN: yaml2obj < %p/Inputs/armnt-executable.obj.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: AddressOfEntryPoint: 0x1001
diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test
new file mode 100644 (file)
index 0000000..519886e
--- /dev/null
@@ -0,0 +1,51 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console %t.obj \
+# RUN:   /entry:mainCRTStartup %p/Inputs/library.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+# CHECK: Import {
+# CHECK:   Name: library.dll
+# CHECK:   ImportLookupTableRVA: 0x2028
+# CHECK:   ImportAddressTableRVA: 0x2030
+# CHECK:   Symbol: function (0)
+# CHECK: }
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     40F20000C0F2000000680047
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp_function
+        Type:            17
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp_function
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-mov32t-exec.test b/test/COFF/armnt-mov32t-exec.test
new file mode 100644 (file)
index 0000000..629f062
--- /dev/null
@@ -0,0 +1,60 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:get_function %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 40 f2 00 00   movw r0, #0
+# BEFORE:        8: c0 f2 00 00   movt r0, #0
+# BEFORE:        c: 70 47         bx lr
+
+# AFTER: Disassembly of section .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 41 f2 01 00   movw r0, #4097
+# AFTER:     1008: c0 f2 40 00   movt r0, #64
+# AFTER:     100c: 70 47         bx lr
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF40F20000C0F200007047
+    Relocations:
+      - VirtualAddress:  4
+        SymbolName:      function
+        Type:            17
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            function
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            get_function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-movt32t.test b/test/COFF/armnt-movt32t.test
new file mode 100644 (file)
index 0000000..6a9bf25
--- /dev/null
@@ -0,0 +1,72 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:get_buffer /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 40 f2 00 00   movw r0, #0
+# BEFORE:        4: c0 f2 00 00   movt r0, #0
+# BEFORE:        8: 70 47         bx lr
+
+# AFTER: Disassembly of section .text:
+# AFTER:        0: 41 f2 00 00   movw r0, #4096
+# AFTER:        4: c0 f2 40 00   movt r0, #64
+# AFTER:        8: 70 47         bx lr
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     40F20000C0F200007047
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      buffer
+        Type:            17
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     '62756666657200'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          10
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          7
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            get_buffer
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            buffer
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/base.test b/test/COFF/base.test
new file mode 100644 (file)
index 0000000..662632b
--- /dev/null
@@ -0,0 +1,57 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DEFAULT-TEXT %s
+
+# DEFAULT-HEADER:    ImageBase: 0x140000000
+# DEFAULT-TEXT:      Contents of section .text:
+# DEFAULT-TEXT-NEXT: 1000 00000040 01000000
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /base:0x280000000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BASE-HEADER %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=BASE-TEXT %s
+
+# BASE-HEADER: ImageBase: 0x280000000
+# BASE-TEXT:      Contents of section .text:
+# BASE-TEXT-NEXT: 1000 00000080 02000000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test
new file mode 100644 (file)
index 0000000..ce0b276
--- /dev/null
@@ -0,0 +1,215 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=BASEREL
+#
+# RUN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=NOBASEREL
+#
+# BASEREL:      BaseReloc [
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x2007
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x200C
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x201E
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: ABSOLUTE
+# BASEREL-NEXT:   Address: 0x2000
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x3007
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x300C
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x301E
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: ABSOLUTE
+# BASEREL-NEXT:   Address: 0x3000
+# BASEREL-NEXT: }
+#
+# NOBASEREL:      BaseReloc [
+# NOBASEREL-NEXT: ]
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck %s \
+# RUN:   --check-prefix=BASEREL-HEADER
+#
+# RN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
+# RN: llvm-readobj -file-headers %t.exe | FileCheck %s \
+# RN:   --check-prefix=NOBASEREL-HEADER
+#
+# BASEREL-HEADER-NOT: IMAGE_FILE_RELOCS_STRIPPED
+#
+# NOBASEREL-HEADER: IMAGE_FILE_RELOCS_STRIPPED
+#
+# BASEREL-HEADER:      BaseRelocationTableRVA: 0x5000
+# BASEREL-HEADER:      BaseRelocationTableSize: 0x20
+# BASEREL-HEADER:      Name: .reloc (2E 72 65 6C 6F 63 00 00)
+# BASEREL-HEADER-NEXT: VirtualSize: 0x20
+# BASEREL-HEADER-NEXT: VirtualAddress: 0x5000
+# BASEREL-HEADER-NEXT: RawDataSize: 512
+# BASEREL-HEADER-NEXT: PointerToRawData: 0xC00
+# BASEREL-HEADER-NEXT: PointerToRelocations: 0x0
+# BASEREL-HEADER-NEXT: PointerToLineNumbers: 0x0
+# BASEREL-HEADER-NEXT: RelocationCount: 0
+# BASEREL-HEADER-NEXT: LineNumberCount: 0
+# BASEREL-HEADER-NEXT: Characteristics [ (0x42000040)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_MEM_READ (0x40000000)
+# BASEREL-HEADER-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .text2
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     48656C6C6F0048656C6C6F20576F726C6400
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text2
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          18
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            MessageBoxA
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            ExitProcess
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            abs_symbol
+    Value:           0xDEADBEEF
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/common.test b/test/COFF/common.test
new file mode 100644 (file)
index 0000000..d57ced4
--- /dev/null
@@ -0,0 +1,102 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# Operands of B8 (MOV EAX) are common symbols
+# CHECK: 3000: b8 00 10 00 40
+# CHECK: 3005: b8 04 10 00 40
+# CHECK: 300a: b8 20 10 00 40
+# CHECK: 300f: b8 60 10 00 40
+# CHECK: 3014: b8 80 10 00 40
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     b800000000b800000000b800000000b800000000b800000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      bssdata4
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  6
+        SymbolName:      bsspad1
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  11
+        SymbolName:      bssdata64
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  16
+        SymbolName:      bsspad2
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  21
+        SymbolName:      bssdata16
+        Type:            IMAGE_REL_AMD64_ADDR32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     03000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 5
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata4
+    Value:           4
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bsspad1
+    Value:           1
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata64
+    Value:           64
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bsspad2
+    Value:           1
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata16
+    Value:           16
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/conflict.test b/test/COFF/conflict.test
new file mode 100644 (file)
index 0000000..65dda51
--- /dev/null
@@ -0,0 +1,41 @@
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# RUN: llvm-as -o %t.lto1.obj %S/Inputs/conflict.ll
+# RUN: llvm-as -o %t.lto2.obj %S/Inputs/conflict.ll
+# RUN: not lld-link /out:%t.exe %t.lto1.obj %t.lto2.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: duplicate symbol: foo {{.+}}1.obj and foo {{.+}}2.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/debug.test b/test/COFF/debug.test
new file mode 100644 (file)
index 0000000..3921e0c
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            debug
+    Value:           0
+    SectionNumber:   -2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/defparser.test b/test/COFF/defparser.test
new file mode 100644 (file)
index 0000000..2e5223a
--- /dev/null
@@ -0,0 +1,13 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: echo -e "LIBRARY foo\nEXPORTS ? @" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "LIBRARY foo\nHEAP abc" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "LIBRARY foo\nSTACK abc" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "foo" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
diff --git a/test/COFF/delayimports.test b/test/COFF/delayimports.test
new file mode 100644 (file)
index 0000000..2c27d58
--- /dev/null
@@ -0,0 +1,41 @@
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib /delayload:STD64.DLL \
+# RUN:   /alternatename:__delayLoadHelper2=main
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+IMPORT:      DelayImport {
+IMPORT-NEXT:   Name: std64.dll
+IMPORT-NEXT:   Attributes: 0x1
+IMPORT-NEXT:   ModuleHandle: 0x1018
+IMPORT-NEXT:   ImportAddressTable: 0x1020
+IMPORT-NEXT:   ImportNameTable: 0x3040
+IMPORT-NEXT:   BoundDelayImportTable: 0x0
+IMPORT-NEXT:   UnloadDelayImportTable: 0x0
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: ExitProcess (0)
+IMPORT-NEXT:     Address: 0x140002066
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol:  (50)
+IMPORT-NEXT:     Address: 0x1400020BD
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: MessageBoxA (0)
+IMPORT-NEXT:     Address: 0x140002114
+IMPORT-NEXT:   }
+IMPORT-NEXT: }
+
+BASEREL:      BaseReloc [
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1020
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1028
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1030
+BASEREL-NEXT:   }
diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test
new file mode 100644 (file)
index 0000000..328b345
--- /dev/null
@@ -0,0 +1,86 @@
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \
+# RUN:   /debug /delayload:std32.dll /out:%t.exe
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
+
+IMPORT:      Format: COFF-i386
+IMPORT-NEXT: Arch: i386
+IMPORT-NEXT: AddressSize: 32bit
+IMPORT-NEXT: DelayImport {
+IMPORT-NEXT:   Name: std32.dll
+IMPORT-NEXT:   Attributes: 0x1
+IMPORT-NEXT:   ModuleHandle: 0x1018
+IMPORT-NEXT:   ImportAddressTable: 0x1020
+IMPORT-NEXT:   ImportNameTable: 0x3040
+IMPORT-NEXT:   BoundDelayImportTable: 0x0
+IMPORT-NEXT:   UnloadDelayImportTable: 0x0
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: ExitProcess (0)
+IMPORT-NEXT:     Address: 0x402029
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: MessageBoxA (0)
+IMPORT-NEXT:     Address: 0x40203E
+IMPORT-NEXT:   }
+IMPORT-NEXT: }
+
+BASEREL:      BaseReloc [
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x1020
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x1024
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2005
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x200C
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x201F
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2025
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x202C
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2031
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2041
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2046
+BASEREL-NEXT:   }
+BASEREL-NEXT: ]
+
+DISASM:      202b:      68 20 10 40 00  pushl   $4198432
+DISASM-NEXT: 2030:      68 00 30 40 00  pushl   $4206592
+DISASM-NEXT: 2035:      e8 c6 ff ff ff  calll   -58 <_main@0>
+DISASM-NEXT: 203a:      5a      popl    %edx
+DISASM-NEXT: 203b:      59      popl    %ecx
+DISASM-NEXT: 203c:      ff e0   jmpl    *%eax
+DISASM-NEXT: 203e:      51      pushl   %ecx
+DISASM-NEXT: 203f:      52      pushl   %edx
+DISASM-NEXT: 2040:      68 24 10 40 00  pushl   $4198436
+DISASM-NEXT: 2045:      68 00 30 40 00  pushl   $4206592
+DISASM-NEXT: 204a:      e8 b1 ff ff ff  calll   -79 <_main@0>
+DISASM-NEXT: 204f:      5a      popl    %edx
+DISASM-NEXT: 2050:      59      popl    %ecx
+DISASM-NEXT: 2051:      ff e0   jmpl    *%eax
diff --git a/test/COFF/dll.test b/test/COFF/dll.test
new file mode 100644 (file)
index 0000000..bafd3c2
--- /dev/null
@@ -0,0 +1,53 @@
+# REQUIRES: winres
+# REQUIRES: winlib
+
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:mangled
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=EXPORT %s
+
+EXPORT:      Export Table:
+EXPORT:      DLL name: dll.test.tmp.dll
+EXPORT:      Ordinal      RVA  Name
+EXPORT-NEXT:       0        0
+EXPORT-NEXT:       1   0x1008  exportfn1
+EXPORT-NEXT:       2   0x1010  exportfn2
+EXPORT-NEXT:       3   0x1010  exportfn3
+EXPORT-NEXT:       4   0x1010  mangled
+
+# RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj
+# RUN: rm -f %t5.lib
+# RUN: llvm-ar cru %t5.lib %t5.obj
+# RUN: lld-link /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2
+# RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=EXPORT2 %s
+
+EXPORT2:      Export Table:
+EXPORT2:      DLL name: dll.test.tmp5.dll
+EXPORT2:      Ordinal      RVA  Name
+EXPORT2-NEXT:       0        0
+EXPORT2-NEXT:       1   0x1010  exportfn3
+EXPORT2-NEXT:       2   0x101c  mangled2
+
+# RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll
+# RUN: lld-link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.lto.dll | FileCheck -check-prefix=EXPORT-LTO %s
+
+EXPORT-LTO:      Export Table:
+EXPORT-LTO:      DLL name: dll.test.tmp.lto.dll
+EXPORT-LTO:      Ordinal      RVA  Name
+EXPORT-LTO-NEXT:       0        0
+EXPORT-LTO-NEXT:       1   0x1010  exportfn1
+EXPORT-LTO-NEXT:       2   0x1020  exportfn2
+EXPORT-LTO-NEXT:       3   0x1030  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /implib:%t2.lib \
+# RUN:   /export:exportfn1 /export:exportfn2
+# RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
+# RUN: lld-link /out:%t2.exe /entry:main %t2.obj %t2.lib
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s
+
+# RUN: lld-link /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib
+# RUN: llvm-readobj -coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s
+
+IMPORT: Symbol: exportfn1
+IMPORT: Symbol: exportfn2
diff --git a/test/COFF/driver.test b/test/COFF/driver.test
new file mode 100644 (file)
index 0000000..0832350
--- /dev/null
@@ -0,0 +1,3 @@
+# RUN: not lld-link nosuchfile.obj >& %t.log
+# RUN: FileCheck -check-prefix=MISSING %s < %t.log
+MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory
diff --git a/test/COFF/entry-inference.test b/test/COFF/entry-inference.test
new file mode 100644 (file)
index 0000000..2eb9a68
--- /dev/null
@@ -0,0 +1,50 @@
+# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+
+# MAIN:     <root>: undefined symbol: mainCRTStartup
+# WMAIN:    <root>: undefined symbol: wmainCRTStartup
+# WINMAIN:  <root>: undefined symbol: WinMainCRTStartup
+# WWINMAIN: <root>: undefined symbol: wWinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            ENTRYNAME
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-inference2.test b/test/COFF/entry-inference2.test
new file mode 100644 (file)
index 0000000..a66422f
--- /dev/null
@@ -0,0 +1,39 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj /verbose > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: WinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f616c7465726e6174656e616d653a6d61696e3d57696e4d61696e00  # /alternatename:main=WinMain
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            WinMain
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-inference32.test b/test/COFF/entry-inference32.test
new file mode 100644 (file)
index 0000000..231b468
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj /verbose > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: _WinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _WinMain@16
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-mangled.test b/test/COFF/entry-mangled.test
new file mode 100644 (file)
index 0000000..acf54ba
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/entry-mangled.ll
+# RUN: lld-link /out:%t.exe /entry:main %t.lto.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '?main@@YAHXZ'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entrylib.ll b/test/COFF/entrylib.ll
new file mode 100644 (file)
index 0000000..4ffa42c
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: rm -f %t.lib
+; RUN: llvm-ar cru %t.lib %t.obj
+; RUN: lld-link /out:%t.exe /entry:main %t.lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  ret i32 0
+}
diff --git a/test/COFF/export-exe.test b/test/COFF/export-exe.test
new file mode 100644 (file)
index 0000000..7a34516
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: winlib
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows \
+# RUN:   %p/Inputs/ret42.obj /export:main
+# RUN: llvm-objdump -p %t.exe | FileCheck %s
+
+CHECK:      Export Table:
+CHECK-NEXT: DLL name: export-exe.test.tmp.exe
+CHECK-NEXT: Ordinal base: 0
+CHECK-NEXT: Ordinal      RVA  Name
+CHECK-NEXT:       0        0
+CHECK-NEXT:       1   0x1000  main
diff --git a/test/COFF/export.test b/test/COFF/export.test
new file mode 100644 (file)
index 0000000..20e069e
--- /dev/null
@@ -0,0 +1,93 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+# REQUIRES: winlib
+
+CHECK1:      Export Table:
+CHECK1:      DLL name: export.test.tmp.dll
+CHECK1:      Ordinal      RVA  Name
+CHECK1-NEXT:       0        0
+CHECK1-NEXT:       1   0x1008  exportfn1
+CHECK1-NEXT:       2   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2:      Export Table:
+CHECK2:      DLL name: export.test.tmp.dll
+CHECK2:      Ordinal      RVA  Name
+CHECK2-NEXT:       0        0
+CHECK2-NEXT:       1        0
+CHECK2-NEXT:       2        0
+CHECK2-NEXT:       3        0
+CHECK2-NEXT:       4        0
+CHECK2-NEXT:       5   0x1008  exportfn1
+CHECK2-NEXT:       6   0x1010  exportfn2
+CHECK2-NEXT:       7   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
+
+CHECK3:      Export Table:
+CHECK3:      DLL name: export.test.tmp.dll
+CHECK3:      Ordinal      RVA  Name
+CHECK3-NEXT:       0        0
+CHECK3-NEXT:       1        0
+CHECK3-NEXT:       2        0
+CHECK3-NEXT:       3        0
+CHECK3-NEXT:       4        0
+CHECK3-NEXT:       5   0x1008
+CHECK3-NEXT:       6   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
+
+CHECK4:      Export Table:
+CHECK4:      DLL name: export.test.tmp.dll
+CHECK4:      Ordinal      RVA  Name
+CHECK4-NEXT:       0        0
+CHECK4-NEXT:       1   0x1010  exportfn3
+CHECK4-NEXT:       2   0x1008  f1
+CHECK4-NEXT:       3   0x1010  f2
+
+# RUN: echo "EXPORTS exportfn1 @3" > %t.def
+# RUN: echo "fn2=exportfn2 @2" >> %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
+
+CHECK5:      Export Table:
+CHECK5:      DLL name: export.test.tmp.dll
+CHECK5:      Ordinal      RVA  Name
+CHECK5-NEXT:       0        0
+CHECK5-NEXT:       1        0
+CHECK5-NEXT:       2   0x1010  fn2
+CHECK5-NEXT:       3   0x1008  exportfn1
+CHECK5-NEXT:       4   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.DLL /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:exportfn1 /export:exportfn2,@5 >& %t.log
+# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
+
+CHECK6:     duplicate /export option: exportfn2
+CHECK6-NOT: duplicate /export option: exportfn1
+
+# RUN: llvm-nm -M %t.lib | FileCheck --check-prefix=SYMTAB %s
+
+SYMTAB: __imp_exportfn1 in export.test.tmp.DLL
+SYMTAB: exportfn1 in export.test.tmp.DLL
+SYMTAB: __imp_exportfn2 in export.test.tmp.DLL
+SYMTAB: exportfn2 in export.test.tmp.DLL
+SYMTAB: __imp_exportfn3 in export.test.tmp.DLL
+SYMTAB: exportfn3 in export.test.tmp.DLL
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s
+
+FORWARDER: Export Table:
+FORWARDER:  DLL name: export.test.tmp.dll
+FORWARDER:  Ordinal base: 0
+FORWARDER:  Ordinal      RVA  Name
+FORWARDER:        0        0
+FORWARDER:        1   0x1010  exportfn
+FORWARDER:        2           foo (forwarded to kernel32.foobar)
diff --git a/test/COFF/export32.test b/test/COFF/export32.test
new file mode 100644 (file)
index 0000000..86cd27b
--- /dev/null
@@ -0,0 +1,133 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+# REQUIRES: winlib
+
+# CHECK1:      Export Table:
+# CHECK1:      DLL name: export32.test.tmp.dll
+# CHECK1:      Ordinal      RVA  Name
+# CHECK1-NEXT:       0        0
+# CHECK1-NEXT:       1   0x1008  exportfn1
+# CHECK1-NEXT:       2   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
+# RUN:   /export:exportfn2 /export:mangled
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2:      Export Table:
+# CHECK2:      DLL name: export32.test.tmp.dll
+# CHECK2:      Ordinal      RVA  Name
+# CHECK2-NEXT:       0        0
+# CHECK2-NEXT:       1        0
+# CHECK2-NEXT:       2        0
+# CHECK2-NEXT:       3        0
+# CHECK2-NEXT:       4        0
+# CHECK2-NEXT:       5   0x1008  exportfn1
+# CHECK2-NEXT:       6   0x1010  exportfn2
+# CHECK2-NEXT:       7   0x1010  exportfn3
+# CHECK2-NEXT:       8   0x1010  mangled
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
+
+# CHECK3:      Export Table:
+# CHECK3:      DLL name: export32.test.tmp.dll
+# CHECK3:      Ordinal      RVA  Name
+# CHECK3-NEXT:       0        0
+# CHECK3-NEXT:       1        0
+# CHECK3-NEXT:       2        0
+# CHECK3-NEXT:       3        0
+# CHECK3-NEXT:       4        0
+# CHECK3-NEXT:       5   0x1008
+# CHECK3-NEXT:       6   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
+
+# CHECK4:      Export Table:
+# CHECK4:      DLL name: export32.test.tmp.dll
+# CHECK4:      Ordinal      RVA  Name
+# CHECK4-NEXT:       0        0
+# CHECK4-NEXT:       1   0x1010  exportfn3
+# CHECK4-NEXT:       2   0x1008  f1
+# CHECK4-NEXT:       3   0x1010  f2
+
+# RUN: echo "EXPORTS exportfn1 @3" > %t.def
+# RUN: echo "fn2=exportfn2 @2" >> %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
+
+# CHECK5:      Export Table:
+# CHECK5:      DLL name: export32.test.tmp.dll
+# CHECK5:      Ordinal      RVA  Name
+# CHECK5-NEXT:       0        0
+# CHECK5-NEXT:       1        0
+# CHECK5-NEXT:       2   0x1010  fn2
+# CHECK5-NEXT:       3   0x1008  exportfn1
+# CHECK5-NEXT:       4   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:exportfn1 /export:exportfn2,@5 >& %t.log
+# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
+
+# CHECK6:     duplicate /export option: _exportfn2
+# CHECK6-NOT: duplicate /export option: _exportfn1
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f6578706f72743a5f6578706f7274666e3300  # /export:_exportfn3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            __DllMainCRTStartup@12
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn1
+    Value:           8
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn2@4
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn3
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?mangled@@YAHXZ'
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/failifmismatch.test b/test/COFF/failifmismatch.test
new file mode 100644 (file)
index 0000000..021d91b
--- /dev/null
@@ -0,0 +1,11 @@
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj
+
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1
+
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1
+
+# RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2
diff --git a/test/COFF/filetype.test b/test/COFF/filetype.test
new file mode 100644 (file)
index 0000000..e161910
--- /dev/null
@@ -0,0 +1,4 @@
+# Make sure input file type is detected by file magic and not by extension.
+
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.lib
+# RUN: lld-link /out:%t.exe /entry:main %t.lib
diff --git a/test/COFF/force.test b/test/COFF/force.test
new file mode 100644 (file)
index 0000000..80bd275
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe /entry:main %t.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /force >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: .obj: undefined symbol: foo
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/heap.test b/test/COFF/heap.test
new file mode 100644 (file)
index 0000000..1eb70a2
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: SizeOfHeapReserve: 1048576
+DEFAULT: SizeOfHeapCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main /heap:0x3000 %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+# RUN: echo "HEAPSIZE 12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: SizeOfHeapReserve: 12288
+CHECK1: SizeOfHeapCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main /heap:0x5000,0x3000 %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+# RUN: echo "HEAPSIZE 20480,12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: SizeOfHeapReserve: 20480
+CHECK2: SizeOfHeapCommit: 12288
diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test
new file mode 100644 (file)
index 0000000..4307d4b
--- /dev/null
@@ -0,0 +1,129 @@
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /out:%t.exe
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+HEADER:      Format: COFF-i386
+HEADER-NEXT: Arch: i386
+HEADER-NEXT: AddressSize: 32bit
+HEADER-NEXT: ImageFileHeader {
+HEADER-NEXT:   Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+HEADER-NEXT:   SectionCount: 4
+HEADER-NEXT:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+HEADER-NEXT:   PointerToSymbolTable: 0x0
+HEADER-NEXT:   SymbolCount: 0
+HEADER-NEXT:   OptionalHeaderSize: 224
+HEADER-NEXT:   Characteristics [ (0x102)
+HEADER-NEXT:     IMAGE_FILE_32BIT_MACHINE (0x100)
+HEADER-NEXT:     IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+HEADER-NEXT:   ]
+HEADER-NEXT: }
+HEADER-NEXT: ImageOptionalHeader {
+HEADER-NEXT:   MajorLinkerVersion: 0
+HEADER-NEXT:   MinorLinkerVersion: 0
+HEADER-NEXT:   SizeOfCode: 512
+HEADER-NEXT:   SizeOfInitializedData: 1536
+HEADER-NEXT:   SizeOfUninitializedData: 0
+HEADER-NEXT:   AddressOfEntryPoint: 0x2000
+HEADER-NEXT:   BaseOfCode: 0x2000
+HEADER-NEXT:   BaseOfData: 0x0
+HEADER-NEXT:   ImageBase: 0x400000
+HEADER-NEXT:   SectionAlignment: 4096
+HEADER-NEXT:   FileAlignment: 512
+HEADER-NEXT:   MajorOperatingSystemVersion: 6
+HEADER-NEXT:   MinorOperatingSystemVersion: 0
+HEADER-NEXT:   MajorImageVersion: 0
+HEADER-NEXT:   MinorImageVersion: 0
+HEADER-NEXT:   MajorSubsystemVersion: 6
+HEADER-NEXT:   MinorSubsystemVersion: 0
+HEADER-NEXT:   SizeOfImage: 16896
+HEADER-NEXT:   SizeOfHeaders: 512
+HEADER-NEXT:   Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+HEADER-NEXT:   Characteristics [ (0x8140)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
+HEADER-NEXT:   ]
+HEADER-NEXT:   SizeOfStackReserve: 1048576
+HEADER-NEXT:   SizeOfStackCommit: 4096
+HEADER-NEXT:   SizeOfHeapReserve: 1048576
+HEADER-NEXT:   SizeOfHeapCommit: 4096
+HEADER-NEXT:   NumberOfRvaAndSize: 16
+HEADER-NEXT:   DataDirectory {
+HEADER-NEXT:     ExportTableRVA: 0x0
+HEADER-NEXT:     ExportTableSize: 0x0
+HEADER-NEXT:     ImportTableRVA: 0x3000
+HEADER-NEXT:     ImportTableSize: 0x28
+HEADER-NEXT:     ResourceTableRVA: 0x0
+HEADER-NEXT:     ResourceTableSize: 0x0
+HEADER-NEXT:     ExceptionTableRVA: 0x0
+HEADER-NEXT:     ExceptionTableSize: 0x0
+HEADER-NEXT:     CertificateTableRVA: 0x0
+HEADER-NEXT:     CertificateTableSize: 0x0
+HEADER-NEXT:     BaseRelocationTableRVA: 0x4000
+HEADER-NEXT:     BaseRelocationTableSize: 0x10
+HEADER-NEXT:     DebugRVA: 0x0
+HEADER-NEXT:     DebugSize: 0x0
+HEADER-NEXT:     ArchitectureRVA: 0x0
+HEADER-NEXT:     ArchitectureSize: 0x0
+HEADER-NEXT:     GlobalPtrRVA: 0x0
+HEADER-NEXT:     GlobalPtrSize: 0x0
+HEADER-NEXT:     TLSTableRVA: 0x0
+HEADER-NEXT:     TLSTableSize: 0x0
+HEADER-NEXT:     LoadConfigTableRVA: 0x0
+HEADER-NEXT:     LoadConfigTableSize: 0x0
+HEADER-NEXT:     BoundImportRVA: 0x0
+HEADER-NEXT:     BoundImportSize: 0x0
+HEADER-NEXT:     IATRVA: 0x3034
+HEADER-NEXT:     IATSize: 0xC
+HEADER-NEXT:     DelayImportDescriptorRVA: 0x0
+HEADER-NEXT:     DelayImportDescriptorSize: 0x0
+HEADER-NEXT:     CLRRuntimeHeaderRVA: 0x0
+HEADER-NEXT:     CLRRuntimeHeaderSize: 0x0
+HEADER-NEXT:     ReservedRVA: 0x0
+HEADER-NEXT:     ReservedSize: 0x0
+HEADER-NEXT:   }
+HEADER-NEXT: }
+HEADER-NEXT: DOSHeader {
+HEADER-NEXT:   Magic: MZ
+HEADER-NEXT:   UsedBytesInTheLastPage: 0
+HEADER-NEXT:   FileSizeInPages: 0
+HEADER-NEXT:   NumberOfRelocationItems: 0
+HEADER-NEXT:   HeaderSizeInParagraphs: 0
+HEADER-NEXT:   MinimumExtraParagraphs: 0
+HEADER-NEXT:   MaximumExtraParagraphs: 0
+HEADER-NEXT:   InitialRelativeSS: 0
+HEADER-NEXT:   InitialSP: 0
+HEADER-NEXT:   Checksum: 0
+HEADER-NEXT:   InitialIP: 0
+HEADER-NEXT:   InitialRelativeCS: 0
+HEADER-NEXT:   AddressOfRelocationTable: 64
+HEADER-NEXT:   OverlayNumber: 0
+HEADER-NEXT:   OEMid: 0
+HEADER-NEXT:   OEMinfo: 0
+HEADER-NEXT:   AddressOfNewExeHeader: 64
+HEADER-NEXT: }
+
+IMPORTS: Format: COFF-i386
+IMPORTS: Arch: i386
+IMPORTS: AddressSize: 32bit
+IMPORTS: Import {
+IMPORTS:   Name: std32.dll
+IMPORTS:   ImportLookupTableRVA: 0x3028
+IMPORTS:   ImportAddressTableRVA: 0x3034
+IMPORTS:   Symbol: ExitProcess (0)
+IMPORTS:   Symbol: MessageBoxA (1)
+IMPORTS: }
+
+BASEREL: BaseReloc [
+BASEREL:   Entry {
+BASEREL:     Type: HIGHLOW
+BASEREL:     Address: 0x2005
+BASEREL:   }
+BASEREL:   Entry {
+BASEREL:     Type: HIGHLOW
+BASEREL:     Address: 0x200C
+BASEREL:   }
+BASEREL: ]
diff --git a/test/COFF/help.test b/test/COFF/help.test
new file mode 100644 (file)
index 0000000..d36fe6d
--- /dev/null
@@ -0,0 +1,3 @@
+# RUN: lld-link /help | FileCheck %s
+
+CHECK: OVERVIEW: LLVM Linker
diff --git a/test/COFF/icf-circular.test b/test/COFF/icf-circular.test
new file mode 100644 (file)
index 0000000..c113566
--- /dev/null
@@ -0,0 +1,81 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Selected foo
+# CHECK:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-circular2.test b/test/COFF/icf-circular2.test
new file mode 100644 (file)
index 0000000..3b8eb8f
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Selected foo
+# CHECK:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-different-align.test b/test/COFF/icf-different-align.test
new file mode 100644 (file)
index 0000000..3502ed3
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK-NOT: Selected foo
+# CHECK-NOT:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       8
+    SectionData:     4883EC28E8000000004883C428C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-local.test b/test/COFF/icf-local.test
new file mode 100644 (file)
index 0000000..db690b8
--- /dev/null
@@ -0,0 +1,66 @@
+# COMDAT sections with non-external linkage should not be merged by ICF.
+
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: sed s/foo/main/ %s | yaml2obj > %t2.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /verbose \
+# RUN:   %t1.obj %t2.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK-NOT: Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     488D0500000000C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       8
+    SectionData:     2A000000000000002B00000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1092178131
+      Number:          1
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          16
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1200668497
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/icf-simple.test b/test/COFF/icf-simple.test
new file mode 100644 (file)
index 0000000..c302c87
--- /dev/null
@@ -0,0 +1,71 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ICF %s < %t.log
+
+# ICF: Selected foo
+# ICF:   Removed bar
+
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose /opt:noicf %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose /opt:noref,noicf %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+
+# NOICF-NOT: Removed foo
+# NOICF-NOT: Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/imports-mangle.test b/test/COFF/imports-mangle.test
new file mode 100644 (file)
index 0000000..5d8ccae
--- /dev/null
@@ -0,0 +1,66 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /opt:noref /entry:main \
+# RUN:   %t.obj %p/Inputs/imports-mangle.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+# CHECK: Import {
+# CHECK:   Symbol: sym4 (0)
+# CHECK:   Symbol: _sym3 (1)
+# CHECK:   Symbol: sym1 (2)
+# CHECK:   Symbol:  (2)
+# CHECK: }
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            sym1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            sym2
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __sym3
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?sym4@@YAHH@Z'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
new file mode 100644 (file)
index 0000000..584c24e
--- /dev/null
@@ -0,0 +1,35 @@
+# Verify that the lld can handle .lib files and emit .idata sections.
+#
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+
+TEXT: Disassembly of section .text:
+TEXT-NEXT: .text:
+TEXT-NEXT: subq    $40, %rsp
+TEXT-NEXT: movq    $0, %rcx
+TEXT-NEXT: leaq    -4108(%rip), %rdx
+TEXT-NEXT: leaq    -4121(%rip), %r8
+TEXT-NEXT: movl    $0, %r9d
+TEXT-NEXT: callq   60
+TEXT-NEXT: movl    $0, %ecx
+TEXT-NEXT: callq   18
+TEXT-NEXT: callq   29
+TEXT:      jmpq    *4098(%rip)
+TEXT:      jmpq    *4090(%rip)
+TEXT:      jmpq    *4082(%rip)
+
+IMPORT:      Import {
+IMPORT-NEXT:   Name: std64.dll
+IMPORT-NEXT:   ImportLookupTableRVA: 0x3028
+IMPORT-NEXT:   ImportAddressTableRVA: 0x3048
+IMPORT-NEXT:   Symbol: ExitProcess (0)
+IMPORT-NEXT:   Symbol:  (50)
+IMPORT-NEXT:   Symbol: MessageBoxA (1)
+IMPORT-NEXT: }
diff --git a/test/COFF/include.test b/test/COFF/include.test
new file mode 100644 (file)
index 0000000..e7b0c58
--- /dev/null
@@ -0,0 +1,83 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /verbose >& %t.log
+### FileCheck doesn't like empty input, so write something.
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /verbose /include:unused >& %t.log
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# CHECK1:     Discarded unused
+# CHECK1-NOT: Discarded used
+# CHECK2-NOT: Discarded unused
+# CHECK2-NOT: Discarded used
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a7573656400  # /include:used
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            used
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            unused
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/include2.test b/test/COFF/include2.test
new file mode 100644 (file)
index 0000000..f2379ea
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj
+# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj
+# RUN: rm -f %t2.lib %t3.lib
+# RUN: llvm-ar cru %t2.lib %t2.obj
+# RUN: llvm-ar cru %t3.lib %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib /verbose >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: include2.test.tmp1.obj
+CHECK: include2.test.tmp2.lib
+CHECK: include2.test.tmp3.lib
+CHECK: include2.test.tmp2.lib(include2.test.tmp2.obj) for foo
+CHECK: include2.test.tmp3.lib(include2.test.tmp3.obj) for bar
diff --git a/test/COFF/internal.test b/test/COFF/internal.test
new file mode 100644 (file)
index 0000000..bc958cb
--- /dev/null
@@ -0,0 +1,42 @@
+# Test that non-external symbols don't conflict
+
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.obj %t3.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            defined
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            absolute
+    Value:           0xdeadbeef
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/invalid-obj.test b/test/COFF/invalid-obj.test
new file mode 100644 (file)
index 0000000..6f76c37
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: not lld-link %t.obj 2>&1 | FileCheck %s
+
+# CHECK: getSectionName failed: #1:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '/1'
+    Characteristics: []
+    SectionData:     00
+symbols:
diff --git a/test/COFF/largeaddressaware.test b/test/COFF/largeaddressaware.test
new file mode 100644 (file)
index 0000000..d035e7c
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /out:%t.exe /largeaddressaware
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+
+HEADER:      Format: COFF-i386
+HEADER-NEXT: Arch: i386
+HEADER-NEXT: AddressSize: 32bit
+HEADER-NEXT: ImageFileHeader {
+HEADER-NEXT:   Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+HEADER-NEXT:   SectionCount: 4
+HEADER-NEXT:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+HEADER-NEXT:   PointerToSymbolTable: 0x0
+HEADER-NEXT:   SymbolCount: 0
+HEADER-NEXT:   OptionalHeaderSize: 224
+HEADER-NEXT:   Characteristics [ (0x122)
+HEADER-NEXT:     IMAGE_FILE_32BIT_MACHINE (0x100)
+HEADER-NEXT:     IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+HEADER-NEXT:     IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
+HEADER-NEXT:   ]
+HEADER-NEXT: }
diff --git a/test/COFF/libpath.test b/test/COFF/libpath.test
new file mode 100644 (file)
index 0000000..da465bc
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: mkdir -p %t/a %t/b %t/c
+# RUN: cp %p/Inputs/std64.lib %t/a/
+# RUN: cp %p/Inputs/std64.lib %t/b/
+# RUN: cp %p/Inputs/std64.lib %t/c/
+
+# RUN: env LIB=%t/a lld-link /out:%t.exe /entry:main /verbose \
+# RUN:   std64.lib /subsystem:console %p/Inputs/hello64.obj \
+# RUN:   /libpath:%t/b /libpath:%t/c > %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+CHECK1: b{{[/\\]}}std64.lib
+
+# RUN: lld-link /out:%t.exe /entry:main /verbose \
+# RUN:   std64.lib /subsystem:console %p/Inputs/hello64.obj \
+# RUN:   /libpath:%t/a /libpath:%t/b /libpath:%t/c > %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+CHECK2: a{{[/\\]}}std64.lib
diff --git a/test/COFF/linkenv.test b/test/COFF/linkenv.test
new file mode 100644 (file)
index 0000000..5dfb875
--- /dev/null
@@ -0,0 +1,4 @@
+# RUN: env LINK=-help lld-link > %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: OVERVIEW: LLVM Linker
diff --git a/test/COFF/lldmap.test b/test/COFF/lldmap.test
new file mode 100644 (file)
index 0000000..a4c2da0
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /lldmap:%t.map %t.obj
+# RUN: FileCheck %s < %t.map
+
+# CHECK: .obj:
+# CHECK-NEXT: 140001000 .text$mn
+# CHECK-NEXT: 140001000 .data
+# CHECK-NEXT: 140001000 main
diff --git a/test/COFF/loadcfg.ll b/test/COFF/loadcfg.ll
new file mode 100644 (file)
index 0000000..c49ae2f
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+; CHECK: LoadConfigTableRVA: 0x1000
+; CHECK: LoadConfigTableSize: 0x70
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+@_load_config_used = constant [28 x i32] [i32 112, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0]
+
+define void @main() {
+  ret void
+}
diff --git a/test/COFF/loadcfg.test b/test/COFF/loadcfg.test
new file mode 100644 (file)
index 0000000..b74917f
--- /dev/null
@@ -0,0 +1,75 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableSize: 0x70
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     '70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          112
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            _load_config_used
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/loadcfg32.test b/test/COFF/loadcfg32.test
new file mode 100644 (file)
index 0000000..03a066c
--- /dev/null
@@ -0,0 +1,58 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableSize: 0x40
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          64
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            __load_config_used
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/locally-imported.test b/test/COFF/locally-imported.test
new file mode 100644 (file)
index 0000000..a10da4b
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 1000 00200000
+# CHECK:      Contents of section .rdata:
+# CHECK-NEXT: 2000 04100040 01000000
+
+# BASEREL:      BaseReloc [
+# BASEREL-NEXT:   Entry {
+# BASEREL-NEXT:     Type: DIR64
+# BASEREL-NEXT:     Address: 0x2000
+# BASEREL-NEXT:   }
+# BASEREL-NEXT:   Entry {
+# BASEREL-NEXT:     Type: ABSOLUTE
+# BASEREL-NEXT:     Address: 0x2000
+# BASEREL-NEXT:   }
+# BASEREL-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp_main
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp_main
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/locally-imported32.test b/test/COFF/locally-imported32.test
new file mode 100644 (file)
index 0000000..789c8c8
--- /dev/null
@@ -0,0 +1,50 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 1000 00200000
+
+# CHECK:      Contents of section .rdata:
+# CHECK-NEXT: 2000 04104000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp__main
+        Type:            IMAGE_REL_I386_DIR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            _main
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp__main
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/long-section-name.test b/test/COFF/long-section-name.test
new file mode 100644 (file)
index 0000000..1de329d
--- /dev/null
@@ -0,0 +1,58 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .data_long_section_name
+# CHECK: Name: .text_long_section_name
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .text_long_section_name
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .data_long_section_name
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     "00"
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text_long_section_name
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data_long_section_name
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/lto-chkstk.ll b/test/COFF/lto-chkstk.ll
new file mode 100644 (file)
index 0000000..43b0bff
--- /dev/null
@@ -0,0 +1,17 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-foo.obj %S/Inputs/lto-chkstk-foo.s
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-chkstk.obj %S/Inputs/lto-chkstk-chkstk.s
+; RUN: llvm-ar cru %t.lib %T/lto-chkstk-chkstk.obj
+; RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj %T/lto-chkstk-foo.obj %t.lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+entry:
+  %array4096 = alloca [4096 x i8]
+  call void @foo([4096 x i8]* %array4096)
+  ret void
+}
+
+declare void @foo([4096 x i8]*)
diff --git a/test/COFF/lto-comdat.ll b/test/COFF/lto-comdat.ll
new file mode 100644 (file)
index 0000000..aaa7a16
--- /dev/null
@@ -0,0 +1,131 @@
+; RUN: llvm-as -o %T/comdat-main.lto.obj %s
+; RUN: llvm-as -o %T/comdat1.lto.obj %S/Inputs/lto-comdat1.ll
+; RUN: llvm-as -o %T/comdat2.lto.obj %S/Inputs/lto-comdat2.ll
+; RUN: rm -f %T/comdat.lto.lib
+; RUN: llvm-ar cru %T/comdat.lto.lib %T/comdat1.lto.obj %T/comdat2.lto.obj
+
+; RUN: llc -filetype=obj -o %T/comdat-main.obj %s
+; RUN: llc -filetype=obj -o %T/comdat1.obj %S/Inputs/lto-comdat1.ll
+; RUN: llc -filetype=obj -o %T/comdat2.obj %S/Inputs/lto-comdat2.ll
+; RUN: rm -f %T/comdat.lib
+; RUN: llvm-ar cru %T/comdat.lib %T/comdat1.obj %T/comdat2.obj
+
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lto.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
+
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat.lto.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
+
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
+
+; HEADERS-11: AddressOfEntryPoint: 0x1000
+; TEXT-11: Disassembly of section .text:
+; TEXT-11-NEXT: .text:
+; TEXT-11-NEXT: xorl   %eax, %eax
+; TEXT-11-NEXT: retq
+
+; HEADERS-01: AddressOfEntryPoint: 0x2000
+; TEXT-01: Disassembly of section .text:
+; TEXT-01-NEXT: .text:
+; TEXT-01-NEXT: subq   $40, %rsp
+; TEXT-01-NEXT: callq  39
+; TEXT-01-NEXT: callq  50
+; TEXT-01-NEXT: callq  13
+; TEXT-01-NEXT: xorl   %eax, %eax
+; TEXT-01-NEXT: addq   $40, %rsp
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: nopw   %cs:(%rax,%rax)
+; TEXT-01-NEXT: retq
+
+; HEADERS-10: AddressOfEntryPoint: 0x2030
+; TEXT-10: Disassembly of section .text:
+; TEXT-10-NEXT: .text:
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  7
+; TEXT-10-NEXT: nop
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  -25
+; TEXT-10-NEXT: nop
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  -57
+; TEXT-10-NEXT: callq  -30
+; TEXT-10-NEXT: xorl   %eax, %eax
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define i32 @main() {
+  call void @f1()
+  call void @f2()
+  call void @comdat()
+  ret i32 0
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
+
+declare void @f1()
+declare void @f2()
diff --git a/test/COFF/lto-linker-opts.ll b/test/COFF/lto-linker-opts.ll
new file mode 100644 (file)
index 0000000..0c18370
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as -o %T/lto-linker-opts.obj %s
+; RUN: env LIB=%S/Inputs lld-link /out:%T/lto-linker-opts.exe /entry:main /subsystem:console %T/lto-linker-opts.obj
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 6, !"Linker Options", !1}
+!1 = !{!2}
+!2 = !{!"/DEFAULTLIB:ret42.lib"}
diff --git a/test/COFF/lto-new-symbol.ll b/test/COFF/lto-new-symbol.ll
new file mode 100644 (file)
index 0000000..d9e14eb
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe /entry:foo /subsystem:console %t.obj
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo(<4 x i32>* %p, <4 x float>* %q, i1 %t) nounwind {
+entry:
+  br label %loop
+loop:
+  store <4 x i32><i32 1073741824, i32 1073741824, i32 1073741824, i32 1073741824>, <4 x i32>* %p
+  store <4 x float><float 2.0, float 2.0, float 2.0, float 2.0>, <4 x float>* %q
+  br i1 %t, label %loop, label %ret
+ret:
+  ret void
+}
diff --git a/test/COFF/lto-opt-level.ll b/test/COFF/lto-opt-level.ll
new file mode 100644 (file)
index 0000000..674b6cc
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /debug %t.obj
+; RUN: llvm-nm %t0.exe | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: lld-link /out:%t2.exe /entry:main /subsystem:console /opt:lldlto=2 /debug %t.obj
+; RUN: llvm-nm %t2.exe | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: lld-link /out:%t2a.exe /entry:main /subsystem:console /debug %t.obj
+; RUN: llvm-nm %t2a.exe | FileCheck --check-prefix=CHECK-O2 %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK-O0: foo
+; CHECK-O2-NOT: foo
+define internal void @foo() {
+  ret void
+}
+
+define void @main() {
+  call void @foo()
+  ret void
+}
diff --git a/test/COFF/lto-parallel.ll b/test/COFF/lto-parallel.ll
new file mode 100644 (file)
index 0000000..2303797
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltojobs=2 /subsystem:console /lldmap:%t.map %t.obj
+; RUN: FileCheck %s < %t.map
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK: <lto object>:
+; CHECK: foo
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK: <lto object>:
+; CHECK: bar
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll
new file mode 100644 (file)
index 0000000..b8f8d70
--- /dev/null
@@ -0,0 +1,130 @@
+; RUN: llvm-as -o %T/main.lto.obj %s
+; RUN: llvm-as -o %T/foo.lto.obj %S/Inputs/lto-dep.ll
+; RUN: rm -f %T/foo.lto.lib
+; RUN: llvm-ar cru %T/foo.lto.lib %T/foo.lto.obj
+
+; RUN: llc -filetype=obj -o %T/main.obj %s
+; RUN: llc -filetype=obj -o %T/foo.obj %S/Inputs/lto-dep.ll
+; RUN: rm -f %T/foo.lib
+; RUN: llvm-ar cru %T/foo.lib %T/foo.obj
+
+; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.lib /verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
+
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.lib
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
+
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.lib
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
+
+; VERBOSE: foo.lto.lib({{.*}}foo.lto.obj)
+
+; HEADERS-11: AddressOfEntryPoint: 0x1000
+; TEXT-11: Disassembly of section .text:
+; TEXT-11-NEXT: .text:
+; TEXT-11-NEXT: xorl   %eax, %eax
+; TEXT-11-NEXT: retq
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: movl   $2, %eax
+; TEXT-11-NEXT: retq
+
+; HEADERS-01: AddressOfEntryPoint: 0x2000
+; TEXT-01: Disassembly of section .text:
+; TEXT-01-NEXT: .text:
+; TEXT-01-NEXT: subq   $40, %rsp
+; TEXT-01-NEXT: callq  23
+; TEXT-01-NEXT: xorl   %eax, %eax
+; TEXT-01-NEXT: addq   $40, %rsp
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: retq
+
+; HEADERS-10: AddressOfEntryPoint: 0x2020
+; TEXT-10: Disassembly of section .text:
+; TEXT-10-NEXT: .text:
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: nopw    %cs:(%rax,%rax)
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  -41
+; TEXT-10-NEXT: xorl   %eax, %eax
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
+
+declare void @foo()
+
+$f1 = comdat any
+define i32 @f1() comdat($f1) {
+  ret i32 1
+}
+
+$f2 = comdat any
+define i32 @f2() comdat($f2) {
+  ret i32 2
+}
+
+define internal void @internal() {
+  ret void
+}
diff --git a/test/COFF/machine.test b/test/COFF/machine.test
new file mode 100644 (file)
index 0000000..847018f
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
+# RUN: lld-link /entry:main /subsystem:console /machine:x64 \
+# RUN:   /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
+
+AMD64: Machine: IMAGE_FILE_MACHINE_AMD64
+
+# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
+# RUN: lld-link /entry:main /subsystem:console /machine:x86 \
+# RUN:   /out:%t.exe %t.obj /fixed
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
+
+I386: Machine: IMAGE_FILE_MACHINE_I386
+
+# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
+# RUN: not lld-link /entry:main /subsystem:console /machine:x86 \
+# RUN:   /out:%t.exe %t.obj /fixed >& %t.log
+# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
+
+# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t1.obj
+# RUN: sed -e s/main/foo/ %p/Inputs/machine-x64.yaml | yaml2obj > %t2.obj
+# RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
+
+INCOMPAT: .obj: machine type x64 conflicts with x86
diff --git a/test/COFF/manifest.test b/test/COFF/manifest.test
new file mode 100644 (file)
index 0000000..33e80e7
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: FileCheck -check-prefix=MANIFEST %s < %t.exe.manifest
+
+MANIFEST: <?xml version="1.0" standalone="yes"?>
+MANIFEST: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+MANIFEST:           manifestVersion="1.0">
+MANIFEST:   <trustInfo>
+MANIFEST:     <security>
+MANIFEST:       <requestedPrivileges>
+MANIFEST:          <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+MANIFEST:       </requestedPrivileges>
+MANIFEST:     </security>
+MANIFEST:   </trustInfo>
+MANIFEST: </assembly>
+
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifestuac:"level='requireAdministrator' uiAccess='true'" %t.obj
+# RUN: FileCheck -check-prefix=UAC %s < %t.exe.manifest
+
+UAC: <?xml version="1.0" standalone="yes"?>
+UAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+UAC:           manifestVersion="1.0">
+UAC:   <trustInfo>
+UAC:     <security>
+UAC:       <requestedPrivileges>
+UAC:          <requestedExecutionLevel level='requireAdministrator' uiAccess='true'/>
+UAC:       </requestedPrivileges>
+UAC:     </security>
+UAC:   </trustInfo>
+UAC: </assembly>
+
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifestdependency:"foo='bar'" %t.obj
+# RUN: FileCheck -check-prefix=DEPENDENCY %s < %t.exe.manifest
+
+DEPENDENCY: <?xml version="1.0" standalone="yes"?>
+DEPENDENCY: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+DEPENDENCY:           manifestVersion="1.0">
+DEPENDENCY:   <trustInfo>
+DEPENDENCY:     <security>
+DEPENDENCY:       <requestedPrivileges>
+DEPENDENCY:          <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+DEPENDENCY:       </requestedPrivileges>
+DEPENDENCY:     </security>
+DEPENDENCY:   </trustInfo>
+DEPENDENCY:   <dependency>
+DEPENDENCY:     <dependentAssembly>
+DEPENDENCY:       <assemblyIdentity foo='bar' />
+DEPENDENCY:     </dependentAssembly>
+DEPENDENCY:   </dependency>
+DEPENDENCY: </assembly>
+
+# RUN: lld-link /out:%t.exe /entry:main /manifestuac:no %t.obj
+# RUN: FileCheck -check-prefix=NOUAC %s < %t.exe.manifest
+
+NOUAC: <?xml version="1.0" standalone="yes"?>
+NOUAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+NOUAC:           manifestVersion="1.0">
+NOUAC: </assembly>
diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test
new file mode 100644 (file)
index 0000000..376d404
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: winres
+
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifestuac:"level='requireAdministrator'" \
+# RUN:   /manifestinput:%p/Inputs/manifestinput.test %t.obj
+# RUN: FileCheck %s < %t.exe.manifest
+
+CHECK: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+CHECK: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity></dependentAssembly></dependency><trustInfo><security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel></requestedPrivileges></security></trustInfo></assembly>
diff --git a/test/COFF/merge.test b/test/COFF/merge.test
new file mode 100644 (file)
index 0000000..4b5c100
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .def
+# CHECK: Name: .abc
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .foo
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+  - Name:            .bar
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/nodefaultlib.test b/test/COFF/nodefaultlib.test
new file mode 100644 (file)
index 0000000..867dc8f
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: cp %p/Inputs/hello64.obj %T
+# RUN: cp %p/Inputs/std64.lib %T
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   hello64.obj /defaultlib:std64.lib >& %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   hello64 /defaultlib:std64.lib >& %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib \
+# RUN:   /nodefaultlib:std64.lib >& %t.log || true
+# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64 \
+# RUN:   /nodefaultlib:std64.lib >& %t.log || true
+# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
+
+CHECK1: hello64.obj: {{[Nn]}}o such file or directory
+CHECK2: hello64: {{[Nn]}}o such file or directory
+CHECK3: hello64.obj: undefined symbol: MessageBoxA
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib
+
+# RUN: env LIB=%T lld-link /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib
diff --git a/test/COFF/noentry.test b/test/COFF/noentry.test
new file mode 100644 (file)
index 0000000..80f387f
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: winres
+# REQUIRES: winlib
+
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s
+# RUN: lld-link /out:%t.dll /dll /noentry %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s
+
+ENTRY:   AddressOfEntryPoint: 0x1000
+NOENTRY: AddressOfEntryPoint: 0x0
diff --git a/test/COFF/opt.test b/test/COFF/opt.test
new file mode 100644 (file)
index 0000000..a8b0e2e
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj \
+# RUN:   /verbose >& %t.log
+### FileCheck doesn't like empty input, so write something.
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj \
+# RUN:   /verbose /opt:noref >& %t.log
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# CHECK1:     Discarded unused
+# CHECK2-NOT: Discarded unused
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            unused
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/options.test b/test/COFF/options.test
new file mode 100644 (file)
index 0000000..39f944b
--- /dev/null
@@ -0,0 +1,51 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
+# RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
+BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND
+
+# RUN: lld-link /allowbind:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s
+NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
+# RUN: lld-link /allowisolation /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
+ISO-NOT: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
+
+# RUN: lld-link /allowisolation:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOISO %s
+NOISO: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
+# RUN: lld-link /out:%t.exe /entry:main /highentropyva %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
+ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
+# RUN: lld-link /out:%t.exe /highentropyva:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s
+NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
+# RUN: lld-link /out:%t.exe /entry:main /nxcompat %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
+NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
+
+# RUN: lld-link /out:%t.exe /nxcompat:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s
+NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
+# RUN: lld-link /out:%t.exe /entry:main /tsaware %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
+TSAWARE: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
+
+# RUN: lld-link /tsaware:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s
+NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
diff --git a/test/COFF/order.test b/test/COFF/order.test
new file mode 100644 (file)
index 0000000..6a0cee8
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj
+# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj
+# RUN: rm -f %t2.lib %t3.lib
+# RUN: llvm-ar cru %t2.lib %t2.obj
+# RUN: llvm-ar cru %t3.lib %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: order.test.tmp1.obj
+CHECK: order.test.tmp3.obj
+CHECK: order.test.tmp2.lib
+CHECK: order.test.tmp3.lib
+CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo
diff --git a/test/COFF/out.test b/test/COFF/out.test
new file mode 100644 (file)
index 0000000..67b2ef0
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: winres
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: mkdir -p %T/out/tmp
+# RUN: cp %t.obj %T/out/out1.obj
+# RUN: cp %t.obj %T/out/tmp/out2
+# RUN: cp %t.obj %T/out/tmp/out3.xyz
+
+# RUN: rm -f out1.exe out2.exe out3.exe out3.dll
+# RUN: lld-link /entry:main %T/out/out1.obj
+# RUN: lld-link /entry:main %T/out/tmp/out2
+# RUN: lld-link /dll /entry:main %T/out/tmp/out3.xyz
+
+# RUN: llvm-readobj out1.exe | FileCheck %s
+# RUN: llvm-readobj out2.exe | FileCheck %s
+# RUN: llvm-readobj out3.dll | FileCheck %s
+
+CHECK: File:
diff --git a/test/COFF/reloc-arm.test b/test/COFF/reloc-arm.test
new file mode 100644 (file)
index 0000000..11b863d
--- /dev/null
@@ -0,0 +1,71 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 402000 01104000 00000000 00000000 00000000
+# CHECK: 402010 01100000 00000000 00000000 00000000
+# CHECK: 402020 01000100 00004000 00000000 00000000
+# CHECK: 402030 fe07e62f 00000000 00000000 00000000
+# CHECK: 402040 3e04de2f 00000000 00000000 00000000
+# CHECK: 402050 fe07d62f 00000000 00000000 00000000
+# CHECK: 402060 00000000 00000000 00000000 00000000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .aaa
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      foo
+        Type:            1  # IMAGE_REL_ARM_ADDR32
+      - VirtualAddress:  16
+        SymbolName:      foo
+        Type:            2  # IMAGE_REL_ARM_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      foo
+        Type:            17  # IMAGE_REL_AMD64_MOV32T
+      - VirtualAddress:  48
+        SymbolName:      foo
+        Type:            20  # IMAGE_REL_AMD64_BRANCH24T
+      - VirtualAddress:  64
+        SymbolName:      foo
+        Type:            18  # IMAGE_REL_ARM_BRANCH20T
+      - VirtualAddress:  80
+        SymbolName:      foo
+        Type:            21  # IMAGE_REL_AMD64_BLX23T
+symbols:
+  - Name:            .aaa
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/reloc-x64.test b/test/COFF/reloc-x64.test
new file mode 100644 (file)
index 0000000..7af8fb2
--- /dev/null
@@ -0,0 +1,102 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 1000: a1 03 20 00 40 00 00 00 00
+# CHECK: 1009: a1 03 20 00 40 01 00 00 00
+# CHECK: 1012: a1 03 20 00 00 00 00 00 00
+# CHECK: 101b: a1 e3 0f 00 00 00 00 00 00
+# CHECK: 1024: a1 d9 0f 00 00 00 00 00 00
+# CHECK: 102d: a1 cf 0f 00 00 00 00 00 00
+# CHECK: 1036: a1 c5 0f 00 00 00 00 00 00
+# CHECK: 103f: a1 bb 0f 00 00 00 00 00 00
+# CHECK: 1048: a1 b1 0f 00 00 00 00 00 00
+# CHECK: 1051: a1 02 00 00 00 00 00 00 00
+# CHECK: 105a: a1 03 00 00 00 00 00 00 00
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  10
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  19
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  28
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  37
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_1
+      - VirtualAddress:  46
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_2
+      - VirtualAddress:  55
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_3
+      - VirtualAddress:  64
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_4
+      - VirtualAddress:  73
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_5
+      - VirtualAddress:  82
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  91
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+  - Name:            .zzz
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .zzz
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           3
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/reloc-x86.test b/test/COFF/reloc-x86.test
new file mode 100644 (file)
index 0000000..5e14069
--- /dev/null
@@ -0,0 +1,82 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /base:0x400000 %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 1000: a1 00 00 00 00
+# CHECK: 1005: a1 03 20 40 00
+# CHECK: 100a: a1 03 20 00 00
+# CHECK: 100f: a1 ef 0f 00 00
+# CHECK: 1014: a1 00 00 02 00
+# CHECK: 1019: a1 03 00 00 00
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     A100000000A100000000A100000000A100000000A100000000A100000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_ABSOLUTE
+      - VirtualAddress:  6
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  11
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_DIR32NB
+      - VirtualAddress:  16
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_REL32
+      - VirtualAddress:  23
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_SECTION
+      - VirtualAddress:  26
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .zzz
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .zzz
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _foo
+    Value:           3
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/resource.test b/test/COFF/resource.test
new file mode 100644 (file)
index 0000000..7b6090d
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: winres
+
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
+
+# Check if the binary contains UTF-16LE string "Hello" copied from resource.res.
+# RUN: FileCheck --check-prefix=EXE %s < %t.exe
+
+EXE: {{H.e.l.l.o}}
+
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck  --check-prefix=HEADER %s
+
+HEADER: ResourceTableRVA: 0x1000
+HEADER: ResourceTableSize: 0x88
diff --git a/test/COFF/responsefile.test b/test/COFF/responsefile.test
new file mode 100644 (file)
index 0000000..fd4d221
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: echo /out:%t.exe /entry:main %t.obj > %t.rsp
+# RUN: lld-link @%t.rsp /heap:0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: SizeOfHeapReserve: 12288
diff --git a/test/COFF/safeseh.test b/test/COFF/safeseh.test
new file mode 100644 (file)
index 0000000..ed928a5
--- /dev/null
@@ -0,0 +1,51 @@
+# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj
+
+# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \
+# RUN:   /safeseh %t.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: /safeseh: {{.*}} is not compatible with SEH
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     0000000000000000
+symbols:
+  - Name:            '@comp.id'
+    Value:           14766605
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           FEAT_VALUE
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/section.test b/test/COFF/section.test
new file mode 100644 (file)
index 0000000..591c04d
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,r %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=R %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,w %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=W %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,e %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=E %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,s %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s
+
+# R:      Characteristics [
+# R-NEXT:   IMAGE_SCN_MEM_READ
+# R-NEXT: ]
+
+# W:      Characteristics [
+# W-NEXT:   IMAGE_SCN_MEM_WRITE
+# W-NEXT: ]
+
+# E:      Characteristics [
+# E-NEXT:   IMAGE_SCN_MEM_EXECUTE
+# E-NEXT: ]
+
+# S:      Characteristics [
+# S-NEXT:   IMAGE_SCN_MEM_SHARED
+# S-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .foo
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/seh.test b/test/COFF/seh.test
new file mode 100644 (file)
index 0000000..f2d0af7
--- /dev/null
@@ -0,0 +1,70 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .rdata:
+# CHECK:  1000 00200000 02200000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     0000000000000000
+  - Name:            .sxdata
+    Characteristics: [ IMAGE_SCN_LNK_INFO ]
+    Alignment:       4
+    SectionData:     0600000007000000
+symbols:
+  - Name:            '@comp.id'
+    Value:           14766605
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147484049
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .sxdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _foo
+    Value:           2
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/sort-debug.test b/test/COFF/sort-debug.test
new file mode 100644 (file)
index 0000000..b04b41a
--- /dev/null
@@ -0,0 +1,296 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .text
+# CHECK: Name: .debug_abbrev
+# CHECK: Name: .debug_info
+# CHECK: Name: .debug_line
+# CHECK: Name: .debug_pubnames
+# CHECK: Name: .debug_pubtypes
+# CHECK: Name: .reloc
+
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     508D0500000000C70424000000005AC3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      '?x@@3HA'
+        Type:            IMAGE_REL_I386_DIR32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     04000000F1000000300000002A00471100000000000000000000000010000000000000000000000000000000000000000000006D61696E0002004F11F200000024000000000000000000010010000000000000000100000018000000000000000100000000000000F4000000080000000100000000000000F30000003C000000005C7573725C6C6F63616C5C676F6F676C655C686F6D655C6D616A6E656D65725C6C6C766D5C7372635C746F6F6C735C6C6C645C3C737464696E3E00
+    Relocations:
+      - VirtualAddress:  44
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  48
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECTION
+      - VirtualAddress:  68
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  72
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECTION
+  - Name:            .debug_str
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_loc
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_abbrev
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     011101250E1305030E10171B0E110112060000023400030E49133F193A0B3B0B02186E0E0000032400030E3E0B0B0B0000042E0011011206E77F194018030E3A0B3B0B49133F19000000
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     54000000040000000000040100000000040037000000000000003F000000000000001000000002720000003B0000000101050300000000780000000374000000050404000000001000000001548000000001013B00000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_abbrev
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  12
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  18
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  22
+        SymbolName:      .debug_line
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  26
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  30
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  39
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  51
+        SymbolName:      '?x@@3HA'
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  55
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  60
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  67
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  77
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_ranges
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_pubnames
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     1D00000002000000000058000000420000006D61696E0026000000780000000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_info
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_pubtypes
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     16000000020000000000580000003B000000696E740000000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_info
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_line
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     3300000002001E0000000101FB0E0D000101010100000001000001003C737464696E3E000000000000050200000000010AD60202000101
+    Relocations:
+      - VirtualAddress:  43
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          16
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          188
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          4
+  - Name:            .debug_str
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          133
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          5
+  - Name:            .debug_loc
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          6
+  - Name:            .debug_abbrev
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          74
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          7
+  - Name:            .debug_info
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          88
+      NumberOfRelocations: 12
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          8
+  - Name:            .debug_ranges
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          9
+  - Name:            .debug_pubnames
+    Value:           0
+    SectionNumber:   10
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          33
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          10
+  - Name:            .debug_pubtypes
+    Value:           0
+    SectionNumber:   11
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          26
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          11
+  - Name:            .debug_line
+    Value:           0
+    SectionNumber:   12
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          55
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          12
+  - Name:            '@feat.00'
+    Value:           1
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?x@@3HA'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/stack.test b/test/COFF/stack.test
new file mode 100644 (file)
index 0000000..df066b1
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: SizeOfStackReserve: 1048576
+DEFAULT: SizeOfStackCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+# RUN: echo "STACKSIZE 12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: SizeOfStackReserve: 12288
+CHECK1: SizeOfStackCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x5000,0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+# RUN: echo "STACKSIZE 20480,12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: SizeOfStackReserve: 20480
+CHECK2: SizeOfStackCommit: 12288
diff --git a/test/COFF/subsystem-inference.test b/test/COFF/subsystem-inference.test
new file mode 100644 (file)
index 0000000..231fd54
--- /dev/null
@@ -0,0 +1,74 @@
+# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s
+
+# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s
+
+# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s
+
+# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s
+
+# MAIN:     Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WMAIN:    Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WINMAIN:  Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+# WWINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            ENTRYNAME
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            wmainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            WinMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            wWinMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/subsystem.test b/test/COFF/subsystem.test
new file mode 100644 (file)
index 0000000..5e72706
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows \
+# RUN:   %p/Inputs/ret42.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: MajorOperatingSystemVersion: 6
+CHECK1: MinorOperatingSystemVersion: 0
+CHECK1: MajorSubsystemVersion: 6
+CHECK1: MinorSubsystemVersion: 0
+CHECK1: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows,8.9 \
+# RUN:   %p/Inputs/ret42.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: MajorOperatingSystemVersion: 8
+CHECK2: MinorOperatingSystemVersion: 9
+CHECK2: MajorSubsystemVersion: 8
+CHECK2: MinorSubsystemVersion: 9
+CHECK2: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
diff --git a/test/COFF/symtab.test b/test/COFF/symtab.test
new file mode 100644 (file)
index 0000000..51eb3a3
--- /dev/null
@@ -0,0 +1,254 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
+# RUN: lld-link /debug /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
+
+# RUN: lld-link /debug /nosymtab /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .text2
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .data
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .data (1)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: message
+# CHECK-NEXT:     Value: 6
+# CHECK-NEXT:     Section: .text2 (3)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: main
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: caption
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text2 (3)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: abs_symbol
+# CHECK-NEXT:     Value: 2662186735
+# CHECK-NEXT:     Section: IMAGE_SYM_ABSOLUTE (-1)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: __imp_ExitProcess
+# CHECK-NEXT:     Value: 64
+# CHECK-NEXT:     Section: .idata (4)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: ExitProcess
+# CHECK-NEXT:     Value: 64
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: __imp_MessageBoxA
+# CHECK-NEXT:     Value: 72
+# CHECK-NEXT:     Section: .idata (4)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: MessageBoxA
+# CHECK-NEXT:     Value: 80
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# NO: Symbols [
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .text2
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     48656C6C6F0048656C6C6F20576F726C6400
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text2
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          18
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            MessageBoxA
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            ExitProcess
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            abs_symbol
+    Value:           0xDEADBEEF
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/tls.test b/test/COFF/tls.test
new file mode 100644 (file)
index 0000000..a577fe8
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: TLSTableRVA: 0x1000
+# CHECK: TLSTableSize: 0x28
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _tls_used
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/tls32.test b/test/COFF/tls32.test
new file mode 100644 (file)
index 0000000..fa39614
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: TLSTableRVA: 0x1000
+# CHECK: TLSTableSize: 0x18
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __tls_used
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/unwind.test b/test/COFF/unwind.test
new file mode 100644 (file)
index 0000000..2415b05
--- /dev/null
@@ -0,0 +1,198 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
+#
+# HEADER: ExceptionTableRVA: 0x1000
+#
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x2000
+# UNWIND:   End Address: 0x201b
+# UNWIND:   Unwind Info Address: 0x3000
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 1 UNW_ExceptionHandler
+# UNWIND:     Size of prolog: 18
+# UNWIND:     Number of Codes: 8
+# UNWIND:     Frame register: RBX
+# UNWIND:     Frame offset: 0
+# UNWIND:     Unwind Codes:
+# UNWIND:       0x12: UOP_SetFPReg
+# UNWIND:       0x0f: UOP_PushNonVol RBX
+# UNWIND:       0x0e: UOP_SaveXMM128 XMM8 [0x0000]
+# UNWIND:       0x09: UOP_SaveNonVol RSI [0x0010]
+# UNWIND:       0x04: UOP_AllocSmall 24
+# UNWIND:       0x00: UOP_PushMachFrame w/o error code
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x2012
+# UNWIND:   End Address: 0x2012
+# UNWIND:   Unwind Info Address: 0x301c
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 4 UNW_ChainInfo
+# UNWIND:     Size of prolog: 0
+# UNWIND:     Number of Codes: 0
+# UNWIND:     No frame pointer used
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x201b
+# UNWIND:   End Address: 0x201c
+# UNWIND:   Unwind Info Address: 0x302c
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 0
+# UNWIND:     Size of prolog: 0
+# UNWIND:     Number of Codes: 0
+# UNWIND:     No frame pointer used
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x201c
+# UNWIND:   End Address: 0x2039
+# UNWIND:   Unwind Info Address: 0x3034
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 0
+# UNWIND:     Size of prolog: 14
+# UNWIND:     Number of Codes: 6
+# UNWIND:     No frame pointer used
+# UNWIND:     Unwind Codes:
+# UNWIND:       0x0e: UOP_AllocLarge 8454128
+# UNWIND:       0x07: UOP_AllocLarge 8190
+# UNWIND:       0x00: UOP_PushMachFrame w/o error code
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     4883EC184889742410440F110424534889E3488D235B4883C418C3C34881ECF0FF00004881ECF0FF80004881C4F0FF80004881C4F0FF0000C3
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0912080312030F300E880000096402000422001A000000000000000021000000000000001B000000000000000100000000000000010E06000E11F0FF80000701FE1F001A
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      __C_specific_handler
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  36
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  40
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000001B0000000000000012000000120000001C00000000000000010000002C000000000000001D00000034000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  12
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  16
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  20
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  24
+        SymbolName:      smallFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  28
+        SymbolName:      smallFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  36
+        SymbolName:      allocFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  40
+        SymbolName:      allocFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  44
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          57
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          68
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          48
+      NumberOfRelocations: 12
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            func
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __C_specific_handler
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            smallFunc
+    Value:           27
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            allocFunc
+    Value:           28
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __C_specific_handler
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/version.test b/test/COFF/version.test
new file mode 100644 (file)
index 0000000..69fa933
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: MajorImageVersion: 0
+DEFAULT: MinorImageVersion: 0
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: MajorImageVersion: 11
+CHECK1: MinorImageVersion: 0
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11.22
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: MajorImageVersion: 11
+CHECK2: MinorImageVersion: 22
diff --git a/test/COFF/weak-external.test b/test/COFF/weak-external.test
new file mode 100644 (file)
index 0000000..e422b2e
--- /dev/null
@@ -0,0 +1,36 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external.ll
+# RUN: lld-link /out:%t1.exe /entry:g /subsystem:console %t.obj
+# RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
+# RUN: FileCheck %s < %t2.map
+
+# CHECK: <lto object>:
+# CHECK-NOT: :
+# CHECK: {{ g$}}
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'g'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL
+    WeakExternal:
+      TagIndex:        2
+      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/weak-external2.test b/test/COFF/weak-external2.test
new file mode 100644 (file)
index 0000000..30101d7
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external2.ll
+# RUN: lld-link /out:%t.exe /entry:g /subsystem:console %t.obj %t.lto.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            'g'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL
+    WeakExternal:
+      TagIndex:        0
+      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+...
diff --git a/test/COFF/weak-external3.test b/test/COFF/weak-external3.test
new file mode 100644 (file)
index 0000000..05ff859
--- /dev/null
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external3.ll
+# RUN: lld-link /out:%t1.exe /entry:f /subsystem:console /lldmap:%t1.map %t.lto.obj
+# RUN: FileCheck --check-prefix=CHECK1 %s < %t1.map
+# RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
+# RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map
+
+# CHECK1: <lto object>:
+# CHECK1-NOT: :
+# CHECK1: {{ g$}}
+
+# CHECK2: weak-external3{{.*}}:
+# CHECK2-NOT: :
+# CHECK2: {{ f$}}
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/Driver/Inputs/libtest.a b/test/Driver/Inputs/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/i386/libtest.a b/test/Driver/Inputs/usr/lib/i386/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/libtest.a b/test/Driver/Inputs/usr/lib/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/ELF/Inputs/aarch64-condb-reloc.s b/test/ELF/Inputs/aarch64-condb-reloc.s
new file mode 100644 (file)
index 0000000..ebe4923
--- /dev/null
@@ -0,0 +1,17 @@
+.globl _foo
+_foo:
+ nop
+ nop
+ nop
+ nop
+
+.globl _bar
+_bar:
+ nop
+ nop
+ nop
+
+.globl _dah
+_dah:
+ nop
+ nop
diff --git a/test/ELF/Inputs/aarch64-copy2.s b/test/ELF/Inputs/aarch64-copy2.s
new file mode 100644 (file)
index 0000000..8f3f748
--- /dev/null
@@ -0,0 +1,5 @@
+        .global foo
+        .type foo, @function
+foo:
+        .global bar
+bar:
diff --git a/test/ELF/Inputs/aarch64-tls-gdie.s b/test/ELF/Inputs/aarch64-tls-gdie.s
new file mode 100644 (file)
index 0000000..289cae5
--- /dev/null
@@ -0,0 +1,4 @@
+        .section        .tdata,"awT",@progbits
+        .globl  a
+a:
+        .word   42
diff --git a/test/ELF/Inputs/aarch64-tls-ie.s b/test/ELF/Inputs/aarch64-tls-ie.s
new file mode 100644 (file)
index 0000000..c5e853b
--- /dev/null
@@ -0,0 +1,19 @@
+.text
+ .global foo
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type foo, %object
+ .size foo, 4
+foo:
+ .word 5
+ .text
+
+.text
+ .global bar
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type bar, %object
+ .size bar, 4
+bar:
+ .word 5
+ .text
diff --git a/test/ELF/Inputs/aarch64-tstbr14-reloc.s b/test/ELF/Inputs/aarch64-tstbr14-reloc.s
new file mode 100644 (file)
index 0000000..64dc440
--- /dev/null
@@ -0,0 +1,12 @@
+.globl _foo
+_foo:
+ nop
+ nop
+ nop
+ nop
+
+.globl _bar
+_bar:
+ nop
+ nop
+ nop
diff --git a/test/ELF/Inputs/abs-hidden.s b/test/ELF/Inputs/abs-hidden.s
new file mode 100644 (file)
index 0000000..44bff38
--- /dev/null
@@ -0,0 +1,3 @@
+.global foo
+.hidden foo
+foo = 0x42
diff --git a/test/ELF/Inputs/abs.s b/test/ELF/Inputs/abs.s
new file mode 100644 (file)
index 0000000..dc7f67a
--- /dev/null
@@ -0,0 +1,4 @@
+.global abs
+abs = 0x42
+.global big
+big = 0x1000000000
diff --git a/test/ELF/Inputs/abs255.s b/test/ELF/Inputs/abs255.s
new file mode 100644 (file)
index 0000000..844ae7d
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 255
diff --git a/test/ELF/Inputs/abs256.s b/test/ELF/Inputs/abs256.s
new file mode 100644 (file)
index 0000000..3f53bc5
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 256
diff --git a/test/ELF/Inputs/abs257.s b/test/ELF/Inputs/abs257.s
new file mode 100644 (file)
index 0000000..4ae7fe8
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 257
diff --git a/test/ELF/Inputs/allow-multiple-definition.s b/test/ELF/Inputs/allow-multiple-definition.s
new file mode 100644 (file)
index 0000000..c2655a4
--- /dev/null
@@ -0,0 +1,4 @@
+.globl _bar
+.type _bar, @function
+_bar:
+  mov $2, %eax
diff --git a/test/ELF/Inputs/allow-shlib-undefined.s b/test/ELF/Inputs/allow-shlib-undefined.s
new file mode 100644 (file)
index 0000000..5e3a461
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _shared
+_shared:
+  callq _unresolved@PLT
diff --git a/test/ELF/Inputs/archive.s b/test/ELF/Inputs/archive.s
new file mode 100644 (file)
index 0000000..568bc1f
--- /dev/null
@@ -0,0 +1,5 @@
+.globl _start
+_start:
+
+.globl end
+end:
diff --git a/test/ELF/Inputs/archive2.s b/test/ELF/Inputs/archive2.s
new file mode 100644 (file)
index 0000000..ade7955
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo:
diff --git a/test/ELF/Inputs/archive3.s b/test/ELF/Inputs/archive3.s
new file mode 100644 (file)
index 0000000..3e11d43
--- /dev/null
@@ -0,0 +1,2 @@
+.global bar
+bar:
diff --git a/test/ELF/Inputs/archive4.s b/test/ELF/Inputs/archive4.s
new file mode 100644 (file)
index 0000000..e842874
--- /dev/null
@@ -0,0 +1 @@
+.quad bar
diff --git a/test/ELF/Inputs/arm-plt-reloc.s b/test/ELF/Inputs/arm-plt-reloc.s
new file mode 100644 (file)
index 0000000..29f133e
--- /dev/null
@@ -0,0 +1,14 @@
+.text
+ .align 2
+ .globl func1
+ .type  func1,%function
+func1:
+ bx lr
+ .globl func2
+ .type  func2,%function
+func2:
+ bx lr
+ .globl func3
+ .type  func3,%function
+func3:
+ bx lr
diff --git a/test/ELF/Inputs/arm-thumb-blx-targets.s b/test/ELF/Inputs/arm-thumb-blx-targets.s
new file mode 100644 (file)
index 0000000..4585ac4
--- /dev/null
@@ -0,0 +1,36 @@
+ .syntax unified
+ .arm
+ .section .R_ARM_CALL24_callee_low, "ax",%progbits
+ .align 2
+ .globl callee_low
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .R_ARM_CALL24_callee_thumb_low, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_thumb_low,%function
+ .globl callee_thumb_low
+callee_thumb_low:
+  bx lr
+
+ .section .R_ARM_CALL24_callee_high, "ax",%progbits
+ .balign 0x100
+ .arm
+ .globl callee_high
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+ .section .R_ARM_CALL24_callee_thumb_high, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_thumb_high,%function
+ .globl callee_thumb_high
+callee_thumb_high:
+  bx lr
+
+ .globl blx_far
+ .type   blx_far, %function
+blx_far = 0x1010018
diff --git a/test/ELF/Inputs/arm-thumb-narrow-branch.o b/test/ELF/Inputs/arm-thumb-narrow-branch.o
new file mode 100644 (file)
index 0000000..9816ec7
Binary files /dev/null and b/test/ELF/Inputs/arm-thumb-narrow-branch.o differ
diff --git a/test/ELF/Inputs/arm-thumb-narrow-branch.s b/test/ELF/Inputs/arm-thumb-narrow-branch.s
new file mode 100644 (file)
index 0000000..473a8e6
--- /dev/null
@@ -0,0 +1,18 @@
+// This input must be assembled by the GNU assembler, as llvm-mc does not emit
+// the R_ARM_JUMP11 relocation for a Thumb narrow branch. This is permissible
+// by the ABI for the ARM architecture as the range of the Thumb narrow branch
+// is short enough (+- 2048 bytes) that widespread use would be impractical.
+//
+// The test case will use a pre compiled object arm-thumb-narrow-branch.o
+ .syntax unified
+ .section .caller, "ax",%progbits
+ .thumb
+ .align 2
+ .type callers,%function
+ .globl callers
+callers:
+ b.n callee_low_far
+ b.n callee_low
+ b.n callee_high
+ b.n callee_high_far
+ bx lr
diff --git a/test/ELF/Inputs/comdat.s b/test/ELF/Inputs/comdat.s
new file mode 100644 (file)
index 0000000..467bfa4
--- /dev/null
@@ -0,0 +1,3 @@
+        .section .text3,"axG",@progbits,zed,comdat,unique,0
+        .global abc
+abc:
diff --git a/test/ELF/Inputs/common.s b/test/ELF/Inputs/common.s
new file mode 100644 (file)
index 0000000..ea8ba91
--- /dev/null
@@ -0,0 +1,3 @@
+.comm sym1,8,4
+.comm sym2,4,4
+.comm sym4,4,16
diff --git a/test/ELF/Inputs/conflict.s b/test/ELF/Inputs/conflict.s
new file mode 100644 (file)
index 0000000..545ae99
--- /dev/null
@@ -0,0 +1,7 @@
+.globl _Z3muldd, foo, baz
+_Z3muldd:
+foo:
+baz:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/Inputs/copy-in-shared.s b/test/ELF/Inputs/copy-in-shared.s
new file mode 100644 (file)
index 0000000..52e99c6
--- /dev/null
@@ -0,0 +1,4 @@
+.type foo, @object
+.global foo
+foo:
+.size foo, 4
diff --git a/test/ELF/Inputs/copy-rel-corrupted.s b/test/ELF/Inputs/copy-rel-corrupted.s
new file mode 100644 (file)
index 0000000..b8d1b1a
--- /dev/null
@@ -0,0 +1,4 @@
+.type x,@object
+.globl x
+x:
+.size x, 0
diff --git a/test/ELF/Inputs/copy-rel-pie.s b/test/ELF/Inputs/copy-rel-pie.s
new file mode 100644 (file)
index 0000000..6cd681f
--- /dev/null
@@ -0,0 +1,9 @@
+.global foo
+.type foo, @object
+.size foo, 4
+foo:
+.long 0
+
+.global bar
+.type bar, @function
+bar:
diff --git a/test/ELF/Inputs/ctors_dtors_priority1.s b/test/ELF/Inputs/ctors_dtors_priority1.s
new file mode 100644 (file)
index 0000000..2eb19d7
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xA1
+
+.section .dtors, "aw", @progbits
+  .byte 0xA2
diff --git a/test/ELF/Inputs/ctors_dtors_priority2.s b/test/ELF/Inputs/ctors_dtors_priority2.s
new file mode 100644 (file)
index 0000000..fb85ce8
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xB1
+
+.section .dtors, "aw", @progbits
+  .byte 0xB2
diff --git a/test/ELF/Inputs/ctors_dtors_priority3.s b/test/ELF/Inputs/ctors_dtors_priority3.s
new file mode 100644 (file)
index 0000000..96418d3
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xC1
+
+.section .dtors, "aw", @progbits
+  .byte 0xC2
diff --git a/test/ELF/Inputs/discard-merge-unnamed.o b/test/ELF/Inputs/discard-merge-unnamed.o
new file mode 100644 (file)
index 0000000..040addf
Binary files /dev/null and b/test/ELF/Inputs/discard-merge-unnamed.o differ
diff --git a/test/ELF/Inputs/duplicated-plt-entry.s b/test/ELF/Inputs/duplicated-plt-entry.s
new file mode 100644 (file)
index 0000000..689f3af
--- /dev/null
@@ -0,0 +1,3 @@
+.global bar
+.type bar, @gnu_indirect_function
+bar:
diff --git a/test/ELF/Inputs/dynamic-reloc-weak.s b/test/ELF/Inputs/dynamic-reloc-weak.s
new file mode 100644 (file)
index 0000000..2310749
--- /dev/null
@@ -0,0 +1,11 @@
+        .type sym1,@function
+        .global sym1
+sym1:
+
+        .type sym2,@function
+        .global sym2
+sym2:
+
+        .type sym3,@function
+        .global sym3
+sym3:
diff --git a/test/ELF/Inputs/dynamic-reloc.s b/test/ELF/Inputs/dynamic-reloc.s
new file mode 100644 (file)
index 0000000..82fa7a1
--- /dev/null
@@ -0,0 +1,2 @@
+.global main
+main:
diff --git a/test/ELF/Inputs/ehframe-relocation.s b/test/ELF/Inputs/ehframe-relocation.s
new file mode 100644 (file)
index 0000000..7ba6c05
--- /dev/null
@@ -0,0 +1,2 @@
+        .cfi_startproc
+        .cfi_endproc
diff --git a/test/ELF/Inputs/empty-ver.ver b/test/ELF/Inputs/empty-ver.ver
new file mode 100644 (file)
index 0000000..7d4b4ed
--- /dev/null
@@ -0,0 +1,2 @@
+ver {
+};
diff --git a/test/ELF/Inputs/far-arm-abs.s b/test/ELF/Inputs/far-arm-abs.s
new file mode 100644 (file)
index 0000000..68d6aab
--- /dev/null
@@ -0,0 +1,13 @@
+.global far
+.type far,%function
+far = 0x201001c
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x2020008
+.global too_far2
+.type too_far2,%function
+too_far2 = 0x202000c
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x2020010
diff --git a/test/ELF/Inputs/far-arm-thumb-abs.s b/test/ELF/Inputs/far-arm-thumb-abs.s
new file mode 100644 (file)
index 0000000..0eb99b8
--- /dev/null
@@ -0,0 +1,24 @@
+.global far_cond
+.type far_cond,%function
+far_cond = 0x110023
+.global far_uncond
+.type far_uncond,%function
+far_uncond = 0x101001b
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x1020005
+.global too_far2
+.type too_far1,%function
+too_far2 = 0x1020009
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x12000d
+
+.global blx_far
+.type   blx_far, %function
+blx_far = 0x2010025
+
+.global blx_far2
+.type   blx_far2, %function
+blx_far2 = 0x2010029
diff --git a/test/ELF/Inputs/gc-sections-weak.s b/test/ELF/Inputs/gc-sections-weak.s
new file mode 100644 (file)
index 0000000..27baa66
--- /dev/null
@@ -0,0 +1,8 @@
+.weak foo
+foo:
+        nop
+
+.data
+.global bar2
+bar2:
+.quad foo
diff --git a/test/ELF/Inputs/gnu-ifunc-gotpcrel.s b/test/ELF/Inputs/gnu-ifunc-gotpcrel.s
new file mode 100644 (file)
index 0000000..83b06e0
--- /dev/null
@@ -0,0 +1,4 @@
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ret
diff --git a/test/ELF/Inputs/gotpc-relax-und-dso.s b/test/ELF/Inputs/gotpc-relax-und-dso.s
new file mode 100644 (file)
index 0000000..cbe39f3
--- /dev/null
@@ -0,0 +1,4 @@
+.globl dsofoo
+.type dsofoo, @function
+dsofoo:
+ nop
diff --git a/test/ELF/Inputs/icf2.s b/test/ELF/Inputs/icf2.s
new file mode 100644 (file)
index 0000000..d332130
--- /dev/null
@@ -0,0 +1,5 @@
+.globl f1, f2
+.section .text.f2, "ax"
+f2:
+  mov $60, %rdi
+  call f1
diff --git a/test/ELF/Inputs/invalid-binding.elf b/test/ELF/Inputs/invalid-binding.elf
new file mode 100644 (file)
index 0000000..61b5af9
Binary files /dev/null and b/test/ELF/Inputs/invalid-binding.elf differ
diff --git a/test/ELF/Inputs/invalid-cie-version2.elf b/test/ELF/Inputs/invalid-cie-version2.elf
new file mode 100644 (file)
index 0000000..87f8a5b
Binary files /dev/null and b/test/ELF/Inputs/invalid-cie-version2.elf differ
diff --git a/test/ELF/Inputs/invalid-data-encoding.a b/test/ELF/Inputs/invalid-data-encoding.a
new file mode 100644 (file)
index 0000000..ff2b373
Binary files /dev/null and b/test/ELF/Inputs/invalid-data-encoding.a differ
diff --git a/test/ELF/Inputs/invalid-file-class.a b/test/ELF/Inputs/invalid-file-class.a
new file mode 100644 (file)
index 0000000..f0ce607
Binary files /dev/null and b/test/ELF/Inputs/invalid-file-class.a differ
diff --git a/test/ELF/Inputs/invalid-multiple-eh-relocs.elf b/test/ELF/Inputs/invalid-multiple-eh-relocs.elf
new file mode 100644 (file)
index 0000000..6291459
Binary files /dev/null and b/test/ELF/Inputs/invalid-multiple-eh-relocs.elf differ
diff --git a/test/ELF/Inputs/invalid-section-index.elf b/test/ELF/Inputs/invalid-section-index.elf
new file mode 100644 (file)
index 0000000..ec5adcf
Binary files /dev/null and b/test/ELF/Inputs/invalid-section-index.elf differ
diff --git a/test/ELF/Inputs/invalid-shentsize-zero.elf b/test/ELF/Inputs/invalid-shentsize-zero.elf
new file mode 100644 (file)
index 0000000..5fa7df2
Binary files /dev/null and b/test/ELF/Inputs/invalid-shentsize-zero.elf differ
diff --git a/test/ELF/Inputs/invalid-shstrndx.so b/test/ELF/Inputs/invalid-shstrndx.so
new file mode 100755 (executable)
index 0000000..dc332b9
Binary files /dev/null and b/test/ELF/Inputs/invalid-shstrndx.so differ
diff --git a/test/ELF/Inputs/invalid-symtab-sh_info.elf b/test/ELF/Inputs/invalid-symtab-sh_info.elf
new file mode 100644 (file)
index 0000000..aa63d58
Binary files /dev/null and b/test/ELF/Inputs/invalid-symtab-sh_info.elf differ
diff --git a/test/ELF/Inputs/libsearch-dyn.s b/test/ELF/Inputs/libsearch-dyn.s
new file mode 100644 (file)
index 0000000..091b3b9
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_dynamic
+_bar:
+_dynamic:
diff --git a/test/ELF/Inputs/libsearch-st.s b/test/ELF/Inputs/libsearch-st.s
new file mode 100644 (file)
index 0000000..6da62f7
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_static
+_bar:
+_static:
diff --git a/test/ELF/Inputs/llvm33-rela-outside-group.o b/test/ELF/Inputs/llvm33-rela-outside-group.o
new file mode 100644 (file)
index 0000000..70e659f
Binary files /dev/null and b/test/ELF/Inputs/llvm33-rela-outside-group.o differ
diff --git a/test/ELF/Inputs/merge.s b/test/ELF/Inputs/merge.s
new file mode 100644 (file)
index 0000000..a8e1144
--- /dev/null
@@ -0,0 +1,6 @@
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .long   0x42
+
+        .text
+        movl .mysec, %eax
diff --git a/test/ELF/Inputs/mips-align-err.s b/test/ELF/Inputs/mips-align-err.s
new file mode 100644 (file)
index 0000000..2d813b7
--- /dev/null
@@ -0,0 +1,2 @@
+        .global _foo
+_foo:
diff --git a/test/ELF/Inputs/mips-dynamic.s b/test/ELF/Inputs/mips-dynamic.s
new file mode 100644 (file)
index 0000000..6f15cf3
--- /dev/null
@@ -0,0 +1,28 @@
+  .option pic2
+  .text
+  .globl _foo
+_foo:
+  nop
+
+  .globl foo0
+  .type foo0, @function
+foo0:
+  nop
+
+  .globl foo1
+  .type foo1, @function
+foo1:
+  nop
+
+  .data
+  .globl data0
+  .type data0, @object
+  .size data0, 4
+data0:
+  .word 0
+
+  .globl data1
+  .type data1, @object
+  .size data1, 4
+data1:
+  .word 0
diff --git a/test/ELF/Inputs/mips-gp-disp.so b/test/ELF/Inputs/mips-gp-disp.so
new file mode 100644 (file)
index 0000000..150de18
Binary files /dev/null and b/test/ELF/Inputs/mips-gp-disp.so differ
diff --git a/test/ELF/Inputs/mips-gprel32-gp0.o b/test/ELF/Inputs/mips-gprel32-gp0.o
new file mode 100644 (file)
index 0000000..0139bd9
Binary files /dev/null and b/test/ELF/Inputs/mips-gprel32-gp0.o differ
diff --git a/test/ELF/Inputs/mips-nonalloc.s b/test/ELF/Inputs/mips-nonalloc.s
new file mode 100644 (file)
index 0000000..72bfd27
--- /dev/null
@@ -0,0 +1,2 @@
+  .section .debug_info
+  .word __start
diff --git a/test/ELF/Inputs/mips-options.o b/test/ELF/Inputs/mips-options.o
new file mode 100644 (file)
index 0000000..ace9385
Binary files /dev/null and b/test/ELF/Inputs/mips-options.o differ
diff --git a/test/ELF/Inputs/mips-pic.s b/test/ELF/Inputs/mips-pic.s
new file mode 100644 (file)
index 0000000..8809032
--- /dev/null
@@ -0,0 +1,19 @@
+  .option pic2
+
+  .section .text.1,"ax",@progbits
+  .align 4
+  .globl foo1a
+  .type foo1a, @function
+foo1a:
+  nop
+  .globl foo1b
+  .type foo1b, @function
+foo1b:
+  nop
+
+  .section .text.2,"ax",@progbits
+  .align 4
+  .globl foo2
+  .type foo2, @function
+foo2:
+  nop
diff --git a/test/ELF/Inputs/mips-sto-pic.o b/test/ELF/Inputs/mips-sto-pic.o
new file mode 100644 (file)
index 0000000..484dbc4
Binary files /dev/null and b/test/ELF/Inputs/mips-sto-pic.o differ
diff --git a/test/ELF/Inputs/mips-tls.s b/test/ELF/Inputs/mips-tls.s
new file mode 100644 (file)
index 0000000..9e0a098
--- /dev/null
@@ -0,0 +1,5 @@
+ .globl   foo
+ .section .tdata,"awT",%progbits
+ .type    foo, %object
+foo:
+ .word 0
diff --git a/test/ELF/Inputs/no-symtab.o b/test/ELF/Inputs/no-symtab.o
new file mode 100644 (file)
index 0000000..7368ba2
Binary files /dev/null and b/test/ELF/Inputs/no-symtab.o differ
diff --git a/test/ELF/Inputs/plt-aarch64.s b/test/ELF/Inputs/plt-aarch64.s
new file mode 100644 (file)
index 0000000..0f7a4ed
--- /dev/null
@@ -0,0 +1,5 @@
+.global bar
+bar:
+
+.global weak
+weak:
diff --git a/test/ELF/Inputs/ppc64-addr16-error.s b/test/ELF/Inputs/ppc64-addr16-error.s
new file mode 100644 (file)
index 0000000..d83a9f9
--- /dev/null
@@ -0,0 +1,3 @@
+.global sym
+.hidden sym
+sym = 0
diff --git a/test/ELF/Inputs/progname-ver.so b/test/ELF/Inputs/progname-ver.so
new file mode 100755 (executable)
index 0000000..e6bb322
Binary files /dev/null and b/test/ELF/Inputs/progname-ver.so differ
diff --git a/test/ELF/Inputs/protected-shared.s b/test/ELF/Inputs/protected-shared.s
new file mode 100644 (file)
index 0000000..5f4b1da
--- /dev/null
@@ -0,0 +1,10 @@
+        .global foo
+        .protected foo
+foo:
+
+        .global bar
+        .protected bar
+bar:
+
+        .global zed
+zed:
diff --git a/test/ELF/Inputs/relocatable-ehframe.s b/test/ELF/Inputs/relocatable-ehframe.s
new file mode 100644 (file)
index 0000000..384aac6
--- /dev/null
@@ -0,0 +1,14 @@
+.section foo1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/Inputs/relocatable.s b/test/ELF/Inputs/relocatable.s
new file mode 100644 (file)
index 0000000..de34a6b
--- /dev/null
@@ -0,0 +1,22 @@
+.text
+.type xx,@object
+.bss
+.globl xx
+.align 4
+xx:
+.long 0
+.size xx, 4
+.type yy,@object
+.globl yy
+.align 4
+yy:
+.long 0
+.size yy, 4
+
+.text
+.globl foo
+.align 16, 0x90
+.type foo,@function
+foo:
+movl $1, xx
+movl $2, yy
diff --git a/test/ELF/Inputs/relocatable2.s b/test/ELF/Inputs/relocatable2.s
new file mode 100644 (file)
index 0000000..93e23bc
--- /dev/null
@@ -0,0 +1,22 @@
+.text
+.type xxx,@object
+.bss
+.globl xxx
+.align 4
+xxx:
+.long 0
+.size xxx, 4
+.type yyy,@object
+.globl yyy
+.align 4
+yyy:
+.long 0
+.size yyy, 4
+
+.text
+.globl bar
+.align 16, 0x90
+.type bar,@function
+bar:
+movl $8, xxx
+movl $9, yyy
diff --git a/test/ELF/Inputs/relocation-copy-alias.s b/test/ELF/Inputs/relocation-copy-alias.s
new file mode 100644 (file)
index 0000000..a9bc3d7
--- /dev/null
@@ -0,0 +1,25 @@
+.data
+
+.globl a1
+.type a1, @object
+.size a1, 1
+a1:
+.weak a2
+.type a2, @object
+.size a2, 1
+a2:
+.byte 1
+
+.weak b1
+.type b1, @object
+.size b1, 1
+b1:
+.weak b2
+.type b2, @object
+.size b2, 1
+b2:
+.globl b3
+.type b3, @object
+.size b3, 1
+b3:
+.byte 1
diff --git a/test/ELF/Inputs/relocation-copy-align.s b/test/ELF/Inputs/relocation-copy-align.s
new file mode 100644 (file)
index 0000000..83dedc7
--- /dev/null
@@ -0,0 +1,9 @@
+.data
+        .balign 16
+        .zero 12
+
+        .type x,@object
+        .globl x
+x:
+        .long 0
+        .size x, 4
diff --git a/test/ELF/Inputs/relocation-copy-arm.s b/test/ELF/Inputs/relocation-copy-arm.s
new file mode 100644 (file)
index 0000000..ba5ab73
--- /dev/null
@@ -0,0 +1,22 @@
+.bss
+
+.type x,%object
+.globl x
+.balign 16
+x:
+.long 0
+.size x, 4
+
+.type y,%object
+.globl y
+.balign 16
+y:
+.long 0
+.size y, 4
+
+.type z,%object
+.globl z
+.balign 4
+z:
+.long 0
+.size z, 4
diff --git a/test/ELF/Inputs/relocation-copy.s b/test/ELF/Inputs/relocation-copy.s
new file mode 100644 (file)
index 0000000..6b113ab
--- /dev/null
@@ -0,0 +1,22 @@
+.bss
+
+.type x,@object
+.globl x
+.balign 16
+x:
+.long 0
+.size x, 4
+
+.type y,@object
+.globl y
+.balign 16
+y:
+.long 0
+.size y, 4
+
+.type z,@object
+.globl z
+.balign 4
+z:
+.long 0
+.size z, 4
diff --git a/test/ELF/Inputs/relocation-size-shared.s b/test/ELF/Inputs/relocation-size-shared.s
new file mode 100644 (file)
index 0000000..02b4cf0
--- /dev/null
@@ -0,0 +1,6 @@
+.data
+.global fooshared
+.type fooshared,%object
+.size fooshared,26
+fooshared:
+.zero 26
diff --git a/test/ELF/Inputs/resolution-shared.s b/test/ELF/Inputs/resolution-shared.s
new file mode 100644 (file)
index 0000000..2f0ccf8
--- /dev/null
@@ -0,0 +1,2 @@
+        .global foo
+foo:
diff --git a/test/ELF/Inputs/resolution.s b/test/ELF/Inputs/resolution.s
new file mode 100644 (file)
index 0000000..70afb16
--- /dev/null
@@ -0,0 +1,107 @@
+local:
+
+.weak RegularWeak_with_RegularWeak
+.size RegularWeak_with_RegularWeak, 32
+RegularWeak_with_RegularWeak:
+
+.global RegularWeak_with_RegularStrong
+.size RegularWeak_with_RegularStrong, 33
+RegularWeak_with_RegularStrong:
+
+.weak RegularStrong_with_RegularWeak
+.size RegularStrong_with_RegularWeak, 34
+RegularStrong_with_RegularWeak:
+
+.weak RegularWeak_with_UndefWeak
+.size RegularWeak_with_UndefWeak, 35
+.quad RegularWeak_with_UndefWeak
+
+.size RegularWeak_with_UndefStrong, 36
+.quad RegularWeak_with_UndefStrong
+
+.weak RegularStrong_with_UndefWeak
+.size RegularStrong_with_UndefWeak, 37
+.quad RegularStrong_with_UndefWeak
+
+.size RegularStrong_with_UndefStrong, 38
+.quad RegularStrong_with_UndefStrong
+
+.weak RegularWeak_with_CommonWeak
+.comm RegularWeak_with_CommonWeak,39,4
+
+.comm RegularWeak_with_CommonStrong,40,4
+
+.weak RegularStrong_with_CommonWeak
+.comm RegularStrong_with_CommonWeak,41,4
+
+.comm RegularStrong_with_CommonStrong,42,4
+
+.weak UndefWeak_with_RegularWeak
+.size UndefWeak_with_RegularWeak, 43
+UndefWeak_with_RegularWeak:
+
+.global UndefWeak_with_RegularStrong
+.size UndefWeak_with_RegularStrong, 44
+UndefWeak_with_RegularStrong:
+
+.weak UndefStrong_with_RegularWeak
+.size UndefStrong_with_RegularWeak, 45
+UndefStrong_with_RegularWeak:
+
+.global UndefStrong_with_RegularStrong
+.size UndefStrong_with_RegularStrong, 46
+UndefStrong_with_RegularStrong:
+
+.weak UndefWeak_with_UndefWeak
+.size UndefWeak_with_UndefWeak, 47
+.quad UndefWeak_with_UndefWeak
+
+.weak UndefWeak_with_CommonWeak
+.comm UndefWeak_with_CommonWeak,48,4
+
+.comm UndefWeak_with_CommonStrong,49,4
+
+.weak UndefStrong_with_CommonWeak
+.comm UndefStrong_with_CommonWeak,50,4
+
+.comm UndefStrong_with_CommonStrong,51,4
+
+.weak CommonWeak_with_RegularWeak
+.size CommonWeak_with_RegularWeak, 52
+CommonWeak_with_RegularWeak:
+
+.global CommonWeak_with_RegularStrong
+.size CommonWeak_with_RegularStrong, 53
+CommonWeak_with_RegularStrong:
+
+.weak CommonStrong_with_RegularWeak
+.size CommonStrong_with_RegularWeak, 54
+CommonStrong_with_RegularWeak:
+
+.global CommonStrong_with_RegularStrong
+.size CommonStrong_with_RegularStrong, 55
+CommonStrong_with_RegularStrong:
+
+.weak CommonWeak_with_UndefWeak
+.size CommonWeak_with_UndefWeak, 56
+.quad CommonWeak_with_UndefWeak
+
+.size CommonWeak_with_UndefStrong, 57
+.quad CommonWeak_with_UndefStrong
+
+.weak CommonStrong_with_UndefWeak
+.size CommonStrong_with_UndefWeak, 58
+.quad CommonStrong_with_UndefWeak
+
+.size CommonStrong_with_UndefStrong, 59
+.quad CommonStrong_with_UndefStrong
+
+.weak CommonWeak_with_CommonWeak
+.comm CommonWeak_with_CommonWeak,60,4
+
+.comm CommonWeak_with_CommonStrong,61,4
+
+.weak CommonStrong_with_CommonWeak
+.comm CommonStrong_with_CommonWeak,62,4
+
+.comm CommonStrong_with_CommonStrong,63,4
diff --git a/test/ELF/Inputs/shared-ppc64.s b/test/ELF/Inputs/shared-ppc64.s
new file mode 100644 (file)
index 0000000..b0117ac
--- /dev/null
@@ -0,0 +1,9 @@
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC.@tocbase,0
+.quad   .Lbar,0,0
+
+.text
+.Lbar:
+        blr
diff --git a/test/ELF/Inputs/shared.s b/test/ELF/Inputs/shared.s
new file mode 100644 (file)
index 0000000..c3c22fe
--- /dev/null
@@ -0,0 +1,10 @@
+.global bar
+.type bar, @function
+bar:
+
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed
+zed:
diff --git a/test/ELF/Inputs/shared2.s b/test/ELF/Inputs/shared2.s
new file mode 100644 (file)
index 0000000..a723902
--- /dev/null
@@ -0,0 +1,6 @@
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed2
+zed2:
diff --git a/test/ELF/Inputs/shared3.s b/test/ELF/Inputs/shared3.s
new file mode 100644 (file)
index 0000000..d1f6ffe
--- /dev/null
@@ -0,0 +1,3 @@
+.global baz
+.type barz, @function
+baz:
diff --git a/test/ELF/Inputs/start-lib-comdat.s b/test/ELF/Inputs/start-lib-comdat.s
new file mode 100644 (file)
index 0000000..dcbaaf4
--- /dev/null
@@ -0,0 +1,5 @@
+        .global bar
+bar:
+        .section        .sec,"aG",@progbits,zed,comdat
+        .global zed
+zed:
diff --git a/test/ELF/Inputs/start-lib1.s b/test/ELF/Inputs/start-lib1.s
new file mode 100644 (file)
index 0000000..d401b20
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+  call bar
diff --git a/test/ELF/Inputs/start-lib2.s b/test/ELF/Inputs/start-lib2.s
new file mode 100644 (file)
index 0000000..f500936
--- /dev/null
@@ -0,0 +1,2 @@
+.globl bar
+bar:
diff --git a/test/ELF/Inputs/symbol-override.s b/test/ELF/Inputs/symbol-override.s
new file mode 100644 (file)
index 0000000..21f3ae2
--- /dev/null
@@ -0,0 +1,16 @@
+.text
+.globl foo
+.type foo,@function
+foo:
+nop
+
+.globl bar
+.type bar,@function
+bar:
+nop
+
+.globl do
+.type do,@function
+do: 
+callq foo@PLT
+callq bar@PLT
diff --git a/test/ELF/Inputs/tls-got-entry.s b/test/ELF/Inputs/tls-got-entry.s
new file mode 100644 (file)
index 0000000..e1e09a3
--- /dev/null
@@ -0,0 +1,13 @@
+.globl __tls_get_addr
+.align 16, 0x90
+.type __tls_get_addr,@function
+__tls_get_addr:
+
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
diff --git a/test/ELF/Inputs/tls-got.s b/test/ELF/Inputs/tls-got.s
new file mode 100644 (file)
index 0000000..5681d00
--- /dev/null
@@ -0,0 +1,14 @@
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
diff --git a/test/ELF/Inputs/tls-in-archive.s b/test/ELF/Inputs/tls-in-archive.s
new file mode 100644 (file)
index 0000000..0474a41
--- /dev/null
@@ -0,0 +1,3 @@
+        .type foo, @tls_object
+        .globl  foo
+foo:
diff --git a/test/ELF/Inputs/tls-mismatch.s b/test/ELF/Inputs/tls-mismatch.s
new file mode 100644 (file)
index 0000000..8c14f58
--- /dev/null
@@ -0,0 +1,4 @@
+.tbss
+.globl tlsvar
+tlsvar:
+  .space 4
diff --git a/test/ELF/Inputs/tls-opt-gdie.s b/test/ELF/Inputs/tls-opt-gdie.s
new file mode 100644 (file)
index 0000000..361578f
--- /dev/null
@@ -0,0 +1,20 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type  tlsshared1,@object
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
+
+.text
+.globl __tls_get_addr
+.align 16, 0x90
+.type __tls_get_addr,@function
+__tls_get_addr:
diff --git a/test/ELF/Inputs/tls-opt-gdiele-i686.s b/test/ELF/Inputs/tls-opt-gdiele-i686.s
new file mode 100644 (file)
index 0000000..ab72b9d
--- /dev/null
@@ -0,0 +1,20 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type  tlsshared1,@object
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
+
+.text
+ .globl __tls_get_addr
+ .align 16, 0x90
+ .type __tls_get_addr,@function
+__tls_get_addr:
diff --git a/test/ELF/Inputs/tls-opt-iele-i686-nopic.s b/test/ELF/Inputs/tls-opt-iele-i686-nopic.s
new file mode 100644 (file)
index 0000000..a090065
--- /dev/null
@@ -0,0 +1,15 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type tlsshared1,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
diff --git a/test/ELF/Inputs/trace-ar1.s b/test/ELF/Inputs/trace-ar1.s
new file mode 100644 (file)
index 0000000..0292bae
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _used
+_used:
diff --git a/test/ELF/Inputs/trace-ar2.s b/test/ELF/Inputs/trace-ar2.s
new file mode 100644 (file)
index 0000000..d56f304
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _notused
+_notused:
diff --git a/test/ELF/Inputs/trace-symbols-foo-strong.s b/test/ELF/Inputs/trace-symbols-foo-strong.s
new file mode 100644 (file)
index 0000000..8746429
--- /dev/null
@@ -0,0 +1,14 @@
+.text
+.globl foo
+.type  foo, @function
+foo:
+nop
+
+.globl bar
+.type  bar, @function
+bar:
+nop
+
+.global func2
+.type   func2, @function
+func2:
diff --git a/test/ELF/Inputs/trace-symbols-foo-weak.s b/test/ELF/Inputs/trace-symbols-foo-weak.s
new file mode 100644 (file)
index 0000000..d071ebe
--- /dev/null
@@ -0,0 +1,12 @@
+.comm  common,4,4
+.text
+.weak  foo
+.type  foo, @function
+foo:
+callq bar@PLT
+
+.globl  func1
+.type   func1, @function
+func1:
+call func2@PLT
+
diff --git a/test/ELF/Inputs/undef-with-plt-addr.s b/test/ELF/Inputs/undef-with-plt-addr.s
new file mode 100644 (file)
index 0000000..b12737d
--- /dev/null
@@ -0,0 +1,7 @@
+       .globl  set_data
+       .type   set_data,@function
+set_data:
+
+        .globl  foo
+        .type   foo,@function
+foo:
diff --git a/test/ELF/Inputs/undef.s b/test/ELF/Inputs/undef.s
new file mode 100644 (file)
index 0000000..01776bf
--- /dev/null
@@ -0,0 +1,3 @@
+        .global zed1
+zed1:
+        .quad zed2
diff --git a/test/ELF/Inputs/unresolved-symbols.s b/test/ELF/Inputs/unresolved-symbols.s
new file mode 100644 (file)
index 0000000..b504708
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _shared
+_shared:
+  callq undef@PLT
diff --git a/test/ELF/Inputs/verdef-defaultver.s b/test/ELF/Inputs/verdef-defaultver.s
new file mode 100644 (file)
index 0000000..2e1d1c3
--- /dev/null
@@ -0,0 +1,22 @@
+b@LIBSAMPLE_1.0 = b_1
+b@@LIBSAMPLE_2.0 = b_2
+
+.globl a
+.type  a,@function
+a:
+retq
+
+.globl b_1
+.type  b_1,@function
+b_1:
+retq
+
+.globl b_2
+.type  b_2,@function
+b_2:
+retq
+
+.globl c
+.type  c,@function
+c:
+retq
diff --git a/test/ELF/Inputs/verdef.s b/test/ELF/Inputs/verdef.s
new file mode 100644 (file)
index 0000000..349d5fd
--- /dev/null
@@ -0,0 +1,6 @@
+.text
+.globl _start
+_start:
+ callq a
+ callq b
+ callq c
diff --git a/test/ELF/Inputs/verneed.so.sh b/test/ELF/Inputs/verneed.so.sh
new file mode 100755 (executable)
index 0000000..3423f67
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh -eu
+
+# This script was used to produce the verneed{1,2}.so files.
+
+tmp=$(mktemp -d)
+
+echo "v1 {}; v2 {}; v3 {}; { local: *; };" > $tmp/verneed.script
+
+cat > $tmp/verneed1.s <<eof
+.globl f1_v1
+f1_v1:
+ret
+
+.globl f1_v2
+f1_v2:
+ret
+
+.globl f1_v3
+f1_v3:
+ret
+
+.symver f1_v1, f1@v1
+.symver f1_v2, f1@v2
+.symver f1_v3, f1@@v3
+
+.globl f2_v1
+f2_v1:
+ret
+
+.globl f2_v2
+f2_v2:
+ret
+
+.symver f2_v1, f2@v1
+.symver f2_v2, f2@@v2
+
+.globl f3_v1
+f3_v1:
+ret
+
+.symver f3_v1, f3@v1
+eof
+
+as -o $tmp/verneed1.o $tmp/verneed1.s
+ld.gold -shared -o verneed1.so $tmp/verneed1.o --version-script $tmp/verneed.script -soname verneed1.so.0
+
+cat > $tmp/verneed2.s <<eof
+.globl g1_v1
+g1_v1:
+ret
+
+.symver g1_v1, g1@@v1
+eof
+
+as -o $tmp/verneed2.o $tmp/verneed2.s
+ld.gold -shared -o verneed2.so $tmp/verneed2.o --version-script $tmp/verneed.script -soname verneed2.so.0
+
+rm -rf $tmp
diff --git a/test/ELF/Inputs/verneed1.so b/test/ELF/Inputs/verneed1.so
new file mode 100755 (executable)
index 0000000..744852b
Binary files /dev/null and b/test/ELF/Inputs/verneed1.so differ
diff --git a/test/ELF/Inputs/verneed2.so b/test/ELF/Inputs/verneed2.so
new file mode 100755 (executable)
index 0000000..ba6c05e
Binary files /dev/null and b/test/ELF/Inputs/verneed2.so differ
diff --git a/test/ELF/Inputs/version-script-err.script b/test/ELF/Inputs/version-script-err.script
new file mode 100644 (file)
index 0000000..37de598
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  global:
+   foo
+};
diff --git a/test/ELF/Inputs/version-undef-sym.so b/test/ELF/Inputs/version-undef-sym.so
new file mode 100755 (executable)
index 0000000..abb4399
Binary files /dev/null and b/test/ELF/Inputs/version-undef-sym.so differ
diff --git a/test/ELF/Inputs/version-use.script b/test/ELF/Inputs/version-use.script
new file mode 100644 (file)
index 0000000..5b2721b
--- /dev/null
@@ -0,0 +1,6 @@
+ABC {
+global:
+foo;
+local:
+*;
+};
diff --git a/test/ELF/Inputs/version-use.so b/test/ELF/Inputs/version-use.so
new file mode 100755 (executable)
index 0000000..153544e
Binary files /dev/null and b/test/ELF/Inputs/version-use.so differ
diff --git a/test/ELF/Inputs/visibility.s b/test/ELF/Inputs/visibility.s
new file mode 100644 (file)
index 0000000..fe7cd9a
--- /dev/null
@@ -0,0 +1,14 @@
+.data
+.quad default
+
+.protected protected
+.quad protected
+
+.hidden hidden
+.quad hidden
+
+.internal internal
+.quad internal
+
+.hidden protected_with_hidden
+.quad protected_with_hidden
diff --git a/test/ELF/Inputs/warn-common.s b/test/ELF/Inputs/warn-common.s
new file mode 100644 (file)
index 0000000..fc4509b
--- /dev/null
@@ -0,0 +1,2 @@
+.type arr,@object
+.comm arr,8,4
diff --git a/test/ELF/Inputs/warn-common2.s b/test/ELF/Inputs/warn-common2.s
new file mode 100644 (file)
index 0000000..976c5be
--- /dev/null
@@ -0,0 +1,8 @@
+.type arr,@object
+.data
+.globl arr
+.p2align 2
+arr:
+ .long 1
+ .long 0
+ .size arr, 8
diff --git a/test/ELF/Inputs/whole-archive.s b/test/ELF/Inputs/whole-archive.s
new file mode 100644 (file)
index 0000000..816b24e
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _bar
+_bar:
diff --git a/test/ELF/Inputs/wrap.s b/test/ELF/Inputs/wrap.s
new file mode 100644 (file)
index 0000000..584e270
--- /dev/null
@@ -0,0 +1,4 @@
+.globl foo, __wrap_foo, __real_foo
+foo = 0x11000
+__wrap_foo = 0x11010
+__real_foo = 0x11020
diff --git a/test/ELF/Inputs/x86-64-relax-offset.s b/test/ELF/Inputs/x86-64-relax-offset.s
new file mode 100644 (file)
index 0000000..780d1d0
--- /dev/null
@@ -0,0 +1,7 @@
+.global foo
+.hidden foo
+foo:
+        nop
+        nop
+        nop
+        nop
diff --git a/test/ELF/Inputs/x86-64-reloc-error.s b/test/ELF/Inputs/x86-64-reloc-error.s
new file mode 100644 (file)
index 0000000..bce6f8f
--- /dev/null
@@ -0,0 +1,7 @@
+.global big
+.hidden big
+big = 0x1000000000
+
+.global foo
+.hidden foo
+foo = 0
diff --git a/test/ELF/Inputs/x86-64-tls-gd-got.s b/test/ELF/Inputs/x86-64-tls-gd-got.s
new file mode 100644 (file)
index 0000000..67a021a
--- /dev/null
@@ -0,0 +1,6 @@
+        .globl  bar
+        .section        .tdata,"awT",@progbits
+        .align 4
+        .type   bar, @object
+bar:
+        .long   42
diff --git a/test/ELF/aarch64-abs16.s b/test/ELF/aarch64-abs16.s
new file mode 100644 (file)
index 0000000..e41abc4
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .hword foo + 0xfeff
+  .hword foo - 0x8100
+
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0xfeff
+//        S + A = 0xffff
+// 11002: S = 0x100, A = -0x8100
+//        S + A = 0x8000
+// CHECK-NEXT: 11000 ffff0080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_ABS16 out of range
diff --git a/test/ELF/aarch64-abs32.s b/test/ELF/aarch64-abs32.s
new file mode 100644 (file)
index 0000000..c2460d1
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .word foo + 0xfffffeff
+  .word foo - 0x80000100
+
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0xfffffeff
+//        S + A = 0xffffffff
+// 11004: S = 0x100, A = -0x80000100
+//        S + A = 0x80000000
+// CHECK-NEXT: 11000 ffffffff 00000080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_ABS32 out of range
diff --git a/test/ELF/aarch64-abs64-dyn.s b/test/ELF/aarch64-abs64-dyn.s
new file mode 100644 (file)
index 0000000..2220225
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+
+// Creates a R_AARCH64_ABS64 relocation against foo and bar
+        .globl foo
+foo:
+
+        .global bar
+        .hidden bar
+bar:
+
+        .data
+        .xword foo
+        .xword bar
+
+// RUN: ld.lld -shared -o %t.so %t.o
+// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
+
+// CHECK:      Dynamic Relocations {
+// CHECK-NEXT:   {{.*}} R_AARCH64_RELATIVE - [[BAR_ADDR:.*]]
+// CHECK-NEXT:   {{.*}} R_AARCH64_ABS64 foo 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK:          Name: bar
+// CHECK-NEXT:     Value: [[BAR_ADDR]]
diff --git a/test/ELF/aarch64-call26-error.s b/test/ELF/aarch64-call26-error.s
new file mode 100644 (file)
index 0000000..4b666c6
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %t %tabs -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.text
+.globl _start
+_start:
+    bl big
+
+// CHECK: R_AARCH64_CALL26 out of range
diff --git a/test/ELF/aarch64-condb-reloc.s b/test/ELF/aarch64-condb-reloc.s
new file mode 100644 (file)
index 0000000..630e343
--- /dev/null
@@ -0,0 +1,99 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-condb-reloc.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld -shared %t1 %t2 -o %t3
+# RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+# REQUIRES: aarch64
+
+# 0x11024 - 36 = 0x11000
+# 0x11028 - 24 = 0x11010
+# 0x1102c - 16 = 0x1101c
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: _foo:
+# CHECK-NEXT:    11000: {{.*}} nop
+# CHECK-NEXT:    11004: {{.*}} nop
+# CHECK-NEXT:    11008: {{.*}} nop
+# CHECK-NEXT:    1100c: {{.*}} nop
+# CHECK:      _bar:
+# CHECK-NEXT:    11010: {{.*}} nop
+# CHECK-NEXT:    11014: {{.*}} nop
+# CHECK-NEXT:    11018: {{.*}} nop
+# CHECK:      _dah:
+# CHECK-NEXT:    1101c: {{.*}} nop
+# CHECK-NEXT:    11020: {{.*}} nop
+# CHECK:      _start:
+# CHECK-NEXT:    11024: {{.*}} b.eq #-36
+# CHECK-NEXT:    11028: {{.*}} b.eq #-24
+# CHECK-NEXT:    1102c: {{.*}} b.eq #-16
+
+#DSOREL:      Section {
+#DSOREL:        Index:
+#DSOREL:        Name: .got.plt
+#DSOREL-NEXT:   Type: SHT_PROGBITS
+#DSOREL-NEXT:   Flags [
+#DSOREL-NEXT:     SHF_ALLOC
+#DSOREL-NEXT:     SHF_WRITE
+#DSOREL-NEXT:   ]
+#DSOREL-NEXT:   Address: 0x3000
+#DSOREL-NEXT:   Offset: 0x3000
+#DSOREL-NEXT:   Size: 48
+#DSOREL-NEXT:   Link: 0
+#DSOREL-NEXT:   Info: 0
+#DSOREL-NEXT:   AddressAlignment: 8
+#DSOREL-NEXT:   EntrySize: 0
+#DSOREL-NEXT:  }
+#DSOREL:      Relocations [
+#DSOREL-NEXT:  Section ({{.*}}) .rela.plt {
+#DSOREL-NEXT:    0x3018 R_AARCH64_JUMP_SLOT _foo
+#DSOREL-NEXT:    0x3020 R_AARCH64_JUMP_SLOT _bar
+#DSOREL-NEXT:    0x3028 R_AARCH64_JUMP_SLOT _dah
+#DSOREL-NEXT:  }
+#DSOREL-NEXT:]
+
+#DSO:      Disassembly of section .text:
+#DSO-NEXT: _foo:
+#DSO-NEXT:     1000: {{.*}} nop
+#DSO-NEXT:     1004: {{.*}} nop
+#DSO-NEXT:     1008: {{.*}} nop
+#DSO-NEXT:     100c: {{.*}} nop
+#DSO:      _bar:
+#DSO-NEXT:     1010: {{.*}} nop
+#DSO-NEXT:     1014: {{.*}} nop
+#DSO-NEXT:     1018: {{.*}} nop
+#DSO:      _dah:
+#DSO-NEXT:     101c: {{.*}} nop
+#DSO-NEXT:     1020: {{.*}} nop
+#DSO:      _start:
+#DSO-NEXT:     1024: {{.*}} b.eq #44
+#DSO-NEXT:     1028: {{.*}} b.eq #56
+#DSO-NEXT:     102c: {{.*}} b.eq #68
+#DSO-NEXT: Disassembly of section .plt:
+#DSO-NEXT: .plt:
+#DSO-NEXT:     1030: {{.*}} stp x16, x30, [sp, #-16]!
+#DSO-NEXT:     1034: {{.*}} adrp x16, #8192
+#DSO-NEXT:     1038: {{.*}} ldr x17, [x16, #16]
+#DSO-NEXT:     103c: {{.*}} add x16, x16, #16
+#DSO-NEXT:     1040: {{.*}} br x17
+#DSO-NEXT:     1044: {{.*}} nop
+#DSO-NEXT:     1048: {{.*}} nop
+#DSO-NEXT:     104c: {{.*}} nop
+#DSO-NEXT:     1050: {{.*}} adrp x16, #8192
+#DSO-NEXT:     1054: {{.*}} ldr x17, [x16, #24]
+#DSO-NEXT:     1058: {{.*}} add x16, x16, #24
+#DSO-NEXT:     105c: {{.*}} br x17
+#DSO-NEXT:     1060: {{.*}} adrp x16, #8192
+#DSO-NEXT:     1064: {{.*}} ldr x17, [x16, #32]
+#DSO-NEXT:     1068: {{.*}} add x16, x16, #32
+#DSO-NEXT:     106c: {{.*}} br x17
+#DSO-NEXT:     1070: {{.*}} adrp x16, #8192
+#DSO-NEXT:     1074: {{.*}} ldr x17, [x16, #40]
+#DSO-NEXT:     1078: {{.*}} add x16, x16, #40
+#DSO-NEXT:     107c: {{.*}} br x17
+
+.globl _start
+_start:
+ b.eq _foo
+ b.eq _bar
+ b.eq _dah
diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s
new file mode 100644 (file)
index 0000000..6e0af27
--- /dev/null
@@ -0,0 +1,93 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+// RUN: llvm-objdump -s -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s
+
+.text
+.globl _start
+_start:
+    adr x1, x
+    adrp x2, y
+    add x2, x2, :lo12:y
+.rodata
+    .word z
+
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x13000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x13000
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x13010
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x13014
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: Symbols [
+// CHECK:     Name: x
+// CHECK-NEXT:     Value: 0x13000
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK:     Name: y
+// CHECK-NEXT:     Value: 0x13010
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK:     Name: z
+// CHECK-NEXT:     Value: 0x13014
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK: ]
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// S(x) = 0x13000, A = 0, P = 0x11000
+// S + A - P = 0x2000 = 8208
+// CODE-NEXT:  11000: {{.*}} adr  x1, #8192
+// S(y) = 0x13010, A = 0, P = 0x11004
+// Page(S + A) - Page(P) = 0x13000 - 0x11000 = 0x2000 = 8192
+// CODE-NEXT:  11004: {{.*}} adrp x2, #8192
+// S(y) = 0x13010, A = 0
+// (S + A) & 0xFFF = 0x10 = 16
+// CODE-NEXT:  11008: {{.*}} add  x2, x2, #16
+
+// RODATA: Contents of section .rodata:
+// S(z) = 0x13014
+// RODATA-NEXT:  101c8 14300100
diff --git a/test/ELF/aarch64-copy2.s b/test/ELF/aarch64-copy2.s
new file mode 100644 (file)
index 0000000..af99d8e
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: llvm-mc %p/Inputs/aarch64-copy2.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -t %t | FileCheck %s
+
+        .global _start
+_start:
+        adrp    x8, foo
+        bl bar
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x11030
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/aarch64-data-relocs.s b/test/ELF/aarch64-data-relocs.s
new file mode 100644 (file)
index 0000000..3077083
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: ld.lld %t %t256.o -o %t2
+// RUN: llvm-objdump -s %t2 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+.section .R_AARCH64_ABS64, "ax",@progbits
+  .xword foo + 0x24
+
+// S = 0x100, A = 0x24
+// S + A = 0x124
+// CHECK: Contents of section .R_AARCH64_ABS64:
+// CHECK-NEXT: 11000 24010000 00000000
+
+.section .R_AARCH64_PREL64, "ax",@progbits
+  .xword foo - . + 0x24
+
+// S = 0x100, A = 0x24, P = 0x11008
+// S + A - P = 0xfffffffffffef11c
+// CHECK: Contents of section .R_AARCH64_PREL64:
+// CHECK-NEXT: 11008 1cf1feff ffffffff
diff --git a/test/ELF/aarch64-fpic-abs16.s b/test/ELF/aarch64-fpic-abs16.s
new file mode 100644 (file)
index 0000000..e123f57
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_ABS16 cannot be used against shared object; recompile with -fPIC.
+
+.data
+  .hword foo
diff --git a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..7e0b6b8
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against readonly segment
+
+  add x0, x0, :lo12:dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-adr_prel_lo21.s b/test/ELF/aarch64-fpic-adr_prel_lo21.s
new file mode 100644 (file)
index 0000000..501a724
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_LO21 against readonly segment
+
+  adr x0, dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s
new file mode 100644 (file)
index 0000000..572ecff
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_PG_HI21 against readonly segment
+
+  adrp x0, dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-got.s b/test/ELF/aarch64-fpic-got.s
new file mode 100644 (file)
index 0000000..70b2a7a
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o %t-lib.o
+# RUN: ld.lld -shared %t-lib.o -o %t-lib.so
+# RUN: ld.lld %t-lib.so %t.o -o %t.exe
+# RUN: llvm-readobj -dyn-relocations %t.exe | FileCheck %s
+
+## Checks if got access to dynamic objects is done through a got relative
+## dynamic relocation and not using plt relative (R_AARCH64_JUMP_SLOT).
+# CHECK:       Dynamic Relocations {
+# CHECK-NEXT:    0x{{[0-9A-F]+}}  R_AARCH64_GLOB_DAT bar 0x0
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
+  adrp x0, :got:bar
+  ldr  x0, [x0, :got_lo12:bar]
diff --git a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..85772f1
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against readonly segment
+
+  ldr s4, [x0, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..d9f7b0c
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against readonly segment
+
+  ldr x0, [x0, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..20e1bba
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against readonly segment
+
+  ldrsb x0, [x1, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-prel16.s b/test/ELF/aarch64-fpic-prel16.s
new file mode 100644 (file)
index 0000000..52e2402
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL16 cannot be used against shared object; recompile with -fPIC.
+
+.data
+  .hword foo - .
diff --git a/test/ELF/aarch64-fpic-prel32.s b/test/ELF/aarch64-fpic-prel32.s
new file mode 100644 (file)
index 0000000..72ba58f
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL32 cannot be used against shared object; recompile with -fPIC.
+
+.data
+  .word foo - .
diff --git a/test/ELF/aarch64-fpic-prel64.s b/test/ELF/aarch64-fpic-prel64.s
new file mode 100644 (file)
index 0000000..53a4820
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL64 cannot be used against shared object; recompile with -fPIC.
+
+.data
+  .xword foo - .
diff --git a/test/ELF/aarch64-gnu-ifunc-nosym.s b/test/ELF/aarch64-gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..bb3a0b8
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// Check that no __rela_iplt_end/__rela_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rela_iplt_end
+// CHECK-NOT: __rela_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
diff --git a/test/ELF/aarch64-gnu-ifunc.s b/test/ELF/aarch64-gnu-ifunc.s
new file mode 100644 (file)
index 0000000..351d0ed
--- /dev/null
@@ -0,0 +1,146 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rela.plt
+// CHECK-NEXT:  Type: SHT_RELA
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0x158
+// CHECK-NEXT:  Size: 48
+// CHECK-NEXT:  Link: 5
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 8
+// CHECK-NEXT:  EntrySize: 24
+// CHECK-NEXT: }
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x12018 R_AARCH64_IRELATIVE
+// CHECK-NEXT:     0x12020 R_AARCH64_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      Symbols [
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name:
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: Undefined
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: $x.0
+// CHECK-NEXT:    Value: 0x11000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_end
+// CHECK-NEXT:    Value: 0x10188
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_start
+// CHECK-NEXT:    Value: 0x10158
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x11008
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x11004
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x11000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT: ]
+
+// 344 = 0x158
+// 392 = 0x188
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:  11000: c0 03 5f d6 ret
+// DISASM:      bar:
+// DISASM-NEXT:  11004: c0 03 5f d6 ret
+// DISASM:      _start:
+// DISASM-NEXT:  11008: 0e 00 00 94 bl #56
+// DISASM-NEXT:  1100c: 11 00 00 94 bl #68
+// DISASM-NEXT:  11010: 42 60 05 91 add x2, x2, #344
+// DISASM-NEXT:  11014: 42 20 06 91 add x2, x2, #392
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:  11020: f0 7b bf a9 stp x16, x30, [sp, #-16]!
+// DISASM-NEXT:  11024: 10 00 00 b0 adrp x16, #4096
+// DISASM-NEXT:  11028: 11 0a 40 f9 ldr x17, [x16, #16]
+// DISASM-NEXT:  1102c: 10 42 00 91 add x16, x16, #16
+// DISASM-NEXT:  11030: 20 02 1f d6 br x17
+// DISASM-NEXT:  11034: 1f 20 03 d5 nop
+// DISASM-NEXT:  11038: 1f 20 03 d5 nop
+// DISASM-NEXT:  1103c: 1f 20 03 d5 nop
+// DISASM-NEXT:  11040: 10 00 00 b0 adrp x16, #4096
+// DISASM-NEXT:  11044: 11 0e 40 f9 ldr x17, [x16, #24]
+// DISASM-NEXT:  11048: 10 62 00 91 add x16, x16, #24
+// DISASM-NEXT:  1104c: 20 02 1f d6 br x17
+// DISASM-NEXT:  11050: 10 00 00 b0 adrp x16, #4096
+// DISASM-NEXT:  11054: 11 12 40 f9 ldr x17, [x16, #32]
+// DISASM-NEXT:  11058: 10 82 00 91 add x16, x16, #32
+// DISASM-NEXT:  1105c: 20 02 1f d6 br x17
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ add x2, x2, :lo12:__rela_iplt_start
+ add x2, x2, :lo12:__rela_iplt_end
diff --git a/test/ELF/aarch64-got-relocations.s b/test/ELF/aarch64-got-relocations.s
new file mode 100644 (file)
index 0000000..13ee09a
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-cloudabi %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# If we're addressing a global relatively through the GOT, we still need to
+# emit a relocation for the entry in the GOT itself.
+# CHECK: Relocations [
+# CHECK:   Section (4) .rela.dyn {
+# CHECK:     0x{{[0-9A-F]+}} R_AARCH64_RELATIVE - 0x{{[0-9A-F]+}}
+# CHECK:   }
+# CHECK: ]
+
+       .globl  _start
+       .type   _start,@function
+_start:
+       adrp    x8, :got:i
+       ldr     x8, [x8, :got_lo12:i]
+
+       .type   i,@object
+       .comm   i,4,4
diff --git a/test/ELF/aarch64-got.s b/test/ELF/aarch64-got.s
new file mode 100644 (file)
index 0000000..f56d8a7
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK-NOT: Name: .got
+
+.globl _start
+_start:
+ adrp    x0, :gottprel:foo
+
+       .global foo
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type foo, %object
+ .size foo, 4
+foo:
+ .word 5
diff --git a/test/ELF/aarch64-hi21-error.s b/test/ELF/aarch64-hi21-error.s
new file mode 100644 (file)
index 0000000..9e2b283
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+adrp x0, big
+
+#CHECK: R_AARCH64_ADR_PREL_PG_HI21 out of range
diff --git a/test/ELF/aarch64-jump26-error.s b/test/ELF/aarch64-jump26-error.s
new file mode 100644 (file)
index 0000000..81fbba1
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %t %tabs -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.text
+.globl _start
+_start:
+    b big
+
+// CHECK: R_AARCH64_JUMP26 out of range
diff --git a/test/ELF/aarch64-lo21-error.s b/test/ELF/aarch64-lo21-error.s
new file mode 100644 (file)
index 0000000..055f894
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+adr x0, big
+
+#CHECK: R_AARCH64_ADR_PREL_LO21 out of range
diff --git a/test/ELF/aarch64-prel16.s b/test/ELF/aarch64-prel16.s
new file mode 100644 (file)
index 0000000..083cda9
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .hword foo - . + 0x20eff
+  .hword foo - . + 0x8f02
+
+// Note: If this test fails, it probably happens because of
+//       the change of the address of the .data section.
+//       You may found the correct address in the aarch64_abs16.s test,
+//       if it is already fixed. Then, update addends accordingly.
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0x20eff, P = 0x11000
+//        S + A - P = 0xffff
+// 11002: S = 0x100, A = 0x8f02, P = 0x11002
+//        S + A - P = 0x8000
+// CHECK-NEXT: 11000 ffff0080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_PREL16 out of range
diff --git a/test/ELF/aarch64-prel32.s b/test/ELF/aarch64-prel32.s
new file mode 100644 (file)
index 0000000..c440b98
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .word foo - . + 0x100010eff
+  .word foo - . - 0x7ffef0fc
+
+// Note: If this test fails, it probably happens because of
+//       the change of the address of the .data section.
+//       You may found the correct address in the aarch64_abs32.s test,
+//       if it is already fixed. Then, update addends accordingly.
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0x100010eff, P = 0x11000
+//        S + A - P = 0xffffffff
+// 11004: S = 0x100, A = -0x7ffef0fc, P = 0x11004
+//        S + A - P = 0x80000000
+// CHECK-NEXT: 11000 ffffffff 00000080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_PREL32 out of range
diff --git a/test/ELF/aarch64-relative.s b/test/ELF/aarch64-relative.s
new file mode 100644 (file)
index 0000000..b10dd80
--- /dev/null
@@ -0,0 +1,26 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+  adr     x8, .Lfoo                 // R_AARCH64_ADR_PREL_LO21
+  adrp    x8, .Lfoo                 // R_AARCH64_ADR_PREL_PG_HI21
+  strb    w9, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST8_ABS_LO12_NC
+  ldr     h17, [x19, :lo12:.Lfoo]   // R_AARCH64_LDST16_ABS_LO12_NC
+  ldr     w0, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST32_ABS_LO12_NC
+  ldr     x0, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST64_ABS_LO12_NC
+  ldr     q20, [x19, #:lo12:.Lfoo]  // R_AARCH64_LDST128_ABS_LO12_NC
+  add     x0, x0, :lo12:.Lfoo       // R_AARCH64_ADD_ABS_LO12_NC
+  bl      .Lfoo                     // R_AARCH64_CALL26
+  b       .Lfoo                     // R_AARCH64_JUMP26
+  beq     .Lfoo                     // R_AARCH64_CONDBR19
+.Lbranch:
+  tbz     x1, 7, .Lbranch           // R_AARCH64_TSTBR14
+.data
+.Lfoo:
+
+.rodata
+.long .Lfoo - .
+.xword .Lfoo - .                    // R_AARCH64_PREL64
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/aarch64-relocs.s b/test/ELF/aarch64-relocs.s
new file mode 100644 (file)
index 0000000..9054132
--- /dev/null
@@ -0,0 +1,152 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: aarch64
+
+.section .R_AARCH64_ADR_PREL_LO21,"ax",@progbits
+.globl _start
+_start:
+  adr x1,msg
+msg:  .asciz  "Hello, world\n"
+msgend:
+
+# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_LO21:
+# CHECK: _start:
+# CHECK:        0:       21 00 00 10     adr     x1, #4
+# CHECK: msg:
+# CHECK:        4:
+# #4 is the adr immediate value.
+
+.section .R_AARCH64_ADR_PREL_PG_H121,"ax",@progbits
+  adrp x1,mystr
+mystr:
+  .asciz "blah"
+  .size mystr, 4
+
+# S = 0x11012, A = 0x4, P = 0x11012
+# PAGE(S + A) = 0x11000
+# PAGE(P) = 0x11000
+#
+# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_PG_H121:
+# CHECK-NEXT: $x.2:
+# CHECK-NEXT:   11012:       01 00 00 90     adrp    x1, #0
+
+.section .R_AARCH64_ADD_ABS_LO12_NC,"ax",@progbits
+  add x0, x0, :lo12:.L.str
+.L.str:
+  .asciz "blah"
+  .size mystr, 4
+
+# S = 0x1101b, A = 0x4
+# R = (S + A) & 0xFFF = 0x1f
+# R << 10 = 0x7c00
+#
+# CHECK: Disassembly of section .R_AARCH64_ADD_ABS_LO12_NC:
+# CHECK-NEXT: $x.4:
+# CHECK-NEXT:   1101b:       00 7c 00 91     add     x0, x0, #31
+
+.section .R_AARCH64_LDST64_ABS_LO12_NC,"ax",@progbits
+  ldr x28, [x27, :lo12:foo]
+foo:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x11024, A = 0x4
+# R = ((S + A) & 0xFFF) << 7 = 0x00001400
+# 0x00001400 | 0xf940177c = 0xf940177c
+# CHECK: Disassembly of section .R_AARCH64_LDST64_ABS_LO12_NC:
+# CHECK-NEXT: $x.6:
+# CHECK-NEXT:   11024:       7c 17 40 f9     ldr     x28, [x27, #40]
+
+.section .SUB,"ax",@progbits
+  nop
+sub:
+  nop
+
+# CHECK: Disassembly of section .SUB:
+# CHECK-NEXT: $x.8:
+# CHECK-NEXT:   1102c:       1f 20 03 d5     nop
+# CHECK: sub:
+# CHECK-NEXT:   11030:       1f 20 03 d5     nop
+
+.section .R_AARCH64_CALL26,"ax",@progbits
+call26:
+        bl sub
+
+# S = 0x1102c, A = 0x4, P = 0x11034
+# R = S + A - P = -0x4 = 0xfffffffc
+# (R & 0x0ffffffc) >> 2 = 0x03ffffff
+# 0x94000000 | 0x03ffffff = 0x97ffffff
+# CHECK: Disassembly of section .R_AARCH64_CALL26:
+# CHECK-NEXT: call26:
+# CHECK-NEXT:   11034:       ff ff ff 97     bl     #-4
+
+.section .R_AARCH64_JUMP26,"ax",@progbits
+jump26:
+        b sub
+
+# S = 0x1102c, A = 0x4, P = 0x11038
+# R = S + A - P = -0x8 = 0xfffffff8
+# (R & 0x0ffffffc) >> 2 = 0x03fffffe
+# 0x14000000 | 0x03fffffe = 0x17fffffe
+# CHECK: Disassembly of section .R_AARCH64_JUMP26:
+# CHECK-NEXT: jump26:
+# CHECK-NEXT:   11038:       fe ff ff 17     b      #-8
+
+.section .R_AARCH64_LDST32_ABS_LO12_NC,"ax",@progbits
+ldst32:
+  ldr s4, [x5, :lo12:foo32]
+foo32:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x1103c, A = 0x4
+# R = ((S + A) & 0xFFC) << 8 = 0x00004000
+# 0x00004000 | 0xbd4000a4 = 0xbd4040a4
+# CHECK: Disassembly of section .R_AARCH64_LDST32_ABS_LO12_NC:
+# CHECK-NEXT: ldst32:
+# CHECK-NEXT:   1103c:       a4 40 40 bd     ldr s4, [x5, #64]
+
+.section .R_AARCH64_LDST8_ABS_LO12_NC,"ax",@progbits
+ldst8:
+  ldrsb x11, [x13, :lo12:foo8]
+foo8:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x11044, A = 0x4
+# R = ((S + A) & 0xFFF) << 10 = 0x00012000
+# 0x00012000 | 0x398001ab = 0x398121ab
+# CHECK: Disassembly of section .R_AARCH64_LDST8_ABS_LO12_NC:
+# CHECK-NEXT: ldst8:
+# CHECK-NEXT:   11044:       ab 21 81 39     ldrsb x11, [x13, #72]
+
+.section .R_AARCH64_LDST128_ABS_LO12_NC,"ax",@progbits
+ldst128:
+  ldr q20, [x19, #:lo12:foo128]
+foo128:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x1104c, A = 0x4
+# R = ((S + A) & 0xFF8) << 6 = 0x00001400
+# 0x00001400 | 0x3dc00274 = 0x3dc01674
+# CHECK: Disassembly of section .R_AARCH64_LDST128_ABS_LO12_NC:
+# CHECK: ldst128:
+# CHECK:   1104c:       74 16 c0 3d     ldr     q20, [x19, #80]
+#foo128:
+#   11050:       66 6f 6f 00     .word
+
+.section .R_AARCH64_LDST16_ABS_LO12_NC,"ax",@progbits
+ldst16:
+  ldr h17, [x19, :lo12:foo16]
+foo16:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x11054, A = 0x4
+# R = ((S + A) & 0x0FFC) << 9 = 0xb000
+# 0xb000 | 0x7d400271 = 0x7d40b271
+# CHECK: Disassembly of section .R_AARCH64_LDST16_ABS_LO12_NC:
+# CHECK-NEXT: ldst16:
+# CHECK-NEXT:   11054:       71 b2 40 7d     ldr     h17, [x19, #88]
diff --git a/test/ELF/aarch64-tls-gdie.s b/test/ELF/aarch64-tls-gdie.s
new file mode 100644 (file)
index 0000000..709cc53
--- /dev/null
@@ -0,0 +1,34 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: llvm-mc %p/Inputs/aarch64-tls-gdie.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s %t | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+        .globl  _start
+_start:
+        nop
+        adrp    x0, :tlsdesc:a
+        ldr     x1, [x0, :tlsdesc_lo12:a]
+        add     x0, x0, :tlsdesc_lo12:a
+        .tlsdesccall a
+        blr     x1
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x120B0
+
+// page(0x120B0) - page(0x11004) = 4096
+// 0x0B0 = 176
+
+// CHECK:      _start:
+// CHECK-NEXT: 11000: {{.*}} nop
+// CHECK-NEXT: 11004: {{.*}} adrp       x0, #4096
+// CHECK-NEXT: 11008: {{.*}} ldr        x0, [x0, #176]
+// CHECK-NEXT: 1100c: {{.*}} nop
+// CHECK-NEXT: 11010: {{.*}} nop
diff --git a/test/ELF/aarch64-tls-gdle.s b/test/ELF/aarch64-tls-gdle.s
new file mode 100644 (file)
index 0000000..dc0c02a
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o
+# RUN: ld.lld %tmain.o %ttlsie.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#Local-Dynamic to Initial-Exec relax creates no
+#RELOC:      Relocations [
+#RELOC-NEXT: ]
+
+# TCB size = 0x16 and foo is first element from TLS register.
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK:  11000:       00 00 a0 d2     movz    x0, #0, lsl #16
+# CHECK:  11004:       00 02 80 f2     movk    x0, #16
+# CHECK:  11008:       1f 20 03 d5     nop
+# CHECK:  1100c:       1f 20 03 d5     nop
+
+.globl _start
+_start:
+ adrp    x0, :tlsdesc:foo
+ ldr     x1, [x0, :tlsdesc_lo12:foo]
+ add     x0, x0, :tlsdesc_lo12:foo
+ .tlsdesccall foo
+ blr     x1
diff --git a/test/ELF/aarch64-tls-ie.s b/test/ELF/aarch64-tls-ie.s
new file mode 100644 (file)
index 0000000..0cec402
--- /dev/null
@@ -0,0 +1,50 @@
+// REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tls-ie.s -o %tdso.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o
+# RUN: ld.lld -shared %tdso.o -o %tdso.so
+# RUN: ld.lld %tmain.o %tdso.so -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#RELOC:      Section {
+#RELOC:        Index:
+#RELOC:        Name: .got
+#RELOC-NEXT:   Type: SHT_PROGBITS
+#RELOC-NEXT:   Flags [
+#RELOC-NEXT:     SHF_ALLOC
+#RELOC-NEXT:     SHF_WRITE
+#RELOC-NEXT:   ]
+#RELOC-NEXT:   Address: 0x120B0
+#RELOC-NEXT:   Offset: 0x20B0
+#RELOC-NEXT:   Size: 16
+#RELOC-NEXT:   Link: 0
+#RELOC-NEXT:   Info: 0
+#RELOC-NEXT:   AddressAlignment: 8
+#RELOC-NEXT:   EntrySize: 0
+#RELOC-NEXT: }
+#RELOC:      Relocations [
+#RELOC-NEXT:  Section ({{.*}}) .rela.dyn {
+#RELOC-NEXT:    0x120B8 R_AARCH64_TLS_TPREL64 bar 0x0
+#RELOC-NEXT:    0x120B0 R_AARCH64_TLS_TPREL64 foo 0x0
+#RELOC-NEXT:  }
+#RELOC-NEXT:]
+
+# Page(0x120B0) - Page(0x11000) = 0x1000 = 4096
+# 0x120B0 & 0xff8 = 0xB0 = 176
+# Page(0x120B8) - Page(0x11000) = 0x1000 = 4096
+# 0x120B8 & 0xff8 = 0xB8 = 184
+#CHECK: Disassembly of section .text:
+#CHECK: _start:
+#CHECK:  11000: 00 00 00 b0 adrp x0, #4096
+#CHECK:  11004: 00 58 40 f9 ldr  x0, [x0, #176]
+#CHECK:  11008: 00 00 00 b0 adrp x0, #4096
+#CHECK:  1100c: 00 5c 40 f9 ldr  x0, [x0, #184]
+
+.globl _start
+_start:
+ adrp x0, :gottprel:foo
+ ldr x0, [x0, #:gottprel_lo12:foo]
+
+ adrp x0, :gottprel:bar
+ ldr x0, [x0, #:gottprel_lo12:bar]
diff --git a/test/ELF/aarch64-tls-iele.s b/test/ELF/aarch64-tls-iele.s
new file mode 100644 (file)
index 0000000..91efc09
--- /dev/null
@@ -0,0 +1,33 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o
+# RUN: ld.lld %tmain.o %ttlsie.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+# Initial-Exec to Local-Exec relax creates no dynamic relocations.
+# RELOC:      Relocations [
+# RELOC-NEXT: ]
+
+# TCB size = 0x16 and foo is first element from TLS register.
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK-NEXT: 11000:  00 00 a0 d2   movz   x0, #0, lsl #16
+# CHECK-NEXT: 11004:  80 02 80 f2   movk   x0, #20
+# CHECK-NEXT: 11008:  00 00 a0 d2   movz   x0, #0, lsl #16
+# CHECK-NEXT: 1100c:  00 02 80 f2   movk   x0, #16
+
+.section .tdata
+.align 2
+.type foo_local, %object
+.size foo_local, 4
+foo_local:
+.word 5
+.text
+
+.globl _start
+_start:
+ adrp    x0, :gottprel:foo
+ ldr     x0, [x0, :gottprel_lo12:foo]
+ adrp    x0, :gottprel:foo_local
+ ldr     x0, [x0, :gottprel_lo12:foo_local]
diff --git a/test/ELF/aarch64-tls-le.s b/test/ELF/aarch64-tls-le.s
new file mode 100644 (file)
index 0000000..22bd0ef
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o
+# RUN: ld.lld %tmain.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#Local-Dynamic to Initial-Exec relax creates no
+#RELOC:      Relocations [
+#RELOC-NEXT: ]
+
+.globl _start
+_start:
+ mrs x0, TPIDR_EL0
+ add x0, x0, :tprel_hi12:v1
+ add x0, x0, :tprel_lo12_nc:v1
+
+# TCB size = 0x16 and foo is first element from TLS register.
+#CHECK: Disassembly of section .text:
+#CHECK: _start:
+#CHECK:  11000: 40 d0 3b d5     mrs     x0, TPIDR_EL0
+#CHECK:  11004: 00 00 00 91     add     x0, x0, #0
+#CHECK:  11008: 00 40 00 91     add     x0, x0, #16
+
+.type   v1,@object
+.section        .tbss,"awT",@nobits
+.globl  v1
+.p2align 2
+v1:
+.word  0
+.size  v1, 4
+
diff --git a/test/ELF/aarch64-tls-pie.s b/test/ELF/aarch64-tls-pie.s
new file mode 100644 (file)
index 0000000..466045d
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-cloudabi %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# Similar to bug 27174: R_AARCH64_TLSLE_*TPREL* relocations should be
+# eliminated when building a PIE executable, as the static TLS layout is
+# fixed.
+#
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+       .globl  _start
+_start:
+       # Accessing the variable directly.
+       add     x11, x8, :tprel_hi12:i
+       add     x11, x11, :tprel_lo12_nc:i
+
+       # Accessing the variable through the GOT.
+       adrp    x10, :gottprel:i
+       mrs     x8, TPIDR_EL0
+       ldr     x10, [x10, :gottprel_lo12:i]
+
+       .section        .tbss.i,"awT",@nobits
+       .globl  i
+i:
+       .word   0
+       .size   i, 4
diff --git a/test/ELF/aarch64-tls-static.s b/test/ELF/aarch64-tls-static.s
new file mode 100644 (file)
index 0000000..c8508ee
--- /dev/null
@@ -0,0 +1,37 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -triple aarch64-pc-linux -filetype=obj
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+foo:
+        adrp    x0, :tlsdesc:bar
+        ldr     x1, [x0, :tlsdesc_lo12:bar]
+        add     x0, x0, :tlsdesc_lo12:bar
+        .tlsdesccall bar
+        blr     x1
+
+
+        .section        .tdata,"awT",@progbits
+bar:
+        .word   42
+
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2098
+// SEC-NEXT: Offset: 0x2098
+// SEC-NEXT: Size: 16
+
+// page(0x2098) - page(0x1000) = 4096
+// 0x98 = 152
+
+// CHECK:      foo:
+// CHECK-NEXT: 1000: {{.*}} adrp x0, #4096
+// CHECK-NEXT: 1004: {{.*}} ldr  x1, [x0, #152]
+// CHECK-NEXT: 1008: {{.*}} add  x0, x0, #152
+// CHECK-NEXT: 100c: {{.*}} blr  x1
diff --git a/test/ELF/aarch64-tlsdesc.s b/test/ELF/aarch64-tlsdesc.s
new file mode 100644 (file)
index 0000000..f8c73af
--- /dev/null
@@ -0,0 +1,24 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+// RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=REL %s
+
+        adrp    x0, :tlsdesc:a
+        ldr     x1, [x0, :tlsdesc_lo12:a]
+        add     x0, x0, :tlsdesc_lo12:a
+        .tlsdesccall a
+        blr     x1
+
+// CHECK:      1000: {{.*}}  adrp    x0, #4096
+// CHECK-NEXT: 1004: {{.*}}  ldr     x1, [x0, #144]
+// CHECK-NEXT: 1008: {{.*}}  add     x0, x0, #144
+// CHECK-NEXT: 100c: {{.*}}  blr     x1
+
+// 0x1000 + 4096 + 144 = 0x2090
+
+// REL:      Relocations [
+// REL-NEXT:   Section (4) .rela.dyn {
+// REL-NEXT:     0x2090 R_AARCH64_TLSDESC a 0x0
+// REL-NEXT:   }
+// REL-NEXT: ]
diff --git a/test/ELF/aarch64-tstbr14-reloc.s b/test/ELF/aarch64-tstbr14-reloc.s
new file mode 100644 (file)
index 0000000..1dc1bdf
--- /dev/null
@@ -0,0 +1,96 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tstbr14-reloc.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld -shared %t1 %t2 -o %t3
+# RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+# REQUIRES: aarch64
+
+# 0x1101c - 28 = 0x11000
+# 0x11020 - 16 = 0x11010
+# 0x11024 - 36 = 0x11000
+# 0x11028 - 24 = 0x11010
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: _foo:
+# CHECK-NEXT:  11000: {{.*}} nop
+# CHECK-NEXT:  11004: {{.*}} nop
+# CHECK-NEXT:  11008: {{.*}} nop
+# CHECK-NEXT:  1100c: {{.*}} nop
+# CHECK:      _bar:
+# CHECK-NEXT:  11010: {{.*}} nop
+# CHECK-NEXT:  11014: {{.*}} nop
+# CHECK-NEXT:  11018: {{.*}} nop
+# CHECK:      _start:
+# CHECK-NEXT:  1101c: {{.*}} tbnz w3, #15, #-28
+# CHECK-NEXT:  11020: {{.*}} tbnz w3, #15, #-16
+# CHECK-NEXT:  11024: {{.*}} tbz x6, #45, #-36
+# CHECK-NEXT:  11028: {{.*}} tbz x6, #45, #-24
+
+#DSOREL:      Section {
+#DSOREL:        Index:
+#DSOREL:        Name: .got.plt
+#DSOREL-NEXT:   Type: SHT_PROGBITS
+#DSOREL-NEXT:   Flags [
+#DSOREL-NEXT:     SHF_ALLOC
+#DSOREL-NEXT:     SHF_WRITE
+#DSOREL-NEXT:   ]
+#DSOREL-NEXT:   Address: 0x3000
+#DSOREL-NEXT:   Offset: 0x3000
+#DSOREL-NEXT:   Size: 40
+#DSOREL-NEXT:   Link: 0
+#DSOREL-NEXT:   Info: 0
+#DSOREL-NEXT:   AddressAlignment: 8
+#DSOREL-NEXT:   EntrySize: 0
+#DSOREL-NEXT:  }
+#DSOREL:      Relocations [
+#DSOREL-NEXT:  Section ({{.*}}) .rela.plt {
+#DSOREL-NEXT:    0x3018 R_AARCH64_JUMP_SLOT _foo
+#DSOREL-NEXT:    0x3020 R_AARCH64_JUMP_SLOT _bar
+#DSOREL-NEXT:  }
+#DSOREL-NEXT:]
+
+#DSO:      Disassembly of section .text:
+#DSO-NEXT: _foo:
+#DSO-NEXT:  1000: {{.*}} nop
+#DSO-NEXT:  1004: {{.*}} nop
+#DSO-NEXT:  1008: {{.*}} nop
+#DSO-NEXT:  100c: {{.*}} nop
+#DSO:      _bar:
+#DSO-NEXT:  1010: {{.*}} nop
+#DSO-NEXT:  1014: {{.*}} nop
+#DSO-NEXT:  1018: {{.*}} nop
+#DSO:      _start:
+# 0x101c + 52 = 0x1050 = PLT[1]
+# 0x1020 + 64 = 0x1060 = PLT[2]
+# 0x1024 + 44 = 0x1050 = PLT[1]
+# 0x1028 + 56 = 0x1060 = PLT[2]
+#DSO-NEXT:  101c: {{.*}} tbnz w3, #15, #52
+#DSO-NEXT:  1020: {{.*}} tbnz w3, #15, #64
+#DSO-NEXT:  1024: {{.*}} tbz x6, #45, #44
+#DSO-NEXT:  1028: {{.*}} tbz x6, #45, #56
+#DSO-NEXT: Disassembly of section .plt:
+#DSO-NEXT: .plt:
+#DSO-NEXT:  1030: {{.*}} stp x16, x30, [sp, #-16]!
+#DSO-NEXT:  1034: {{.*}} adrp x16, #8192
+#DSO-NEXT:  1038: {{.*}} ldr x17, [x16, #16]
+#DSO-NEXT:  103c: {{.*}} add x16, x16, #16
+#DSO-NEXT:  1040: {{.*}} br x17
+#DSO-NEXT:  1044: {{.*}} nop
+#DSO-NEXT:  1048: {{.*}} nop
+#DSO-NEXT:  104c: {{.*}} nop
+#DSO-NEXT:  1050: {{.*}} adrp x16, #8192
+#DSO-NEXT:  1054: {{.*}} ldr x17, [x16, #24]
+#DSO-NEXT:  1058: {{.*}} add x16, x16, #24
+#DSO-NEXT:  105c: {{.*}} br x17
+#DSO-NEXT:  1060: {{.*}} adrp x16, #8192
+#DSO-NEXT:  1064: {{.*}} ldr x17, [x16, #32]
+#DSO-NEXT:  1068: {{.*}} add x16, x16, #32
+#DSO-NEXT:  106c: {{.*}} br x17
+
+.globl _start
+_start:
+ tbnz w3, #15, _foo
+ tbnz w3, #15, _bar
+ tbz x6, #45, _foo
+ tbz x6, #45, _bar
diff --git a/test/ELF/abs-hidden.s b/test/ELF/abs-hidden.s
new file mode 100644 (file)
index 0000000..b93c2c6
--- /dev/null
@@ -0,0 +1,46 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/abs-hidden.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+        .quad foo
+        .long foo@gotpcrel
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 12
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 00000000 58100000
+//                                       0x2060 - (0x1000 + 8) = 1058
+// CHECK-NEXT: )
+
+// CHECK:      Name: .got (38)
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2060
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/allow-multiple-definition.s b/test/ELF/allow-multiple-definition.s
new file mode 100644 (file)
index 0000000..89ea8c8
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/allow-multiple-definition.s -o %t2
+# RUN: not ld.lld %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition %t2 %t1 -o %t4
+# RUN: llvm-objdump -d %t3 | FileCheck %s
+# RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s
+
+# inputs contain different constants for instuction movl.
+# Tests below checks that order of files in command line
+# affects on what symbol will be used.
+# If flag allow-multiple-definition is enabled the first
+# meet symbol should be used.
+
+# CHECK: _bar:
+# CHECK-NEXT: 11000:   b8 01 00 00 00   movl   $1, %eax
+
+# REVERT: _bar:
+# REVERT-NEXT: 11000:   b8 02 00 00 00   movl   $2, %eax
+
+.globl _bar
+.type _bar, @function
+_bar:
+  mov $1, %eax
+
+.globl _start
+_start:
diff --git a/test/ELF/allow-shlib-undefined.s b/test/ELF/allow-shlib-undefined.s
new file mode 100644 (file)
index 0000000..2d068b0
--- /dev/null
@@ -0,0 +1,25 @@
+# --allow-shlib-undefined and --no-allow-shlib-undefined are fully
+# ignored in linker implementation.
+# --allow-shlib-undefined is set by default
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/allow-shlib-undefined.s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+
+# Executable: should link with DSO containing undefined symbols in any case.
+# RUN: ld.lld %t1 %t.so -o %t2
+# RUN: ld.lld --no-allow-shlib-undefined %t1 %t.so -o %t2
+# RUN: ld.lld --allow-shlib-undefined %t1 %t.so -o %t2
+
+# DSO with undefines:
+# should link with or without any of these options.
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld -shared --allow-shlib-undefined %t -o %t.so
+# RUN: ld.lld -shared --no-allow-shlib-undefined %t -o %t.so
+
+# Executable still should not link when have undefines inside.
+# RUN: not ld.lld %t -o %t.so
+
+.globl _start
+_start:
+  callq _shared@PLT
diff --git a/test/ELF/amdgpu-entry.s b/test/ELF/amdgpu-entry.s
new file mode 100644 (file)
index 0000000..2a47b17
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: not ld.lld -e kernel0 %t.o -o %t
+
+# REQUIRES: amdgpu
+
+.hsa_code_object_version 1,0
+.hsa_code_object_isa 7,0,0,"AMD","AMDGPU"
+
+.hsatext
+.globl kernel0
+.align 256
+.amdgpu_hsa_kernel kernel0
+kernel0:
+  s_endpgm
+.Lfunc_end0:
+  .size kernel0, .Lfunc_end0-kernel0
diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s
new file mode 100644 (file)
index 0000000..7f46b98
--- /dev/null
@@ -0,0 +1,138 @@
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: lld -flavor gnu %t.o -o %t
+# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
+
+# REQUIRES: amdgpu
+
+       .amdgpu_hsa_module_global module_global_program
+       .size   module_global_program, 4
+       .hsadata_global_program
+module_global_program:
+       .long   0                       ; 0x0
+
+       .amdgpu_hsa_program_global program_global_program
+       .size   program_global_program, 4
+       .hsadata_global_program
+program_global_program:
+       .long   0                       ; 0x0
+
+       .amdgpu_hsa_module_global module_global_agent
+       .size   module_global_agent, 4
+       .hsadata_global_agent
+module_global_agent:
+       .long   0                       ; 0x0
+
+       .amdgpu_hsa_program_global program_global_agent
+       .size   program_global_agent, 4
+       .hsadata_global_agent
+program_global_agent:
+       .long   0                       ; 0x0
+
+       .amdgpu_hsa_module_global module_global_readonly
+       .size   module_global_readonly, 4
+       .hsatext
+module_global_readonly:
+       .long   0                       ; 0x0
+
+       .amdgpu_hsa_program_global program_global_readonly
+       .size   program_global_readonly, 4
+       .hsatext
+program_global_readonly:
+       .long   0                       ; 0x0
+
+# CHECK: Section {
+# CHECK: Name: .hsadata_global_program
+# CHECK: Type: SHT_PROGBITS (0x1)
+# CHECK: Flags [ (0x100003)
+# CHECK: SHF_ALLOC (0x2)
+# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000)
+# CHECK: SHF_WRITE (0x1)
+# CHECK: ]
+# CHECK: Address: [[HSADATA_GLOBAL_PROGRAM_ADDR:[0-9xa-f]+]]
+# CHECK: }
+
+# CHECK: Section {
+# CHECK: Name: .hsadata_global_agent
+# CHECK: Type: SHT_PROGBITS (0x1)
+# CHECK: Flags [ (0x900003)
+# CHECK: SHF_ALLOC (0x2)
+# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000)
+# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000)
+# CHECK: SHF_WRITE (0x1)
+# CHECK: ]
+# CHECK: }
+
+# CHECK: Section {
+# CHECK: Name: .hsatext
+# CHECK: Type: SHT_PROGBITS
+# CHECK: Flags [ (0xC00007)
+# CHECK: SHF_ALLOC (0x2)
+# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000)
+# CHECK: SHF_AMDGPU_HSA_CODE (0x400000)
+# CHECK: SHF_EXECINSTR (0x4)
+# CHECK: SHF_WRITE (0x1)
+# CHECK: ]
+# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]]
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: module_global_agent
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Local
+# CHECK: Section: .hsadata_global_agent
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: module_global_program
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Local
+# CHECK: Section: .hsadata_global_program
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: module_global_readonly
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Local
+# CHECK: Type: Object
+# CHECK: Section: .hsatext
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: program_global_agent
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Global
+# CHECK: Type: Object
+# CHECK: Section: .hsadata_global_agent
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: program_global_program
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Global
+# CHECK: Type: Object
+# CHECK: Section: .hsadata_global_program
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: program_global_readonly
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Global
+# CHECK: Type: Object
+# CHECK: Section: .hsatext
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s
new file mode 100644 (file)
index 0000000..62a8cb7
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
+
+# REQUIRES: amdgpu
+
+.hsa_code_object_version 1,0
+.hsa_code_object_isa 7,0,0,"AMD","AMDGPU"
+
+.hsatext
+.globl kernel0
+.align 256
+.amdgpu_hsa_kernel kernel0
+kernel0:
+  s_endpgm
+.Lfunc_end0:
+  .size kernel0, .Lfunc_end0-kernel0
+
+.globl kernel1
+.align 256
+.amdgpu_hsa_kernel kernel1
+kernel1:
+  s_endpgm
+  s_endpgm
+.Lfunc_end1:
+  .size kernel1, .Lfunc_end1-kernel1
+
+
+# CHECK: Section {
+# CHECK: Name: .hsatext
+# CHECK: Type: SHT_PROGBITS
+# CHECK: Flags [ (0xC00007)
+# CHECK: SHF_ALLOC (0x2)
+# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000)
+# CHECK: SHF_AMDGPU_HSA_CODE (0x400000)
+# CHECK: SHF_EXECINSTR (0x4)
+# CHECK: SHF_WRITE (0x1)
+# CHECK: ]
+# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]]
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: kernel0
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Global
+# CHECK: Type: AMDGPU_HSA_KERNEL
+# CHECK: Section: .hsatext
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: kernel1
+# CHECK: Value:
+# CHECK: Size: 8
+# CHECK: Binding: Global
+# CHECK: Type: AMDGPU_HSA_KERNEL
+# CHECK: Section: .hsatext
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
diff --git a/test/ELF/amdgpu-relocs.s b/test/ELF/amdgpu-relocs.s
new file mode 100644 (file)
index 0000000..58c9582
--- /dev/null
@@ -0,0 +1,33 @@
+# RUN: llvm-mc -filetype=obj -triple=amdgcn--amdhsa -mcpu=fiji %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+# REQUIRES: amdgpu
+
+  .text
+
+kernel0:
+  s_mov_b32 s0, common_var@GOTPCREL+4
+  s_mov_b32 s0, extern_var@GOTPCREL+4
+  s_mov_b32 s0, local_var+4
+  s_mov_b32 s0, global_var@GOTPCREL+4
+  s_mov_b32 s0, weak_var@GOTPCREL+4
+  s_mov_b32 s0, weakref_var@GOTPCREL+4
+  s_endpgm
+
+  .comm   common_var,1024,4
+  .globl  global_var
+  .local  local_var
+  .weak   weak_var
+  .weakref weakref_var, weakref_alias_var
+
+# The relocation for local_var should be resolved by the linker.
+# CHECK: Relocations [
+# CHECK: .rela.dyn {
+# CHECK-NEXT: R_AMDGPU_ABS64 common_var 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 extern_var 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 global_var 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weak_var 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
diff --git a/test/ELF/archive.s b/test/ELF/archive.s
new file mode 100644 (file)
index 0000000..59c96a5
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive3.s -o %t4
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive4.s -o %t5
+# RUN: llvm-ar rcs %tar %t2 %t3 %t4
+# RUN: ld.lld %t %tar %t5 -o %tout
+# RUN: llvm-nm %tout | FileCheck %s
+# RUN: rm -f %tarthin
+# RUN: llvm-ar --format=gnu rcsT %tarthin %t2 %t3 %t4
+# RUN: ld.lld %t %tarthin %t5 -o %tout
+# RUN: llvm-nm %tout | FileCheck %s
+# REQUIRES: x86
+
+# Nothing here. Just needed for the linker to create a undefined _start symbol.
+
+.quad end
+
+.weak foo
+.quad foo
+
+.weak bar
+.quad bar
+
+
+# CHECK:      T _start
+# CHECK-NEXT: T bar
+# CHECK-NEXT: T end
+# CHECK-NEXT: w foo
+
+
+# Test that the hitting the first object file after having a lazy symbol for
+# _start is handled correctly.
+# RUN: ld.lld %tar %t -o %tout
+# RUN: llvm-nm %tout | FileCheck --check-prefix=AR-FIRST %s
+
+# AR-FIRST:      T _start
+# AR-FIRST-NEXT: w bar
+# AR-FIRST-NEXT: T end
+# AR-FIRST-NEXT: w foo
diff --git a/test/ELF/arm-abs32-dyn.s b/test/ELF/arm-abs32-dyn.s
new file mode 100644 (file)
index 0000000..68183fe
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux %s -o %t.o
+
+// Creates a R_ARM_ABS32 relocation against foo and bar, bar has hidden
+// visibility so we expect a R_ARM_RELATIVE
+ .syntax unified
+ .globl foo
+foo:
+ .globl bar
+ .hidden bar
+bar:
+
+ .data
+ .word foo
+ .word bar
+
+// RUN: ld.lld -shared -o %t.so %t.o
+// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
+
+// CHECK:      Dynamic Relocations {
+// CHECK-NEXT:   0x2004 R_ARM_RELATIVE
+// CHECK-NEXT:   0x2000 R_ARM_ABS32 foo 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK:          Name: bar
+// CHECK-NEXT:     Value: 0x1000
+
+// CHECK:        Symbol {
+// CHECK:          Name: foo
+// CHECK-NEXT:     Value: 0x1000
diff --git a/test/ELF/arm-attributes-remove.s b/test/ELF/arm-attributes-remove.s
new file mode 100644 (file)
index 0000000..010f366
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: ld.lld %t.o -shared -o %t2
+// RUN: llvm-readobj -s %t2 | FileCheck %s
+// RUN: ld.lld %t.o -r -o %t3
+// RUN: llvm-readobj -s %t3 | FileCheck %s
+
+// The .ARM.attributes section should be removed from executables and
+// shared objects.
+
+// At present we remove it from the -r object output as well which isn't ideal.
+// Unfortunately combining per-object attributes cannot be safely done by just
+// concatentation of input sections.
+
+// CHECK-NOT: Name: .ARM.attributes
+// REQUIRES: arm
+ .text
+ .syntax unified
+ .eabi_attribute        67, "2.09"      @ Tag_conformance
+ .cpu    cortex-a8
+ .eabi_attribute 6, 10   @ Tag_CPU_arch
+ .eabi_attribute 7, 65   @ Tag_CPU_arch_profile
+ .eabi_attribute 8, 1    @ Tag_ARM_ISA_use
+ .eabi_attribute 9, 2    @ Tag_THUMB_ISA_use
+ .fpu    neon
+ .eabi_attribute 15, 1   @ Tag_ABI_PCS_RW_data
+ .eabi_attribute 16, 1   @ Tag_ABI_PCS_RO_data
+ .eabi_attribute 17, 2   @ Tag_ABI_PCS_GOT_use
+ .eabi_attribute 20, 1   @ Tag_ABI_FP_denormal
+ .eabi_attribute 21, 1   @ Tag_ABI_FP_exceptions
+ .eabi_attribute 23, 3   @ Tag_ABI_FP_number_model
+ .eabi_attribute 34, 1   @ Tag_CPU_unaligned_access
+ .eabi_attribute 24, 1   @ Tag_ABI_align_needed
+ .eabi_attribute 25, 1   @ Tag_ABI_align_preserved
+ .eabi_attribute 38, 1   @ Tag_ABI_FP_16bit_format
+ .eabi_attribute 18, 4   @ Tag_ABI_PCS_wchar_t
+ .eabi_attribute 26, 2   @ Tag_ABI_enum_size
+ .eabi_attribute 14, 0   @ Tag_ABI_PCS_R9_use
+ .eabi_attribute 68, 1   @ Tag_Virtualization_use
+ .globl  _start
+ .p2align        2
+ .type   _start,%function
+_start:
+ bx lr
diff --git a/test/ELF/arm-blx.s b/test/ELF/arm-blx.s
new file mode 100644 (file)
index 0000000..cccb132
--- /dev/null
@@ -0,0 +1,113 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .callee2 : { *(.callee_arm_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee3 : { *(.callee_high) } \
+// RUN:          .callee4 : { *(.callee_arm_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
+// REQUIRES: arm
+
+// Test BLX instruction is chosen for ARM BL/BLX instruction and Thumb callee
+// Using two callees to ensure at least one has 2-byte alignment.
+ .syntax unified
+ .thumb
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+ .type callee_low2, %function
+callee_low2:
+ bx lr
+
+ .section .callee_arm_low, "ax",%progbits
+ .arm
+ .balign 0x100
+ .type callee_arm_low,%function
+ .align 2
+callee_arm_low:
+  bx lr
+
+.section .text, "ax",%progbits
+ .arm
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ blx callee_low
+ bl  callee_low2
+ blx callee_low2
+ bl  callee_high
+ blx callee_high
+ bl  callee_high2
+ blx callee_high2
+ bl  blx_far
+ blx blx_far2
+// blx to ARM instruction should be written as a BL
+ bl  callee_arm_low
+ blx callee_arm_low
+ bl  callee_arm_high
+ blx callee_arm_high
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_high,%function
+callee_high:
+ bx lr
+ .type callee_high2,%function
+callee_high2:
+ bx lr
+
+ .section .callee_arm_high, "ax",%progbits
+ .arm
+ .balign 0x100
+ .type callee_arm_high,%function
+callee_arm_high:
+  bx lr
+
+// CHECK-THUMB: Disassembly of section .callee1:
+// CHECK-THUMB-NEXT: callee_low:
+// CHECK-THUMB-NEXT:    b4:       70 47   bx      lr
+// CHECK-THUMB: callee_low2:
+// CHECK-THUMB-NEXT:    b6:       70 47   bx      lr
+
+// CHECK-ARM: Disassembly of section .callee2:
+// CHECK-ARM-NEXT: callee_arm_low:
+// CHECK-ARM-NEXT:    100:        1e ff 2f e1     bx      lr
+
+// CHECK-ARM: Disassembly of section .caller:
+// CHECK-ARM-NEXT: _start:
+// CHECK-ARM-NEXT:   10000:       2b c0 ff fa     blx     #-65364 <callee_low>
+// CHECK-ARM-NEXT:   10004:       2a c0 ff fa     blx     #-65368 <callee_low>
+// CHECK-ARM-NEXT:   10008:       29 c0 ff fb     blx     #-65370 <callee_low2>
+// CHECK-ARM-NEXT:   1000c:       28 c0 ff fb     blx     #-65374 <callee_low2>
+// CHECK-ARM-NEXT:   10010:       3a 00 00 fa     blx     #232 <callee_high>
+// CHECK-ARM-NEXT:   10014:       39 00 00 fa     blx     #228 <callee_high>
+// CHECK-ARM-NEXT:   10018:       38 00 00 fb     blx     #226 <callee_high2>
+// CHECK-ARM-NEXT:   1001c:       37 00 00 fb     blx     #222 <callee_high2>
+// 10020 + 1FFFFFC + 8 = 0x2010024 = blx_far
+// CHECK-ARM-NEXT:   10020:       ff ff 7f fa     blx     #33554428
+// 10024 + 1FFFFFC + 8 = 0x2010028 = blx_far2
+// CHECK-ARM-NEXT:   10024:       ff ff 7f fa     blx     #33554428
+// CHECK-ARM-NEXT:   10028:       34 c0 ff eb     bl      #-65328 <callee_arm_low>
+// CHECK-ARM-NEXT:   1002c:       33 c0 ff eb     bl      #-65332 <callee_arm_low>
+// CHECK-ARM-NEXT:   10030:       72 00 00 eb     bl      #456 <callee_arm_high>
+// CHECK-ARM-NEXT:   10034:       71 00 00 eb     bl      #452 <callee_arm_high>
+// CHECK-ARM-NEXT:   10038:       1e ff 2f e1     bx      lr
+
+// CHECK-THUMB: Disassembly of section .callee3:
+// CHECK-THUMB: callee_high:
+// CHECK-THUMB-NEXT:    10100:       70 47   bx      lr
+// CHECK-THUMB: callee_high2:
+// CHECK-THUMB-NEXT:    10102:       70 47   bx      lr
+
+// CHECK-ARM: Disassembly of section .callee4:
+// CHECK-NEXT-ARM: callee_arm_high:
+// CHECK-NEXT-ARM:   10200:     1e ff 2f e1     bx      lr
diff --git a/test/ELF/arm-branch-error.s b/test/ELF/arm-branch-error.s
new file mode 100644 (file)
index 0000000..f1a855d
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq too_far3
+
+// CHECK: R_ARM_CALL out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
diff --git a/test/ELF/arm-branch.s b/test/ELF/arm-branch.s
new file mode 100644 (file)
index 0000000..38266fa
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee2 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck  %s
+// REQUIRES: arm
+ .syntax unified
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ b   callee_low
+ beq callee_low
+ bl  callee_high
+ b   callee_high
+ bne callee_high
+ bl  far
+ b   far
+ bgt far
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .align 2
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+// CHECK: Disassembly of section .caller:
+// CHECK-NEXT: _start:
+// S(callee_low) = 0xb4 P = 0x10000 A = -8 = -0xff54 = -65364
+// CHECK-NEXT:   10000:       2b c0 ff eb          bl      #-65364 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10004 A = -8 = -0xff58 = -65368
+// CHECK-NEXT:   10004:       2a c0 ff ea          b       #-65368 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10008 A = -8 = -0xff5c -65372
+// CHECK-NEXT:   10008:       29 c0 ff 0a          beq     #-65372 <callee_low>
+// S(callee_high) = 0x10028 P = 0x1000c A = -8 = 0x14 = 20
+// CHECK-NEXT:   1000c:       05 00 00 eb          bl      #20 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10010 A = -8 = 0x10 = 16
+// CHECK-NEXT:   10010:       04 00 00 ea          b       #16 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10014 A = -8 = 0x0c =12
+// CHECK-NEXT:   10014:       03 00 00 1a          bne     #12 <callee_high>
+// S(far) = 0x201001c P = 0x10018 A = -8 = 0x1fffffc = 33554428
+// CHECK-NEXT:   10018:       ff ff 7f eb          bl      #33554428
+// S(far) = 0x201001c P = 0x1001c A = -8 = 0x1fffff8 = 33554424
+// CHECK-NEXT:   1001c:       fe ff 7f ea          b       #33554424
+// S(far) = 0x201001c P = 0x10020 A = -8 = 0x1fffff4 = 33554420
+// CHECK-NEXT:   10020:       fd ff 7f ca          bgt     #33554420
+// CHECK-NEXT:   10024:       1e ff 2f e1          bx      lr
diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s
new file mode 100644 (file)
index 0000000..e5ce157
--- /dev/null
@@ -0,0 +1,81 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s
+
+// Copy relocations R_ARM_COPY are required for y and z
+ .syntax unified
+ .text
+ .globl _start
+_start:
+ movw r2,:lower16: y
+ movt r2,:upper16: y
+ ldr r3,[pc,#4]
+ ldr r3,[r3,#0]
+ .rodata
+ .word z
+
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x13000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 8
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT:  Section (5) .rel.dyn {
+// CHECK-NEXT:    Relocation {
+// CHECK-NEXT:      Offset: 0x13000
+// CHECK-NEXT:      Type: R_ARM_COPY
+// CHECK-NEXT:      Symbol: y
+// CHECK-NEXT:      Addend: 0x0
+// CHECK-NEXT:    }
+// CHECK-NEXT:    Relocation {
+// CHECK-NEXT:      Offset: 0x13004
+// CHECK-NEXT:      Type: R_ARM_COPY
+// CHECK-NEXT:      Symbol: z
+// CHECK-NEXT:      Addend: 0x0
+// CHECK-NEXT:    }
+// CHECK-NEXT:  }
+
+// CHECK: Symbols [
+// CHECK:     Name: y
+// CHECK-NEXT:    Value: 0x13000
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other:
+// CHECK-NEXT:    Section: .bss
+// CHECK:    Name: z
+// CHECK-NEXT:    Value: 0x13004
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// S(y) = 0x13000, A = 0
+// (S + A) & 0x0000ffff = 0x3000 = #12288
+// CODE-NEXT:   11000:  00 20 03 e3    movw    r2, #12288
+// S(y) = 0x13000, A = 0
+// ((S + A) & 0xffff0000) >> 16 = 0x1
+// CODE-NEXT:   11004:       01 20 40 e3    movt    r2, #1
+// CODE-NEXT:   11008:       04 30 9f e5    ldr     r3, [pc, #4]
+// CODE-NEXT:   1100c:       00 30 93 e5    ldr     r3, [r3]
+
+
+// RODATA: Contents of section .rodata:
+// S(z) = 0x13004
+// RODATA-NEXT: 10114 04300100
diff --git a/test/ELF/arm-data-prel.s b/test/ELF/arm-data-prel.s
new file mode 100644 (file)
index 0000000..590d811
--- /dev/null
@@ -0,0 +1,63 @@
+// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:          .text : { *(.text) } \
+// RUN:          .ARM.exidx : { *(.ARM.exidx) } \
+// RUN:          .ARM.exidx.TEST1 : { *(.ARM.exidx.TEST1) } \
+// RUN:          .TEST1 : { *(.TEST1) } } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s
+// REQUIRES: arm
+
+// The R_ARM_PREL31 relocation is used in by the .ARM.exidx exception tables
+// bit31 of the place denotes whether the field is an inline table entry
+// (bit31=1) or relocation (bit31=0)
+// The linker must preserve the value of bit31
+
+// This test case is adapted from llvm/test/MC/ARM/eh-compact-pr0.s
+// We use a linker script to place the .ARM.exidx sections in between
+// the code sections so that we can test positive and negative offsets
+ .syntax unified
+
+ .section .TEST1, "ax",%progbits
+ .globl _start
+ .align 2
+ .type  _start,%function
+_start:
+ .fnstart
+ .save   {r11, lr}
+ push    {r11, lr}
+ .setfp  r11, sp
+ mov     r11, sp
+ pop     {r11, lr}
+ mov     pc, lr
+ .fnend
+
+ .section .text, "ax",%progbits
+// The generated .ARM.exidx section will refer to the personality
+// routine __aeabi_unwind_cpp_pr0. Provide a dummy implementation
+// to stop an undefined symbol error
+ .globl __aeabi_unwind_cpp_pr0
+ .align 2
+ .type __aeabi_unwind_cpp_pr0,%function
+__aeabi_unwind_cpp_pr0:
+ .fnstart
+ bx lr
+ .fnend
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, -4 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// CHECK:  Name: .ARM.exidx
+// CHECK:  SectionData (
+// CHECK:     0000: FCFFFF7F B0B0B080
+// CHECK:  )
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, +8 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// set vsp = r11
+// pop r11, r14
+// CHECK:  Name: .ARM.exidx.TEST1
+// CHECK:  SectionData (
+// CHECK:     0000: 08000000 80849B80
+// CHECK:  )
diff --git a/test/ELF/arm-data-relocs.s b/test/ELF/arm-data-relocs.s
new file mode 100644 (file)
index 0000000..ed23785
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/abs256.s -o %t256.o
+// RUN: ld.lld %t %t256.o -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_ABS32POS, "ax",%progbits
+ .word foo + 0x24
+
+// S = 0x100, A = 0x24
+// S + A = 0x124
+// CHECK: Disassembly of section .R_ARM_ABS32POS:
+// CHECK: 11000: 24 01 00 00
+ .section .R_ARM_ABS32NEG, "ax",%progbits
+ .word foo - 0x24
+// S = 0x100, A = -0x24
+// CHECK: Disassembly of section .R_ARM_ABS32NEG:
+// CHECK: 11004: dc 00 00 00
diff --git a/test/ELF/arm-fpic-got.s b/test/ELF/arm-fpic-got.s
new file mode 100644 (file)
index 0000000..4b6002d
--- /dev/null
@@ -0,0 +1,63 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: llvm-readobj -s -symbols %t | FileCheck -check-prefix=SYMBOLS %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+
+// Test the R_ARM_GOT_PREL relocation
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ ldr     r0, .LCPI0_0
+.LPC0_0:
+ ldr     r0, [pc, r0]
+ ldr     r0, [r0]
+ bx      lr
+.LCPI0_0:
+.Ltmp0:
+ // Generate R_ARM_GOT_PREL
+ .long   val(GOT_PREL)-((.LPC0_0+8)-.Ltmp0)
+
+ .data
+ .type   val,%object
+ .globl  val
+ .align  2
+val:
+ .long   10
+ .size   val, 4
+
+// CHECK: Section {
+// CHECK:    Name: .got
+// CHECK-NEXT:    Type: SHT_PROGBITS
+// CHECK-NEXT:      Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x12000
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize:
+
+// SYMBOLS:    Name: val
+// SYMBOLS-NEXT:    Value: 0x13000
+// SYMBOLS-NEXT:    Size: 4
+// SYMBOLS-NEXT:    Binding: Global
+// SYMBOLS-NEXT:    Type: Object
+// SYMBOLS-NEXT:    Other:
+// SYMBOLS-NEXT:    Section: .data
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT:   11000:  08 00 9f e5     ldr     r0, [pc, #8]
+// CODE-NEXT:   11004:  00 00 9f e7     ldr     r0, [pc, r0]
+// CODE-NEXT:   11008:  00 00 90 e5     ldr     r0, [r0]
+// CODE-NEXT:   1100c:  1e ff 2f e1     bx      lr
+// CODE: $d.1:
+// 0x11004 + 0x0ff4 + 8 = 0x12000 = .got
+// CODE-NEXT:   11010:  f4 0f 00 00
diff --git a/test/ELF/arm-gnu-ifunc-nosym.s b/test/ELF/arm-gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..fa79aef
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: arm
+
+// Check that no __rel_iplt_end/__rel_iplt_start
+// appear in symtab if there are no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rel_iplt_end
+// CHECK-NOT: __rel_iplt_start
+// CHECK: ]
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s
new file mode 100644 (file)
index 0000000..c1e8a71
--- /dev/null
@@ -0,0 +1,131 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
+ movw r0,:lower16:__rel_iplt_start
+ movt r0,:upper16:__rel_iplt_start
+ movw r0,:lower16:__rel_iplt_end
+ movt r0,:upper16:__rel_iplt_end
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rel.plt
+// CHECK-NEXT:  Type: SHT_REL
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[REL:.*]]
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:   Size: 16
+// CHECK-NEXT:   Link:
+// CHECK-NEXT:   Info:
+// CHECK-NEXT:   AddressAlignment: 4
+// CHECK-NEXT:   EntrySize: 8
+// CHECK-NEXT:  }
+// CHECK: Relocations [
+// CHECK-NEXT:  Section (1) .rel.plt {
+// CHECK-NEXT:    0x1200C R_ARM_IRELATIVE
+// CHECK-NEXT:    0x12010 R_ARM_IRELATIVE
+// CHECK-NEXT:  }
+// CHECK-NEXT:]
+// CHECK:  Symbols [
+// CHECK:   Symbol {
+// CHECK:         Name: __rel_iplt_end
+// CHECK-NEXT:    Value: 0x100E4
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rel.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rel_iplt_start
+// CHECK-NEXT:    Value: 0x100D4
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rel.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start (6)
+// CHECK-NEXT:    Value: 0x11008
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other:
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x11004
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x11000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:   11000:       1e ff 2f e1     bx      lr
+// DISASM: bar:
+// DISASM-NEXT:   11004:       1e ff 2f e1     bx      lr
+// DISASM: _start:
+// DISASM-NEXT:   11008:       09 00 00 eb     bl      #36
+// DISASM-NEXT:   1100c:       0c 00 00 eb     bl      #48
+// DISASM-NEXT:   11010:       d4 00 00 e3     movw    r0, #212
+// DISASM-NEXT:   11014:       01 00 40 e3     movt    r0, #1
+// r0 = 212 + 1 * 65536 = 100D4 = __rel_iplt_start
+// DISASM-NEXT:   11018:       e4 00 00 e3     movw    r0, #228
+// DISASM-NEXT:   1101c:       01 00 40 e3     movt    r0, #1
+// r1 = 228 + 1 * 65536 = 100E4 = __rel_iplt_end
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   11020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DISASM-NEXT:   11024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DISASM-NEXT:   11028:       0e e0 8f e0     add     lr, pc, lr
+// DISASM-NEXT:   1102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// 0x0fd0 + 0x11028 + 0x8 = 0x12000
+// DISASM-NEXT:   11030:       d0 0f 00 00
+// DISASM-NEXT:   11034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:   11038:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:   1103c:       00 f0 9c e5     ldr     pc, [r12]
+// 0x0fcc + 0x11038 + 0x8 = 0x1200C
+// DISASM-NEXT:   11040:       cc 0f 00 00
+// DISASM-NEXT:   11044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:   11048:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:   1104c:       00 f0 9c e5     ldr     pc, [r12]
+// 0x0fc0 + 0x11048 + 0x8 = 0x12010
+// DISASM-NEXT:   11050:       c0 0f 00 00
diff --git a/test/ELF/arm-got-relative.s b/test/ELF/arm-got-relative.s
new file mode 100644 (file)
index 0000000..22ccb16
--- /dev/null
@@ -0,0 +1,53 @@
+// REQUIRES: arm
+// RUN: llvm-mc -position-independent -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -shared -o %t
+// RUN: llvm-readobj -s -symbols -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ .type _start, %function
+ ldr r3, .LGOT
+ ldr r2, .LGOT+4
+.LPIC:
+ add r0, pc, r3
+ bx lr
+ .align 2
+.LGOT:
+ // gas implicitly uses (GOT_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
+ // llvm-mc needs the (GOT_PREL) suffix or it generates R_ARM_REL32
+ .word _GLOBAL_OFFSET_TABLE_(GOT_PREL) - (.LPIC+8)
+ .word function(GOT)
+
+ .globl function
+ .align 2
+function:
+ .type function, %function
+ bx lr
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT:  0x204C R_ARM_GLOB_DAT function 0x0
+
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (16)
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size:
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: Absolute
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT:    1000:        08 30 9f e5    ldr     r3, [pc, #8]
+// CODE-NEXT:    1004:        08 20 9f e5    ldr     r2, [pc, #8]
+// CODE-NEXT:    1008:        03 00 8f e0    add     r0, pc, r3
+// CODE-NEXT:    100c:        1e ff 2f e1    bx      lr
+// CODE:$d.1:
+// (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038
+// CODE-NEXT:    1010:        38 10 00 00
+// (Got(function) - GotBase = 0x4
+// CODE-NEXT:    1014:        04 00 00 00
diff --git a/test/ELF/arm-gotoff.s b/test/ELF/arm-gotoff.s
new file mode 100644 (file)
index 0000000..5169f84
--- /dev/null
@@ -0,0 +1,74 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -r -t %t | FileCheck %s
+// RUN: llvm-objdump -triple=armv7a-linux-gnueabi -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: arm
+
+// Test the R_ARM_GOTOFF32 relocation
+
+// CHECK:      Name: .got
+// CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x12000
+// CHECK-NEXT:    Offset: 0x2000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment:
+
+// CHECK:    Name: .bss
+// CHECK-NEXT:    Type: SHT_NOBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x12000
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 20
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 1
+
+// CHECK-NEXT:    EntrySize: 0
+
+// CHECK:       Symbol {
+// CHECK:       Name: bar
+// CHECK-NEXT:    Value: 0x12000
+// CHECK-NEXT:    Size: 10
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: obj
+// CHECK-NEXT:    Value: 0x1200A
+// CHECK-NEXT:    Size: 10
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT :_start:
+// DISASM-NEXT   11000:       1e ff 2f e1     bx      lr
+// Offset 0 from .got = bar
+// DISASM        11004:       00 00 00 00
+// Offset 10 from .got = obj
+// DISASM-NEXT   11008:       0a 00 00 00
+// Offset 15 from .got = obj +5
+// DISASM-NEXT   1100c:       0f 00 00 00
+ .syntax unified
+ .globl _start
+_start:
+ bx lr
+ .word bar(GOTOFF)
+ .word obj(GOTOFF)
+ .word obj(GOTOFF)+5
+ .type bar, %object
+ .comm bar, 10
+ .type obj, %object
+ .comm obj, 10
diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s
new file mode 100644 (file)
index 0000000..31ccba4
--- /dev/null
@@ -0,0 +1,94 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-unknown-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 -triple=armv7a-unknown-linux-gnueabi | FileCheck %s
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-unknown-linux-gnueabi %s -o %t3
+// RUN: ld.lld %t3 -o %t4
+// RUN: llvm-objdump -d %t4 -triple=thumbv7a-unknown-linux-gnueabi | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations as well as
+// the R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS relocations.
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_MOVW_ABS_NC, "ax",%progbits
+ movw r0, :lower16:label
+ movw r1, :lower16:label1
+ movw r2, :lower16:label2 + 4
+ movw r3, :lower16:label3
+ movw r4, :lower16:label3 + 4
+// CHECK: Disassembly of section .R_ARM_MOVW_ABS_NC
+// CHECK: movw r0, #0
+// CHECK: movw r1, #4
+// CHECK: movw r2, #12
+// CHECK: movw r3, #65532
+// CHECK: movw r4, #0
+ .section .R_ARM_MOVT_ABS, "ax",%progbits
+ movt r0, :upper16:label
+ movt r1, :upper16:label1
+// FIXME: We shouldn't need to multiply by 65536.
+// arguably llvm-mc incorrectly assembles addends for
+// SHT_REL relocated movt instructions. When there is a relocation
+// the interpretation of the addend for SHT_REL is not shifted
+ movt r2, :upper16:label2 + (4 * 65536)
+ movt r3, :upper16:label3
+// FIXME: We shouldn't need to multiply by 65536 see comment above.
+ movt r4, :upper16:label3 + (4 * 65536)
+// CHECK: Disassembly of section .R_ARM_MOVT_ABS
+// CHECK: movt r0, #2
+// CHECK: movt r1, #2
+// CHECK: movt r2, #2
+// CHECK: movt r3, #2
+// CHECK: movt r4, #3
+
+.section .R_ARM_MOVW_PREL_NC, "ax",%progbits
+ movw r0, :lower16:label - .
+ movw r1, :lower16:label1 - .
+ movw r2, :lower16:label2 + 4 - .
+ movw r3, :lower16:label3 - .
+ movw r4, :lower16:label3 + 0x103c - .
+// 0x20000 - 0x11028 = :lower16:0xefd8 (61400)
+// CHECK: 11028:  {{.*}}     movw    r0, #61400
+// 0x20004 = 0x1102c = :lower16:0xefd8 (61400)
+// CHECK: 1102c:  {{.*}}     movw    r1, #61400
+// 0x20008 - 0x11030 + 4 = :lower16:0xefdc (61404)
+// CHECK: 11030:  {{.*}}     movw    r2, #61404
+// 0x2fffc - 0x11034 = :lower16:0x1efc8 (61384)
+// CHECK: 11034:  {{.*}}     movw    r3, #61384
+// 0x2fffc - 0x11038 +0x103c :lower16:0x20000 (0)
+// CHECK: 11038:  {{.*}}     movw    r4, #0
+
+.section .R_ARM_MOVT_PREL, "ax",%progbits
+ movt r0, :upper16:label - .
+ movt r1, :upper16:label1 - .
+ movt r2, :upper16:label2 + 0x4 - .
+ movt r3, :upper16:label3 - .
+ movt r4, :upper16:label3 + 0x1050 - .
+// 0x20000 - 0x1103c = :upper16:0xefc4  = 0
+// CHECK: 1103c:  {{.*}}     movt    r0, #0
+// 0x20004 - 0x11040 = :upper16:0xefc0 = 0
+// CHECK: 11040:  {{.*}}     movt    r1, #0
+// 0x20008 - 0x11044 + 4 = :upper16:0xefc8 = 0
+// CHECK: 11044:  {{.*}}     movt    r2, #0
+// 0x2fffc - 0x11048 = :upper16:0x1efb4 = 1
+// CHECK: 11048:  {{.*}}     movt    r3, #1
+// 0x2fffc - 0x1104c + 0x1050 = :upper16:0x20000 = 2
+// CHECK: 1104c:  {{.*}}     movt    r4, #2
+ .section .destination, "aw",%progbits
+ .balign 65536
+// 0x20000
+label:
+ .word 0
+// 0x20004
+label1:
+ .word 1
+// 0x20008
+label2:
+ .word 2
+// Test label3 is immediately below 2^16 alignment boundary
+ .space 65536 - 16
+// 0x2fffc
+label3:
+ .word 3
+// label3 + 4 is on a 2^16 alignment boundary
+ .word 4
diff --git a/test/ELF/arm-plt-reloc.s b/test/ELF/arm-plt-reloc.s
new file mode 100644 (file)
index 0000000..0616aa7
--- /dev/null
@@ -0,0 +1,90 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2
+// RUN: ld.lld %t1 %t2 -o %t
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t | FileCheck %s
+// RUN: ld.lld -shared %t1 %t2 -o %t3
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSO %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+// REQUIRES: arm
+//
+// Test PLT entry generation
+ .syntax unified
+ .text
+ .align 2
+ .globl _start
+ .type  _start,%function
+_start:
+ b func1
+ bl func2
+ beq func3
+
+// Executable, expect no PLT
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func1:
+// CHECK-NEXT:   11000:        1e ff 2f e1    bx      lr
+// CHECK: func2:
+// CHECK-NEXT:   11004:        1e ff 2f e1    bx      lr
+// CHECK: func3:
+// CHECK-NEXT:   11008:        1e ff 2f e1    bx      lr
+// CHECK: _start:
+// CHECK-NEXT:   1100c:        fb ff ff ea    b       #-20 <func1>
+// CHECK-NEXT:   11010:        fb ff ff eb    bl      #-20 <func2>
+// CHECK-NEXT:   11014:        fb ff ff 0a    beq     #-20 <func3>
+
+// Expect PLT entries as symbols can be preempted
+// DSO: Disassembly of section .text:
+// DSO-NEXT: func1:
+// DSO-NEXT:    1000:        1e ff 2f e1    bx      lr
+// DSO: func2:
+// DSO-NEXT:    1004:        1e ff 2f e1    bx      lr
+// DSO: func3:
+// DSO-NEXT:    1008:        1e ff 2f e1    bx      lr
+// DSO: _start:
+// S(0x1034) - P(0x100c) + A(-8) = 0x20 = 32
+// DSO-NEXT:    100c:        08 00 00 ea    b       #32
+// S(0x1044) - P(0x1010) + A(-8) = 0x2c = 44
+// DSO-NEXT:    1010:        0b 00 00 eb    bl      #44
+// S(0x1054) - P(0x1014) + A(-8) = 0x38 = 56
+// DSO-NEXT:    1014:        0e 00 00 0a    beq     #56
+// DSO: Disassembly of section .plt:
+// DSO-NEXT:.plt:
+// DSO-NEXT:    1020:        04 e0 2d e5    str     lr, [sp, #-4]!
+// DSO-NEXT:    1024:        04 e0 9f e5    ldr     lr, [pc, #4]
+// DSO-NEXT:    1028:        0e e0 8f e0    add     lr, pc, lr
+// DSO-NEXT:    102c:        08 f0 be e5    ldr     pc, [lr, #8]!
+// 0x1028 + 8 + 1fd0 = 0x3000
+// DSO-NEXT:    1030:        d0 1f 00 00
+// DSO-NEXT:    1034:        04 c0 9f e5    ldr     r12, [pc, #4]
+// DSO-NEXT:    1038:        0f c0 8c e0    add     r12, r12, pc
+// DSO-NEXT:    103c:        00 f0 9c e5    ldr     pc, [r12]
+// 0x1038 + 8 + 1fcc = 0x300c
+// DSO-NEXT:    1040:        cc 1f 00 00
+// DSO-NEXT:    1044:        04 c0 9f e5    ldr     r12, [pc, #4]
+// DSO-NEXT:    1048:        0f c0 8c e0    add     r12, r12, pc
+// DSO-NEXT:    104c:        00 f0 9c e5    ldr     pc, [r12]
+// 0x1048 + 8 + 1fc0 = 0x3010
+// DSO-NEXT:    1050:        c0 1f 00 00
+// DSO-NEXT:    1054:        04 c0 9f e5    ldr     r12, [pc, #4]
+// DSO-NEXT:    1058:        0f c0 8c e0    add     r12, r12, pc
+// DSO-NEXT:    105c:        00 f0 9c e5    ldr     pc, [r12]
+// 0x1058 + 8 + 1fb4 = 0x3014
+// DSO-NEXT:    1060:       b4 1f 00 00
+
+// DSOREL:    Name: .got.plt
+// DSOREL-NEXT:    Type: SHT_PROGBITS
+// DSOREL-NEXT:    Flags [
+// DSOREL-NEXT:      SHF_ALLOC
+// DSOREL-NEXT:      SHF_WRITE
+// DSOREL-NEXT:    ]
+// DSOREL-NEXT:    Address: 0x3000
+// DSOREL-NEXT:    Offset:
+// DSOREL-NEXT:    Size: 24
+// DSOREL-NEXT:    Link:
+// DSOREL-NEXT:    Info:
+// DSOREL-NEXT:    AddressAlignment: 4
+// DSOREL-NEXT:    EntrySize:
+// DSOREL:  Relocations [
+// DSOREL-NEXT:  Section (4) .rel.plt {
+// DSOREL-NEXT:    0x300C R_ARM_JUMP_SLOT func1 0x0
+// DSOREL-NEXT:    0x3010 R_ARM_JUMP_SLOT func2 0x0
+// DSOREL-NEXT:    0x3014 R_ARM_JUMP_SLOT func3 0x0
diff --git a/test/ELF/arm-thumb-blx.s b/test/ELF/arm-thumb-blx.s
new file mode 100644 (file)
index 0000000..b581d1d
--- /dev/null
@@ -0,0 +1,85 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/arm-thumb-blx-targets.s -o %ttarget
+// RUN: echo "SECTIONS { \
+// RUN:          .R_ARM_CALL24_callee1 : { *(.R_ARM_CALL24_callee_low) } \
+// RUN:          .R_ARM_CALL24_callee2 : { *(.R_ARM_CALL24_callee_thumb_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .R_ARM_CALL24_callee3 : { *(.R_ARM_CALL24_callee_high) } \
+// RUN:          .R_ARM_CALL24_callee4 : { *(.R_ARM_CALL24_callee_thumb_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %ttarget -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s 
+// REQUIRES: arm
+// Test BLX instruction is chosen for Thumb BL/BLX instruction and ARM callee
+// 2 byte nops are used to test the pc-rounding behaviour. As a BLX from a
+// 2 byte aligned destination is defined as Align(PC,4) + immediate:00
+// FIXME: llvm-mc has problems assembling BLX unless the destination is
+// external. The targets of the BL and BLX instructions are in arm-thumb-blx-target.s
+ .syntax unified
+ .section .text, "ax",%progbits
+ .thumb
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ blx  callee_low
+ nop
+ bl callee_low
+ nop
+ blx  callee_high
+ nop
+ bl callee_high
+ nop
+ blx  blx_far
+ nop
+ bl   blx_far
+ nop
+// Expect BLX to thumb target to be written out as a BL
+ blx   callee_thumb_low
+ nop
+ blx   callee_thumb_high
+ bx lr
+
+// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee1:
+// CHECK-NEXT-ARM: callee_low:
+// CHECK-NEXT-ARM:      b4:     1e ff 2f e1     bx      lr
+
+// CHECK-THUMB: Disassembly of section .R_ARM_CALL24_callee2:
+// CHECK-NEXT-THUMB: callee_thumb_low:
+// CHECK-NEXT-THUMB:     100:  70 47   bx      lr
+
+// CHECK-THUMB: Disassembly of section .caller:
+// CHECK-THUMB: _start:
+// Align(0x10000,4) - 0xff50 (65360) + 4 = 0xb4 = callee_low
+// CHECK-NEXT-THUMB:   10000:       f0 f7 58 e8     blx     #-65360
+// CHECK-NEXT-THUMB:   10004:       00 bf   nop
+// Align(0x10006,4) - 0xff54 (65364) + 4 = 0xb4 = callee_low
+// CHECK-NEXT-THUMB:   10006:       f0 f7 56 e8     blx     #-65364
+// CHECK-NEXT-THUMB:   1000a:       00 bf   nop
+// Align(0x1000c,4) + 0xf0 (240) + 4 = 0x10100 = callee_high
+// CHECK-NEXT-THUMB:   1000c:   00 f0 78 e8     blx     #240
+// CHECK-NEXT-THUMB:   10010:       00 bf   nop
+// Align(0x10012,4) + 0xec (236) + 4 = 0x10100 = callee_high
+// CHECK-NEXT-THUMB:   10012:       00 f0 76 e8     blx     #236
+// CHECK-NEXT-THUMB:   10016:       00 bf   nop
+// Align(0x10018,4) + 0xfffffc (16777212) = 0x1010018 = blx_far
+// CHECK-NEXT-THUMB:   10018:       ff f3 fe c7     blx     #16777212
+// CHECK-NEXT-THUMB:   1001c:       00 bf   nop
+// Align(0x1001e,4) + 0xfffff8 (16777208) = 0x1010018 = blx_far
+// CHECK-NEXT-THUMB:   1001e:       ff f3 fc c7     blx     #16777208
+// CHECK-NEXT-THUMB:   10022:       00 bf   nop
+// 10024 - 0xff28 (65320) + 4 = 0x100 = callee_thumb_low
+// CHECK-NEXT-THUMB:   10024:       f0 f7 6c f8     bl      #-65320
+// CHECK-NEXT-THUMB:   10028:       00 bf   nop
+// 1002a + 0x1d2 (466) + 4 = 0x10200 = callee_thumb_high
+// CHECK-NEXT-THUMB:   1002a:       00 f0 e9 f8     bl      #466
+// CHECK-NEXT-THUMB:   1002e:       70 47   bx      lr
+
+
+// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee3:
+// CHECK-NEXT-ARM: callee_high:
+// CHECK-NEXT-ARM:   10100:     1e ff 2f e1     bx      lr
+
+// CHECK: Disassembly of section .R_ARM_CALL24_callee4:
+// CHECK-NEXT-THUMB:callee_thumb_high:
+// CHECK-NEXT-THUMB:   10200:   70 47   bx      lr
diff --git a/test/ELF/arm-thumb-branch-error.s b/test/ELF/arm-thumb-branch-error.s
new file mode 100644 (file)
index 0000000..de6c1bc
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq.w too_far3
+
+// CHECK: R_ARM_THM_CALL out of range
+// CHECK-NEXT: R_ARM_THM_JUMP24 out of range
+// CHECK-NEXT: R_ARM_THM_JUMP19 out of range
diff --git a/test/ELF/arm-thumb-branch.s b/test/ELF/arm-thumb-branch.s
new file mode 100644 (file)
index 0000000..94be9ec
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee2 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck  %s
+// REQUIRES: arm
+
+ .syntax unified
+ .thumb
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ b   callee_low
+ beq callee_low
+ bl  callee_high
+ b   callee_high
+ bne callee_high
+ bl  far_uncond
+ b   far_uncond
+ bgt far_cond
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .align 2
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+// CHECK: Disassembly of section .callee1:
+// CHECK-NEXT: callee_low:
+// CHECK-NEXT:      b4:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .caller:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   10000:       f0 f7 58 f8     bl      #-65360
+// CHECK-NEXT:   10004:       f0 f7 56 b8     b.w     #-65364
+// CHECK-NEXT:   10008:       30 f4 54 a8     beq.w   #-65368
+// CHECK-NEXT:   1000c:       00 f0 0c f8     bl      #24
+// CHECK-NEXT:   10010:       00 f0 0a b8     b.w     #20
+// CHECK-NEXT:   10014:       40 f0 08 80     bne.w   #16
+// CHECK-NEXT:   10018:       ff f3 ff d7     bl      #16777214
+// CHECK-NEXT:   1001c:       ff f3 fd 97     b.w     #16777210
+// CHECK-NEXT:   10020:       3f f3 ff af     bgt.w   #1048574
+// CHECK-NEXT:   10024:       70 47   bx      lr
+// CHECK-NEXT:   10026:       00 00   movs    r0, r0
+// CHECK-NEXT: Disassembly of section .callee2:
+// CHECK-NEXT: callee_high:
+// CHECK-NEXT:   10028:       70 47   bx      lr
diff --git a/test/ELF/arm-thumb-interwork-thunk.s b/test/ELF/arm-thumb-interwork-thunk.s
new file mode 100644 (file)
index 0000000..6173df3
--- /dev/null
@@ -0,0 +1,375 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       .R_ARM_JUMP24_callee_1 : { *(.R_ARM_JUMP24_callee_low) } \
+// RUN:       .R_ARM_THM_JUMP_callee_1 : { *(.R_ARM_THM_JUMP_callee_low)} \
+// RUN:       .text : { *(.text) } \
+// RUN:       .arm_caller : { *(.arm_caller) } \
+// RUN:       .thumb_caller : { *(.thumb_caller) } \
+// RUN:       .R_ARM_JUMP24_callee_2 : { *(.R_ARM_JUMP24_callee_high) } \
+// RUN:       .R_ARM_THM_JUMP_callee_2 : { *(.R_ARM_THM_JUMP_callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-ABS-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-ABS-ARM %s
+// RUN: ld.lld --script %t.script %t -pie -o %t3 2>&1
+// RUN: ld.lld --script %t.script %t --shared -o %t4 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-ARM %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-PLT-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-PLT-ARM %s
+// RUN: llvm-readobj -s -r %t4 | FileCheck -check-prefix=CHECK-DSO-REL %s
+// REQUIRES: arm
+
+// Test ARM Thumb Interworking
+// The file is linked and checked 3 times to check the following contexts
+// - Absolute executables, absolute Thunks are used.
+// - Position independent executables, position independent Thunks are used.
+// - Shared object, position independent Thunks to PLT entries are used.
+
+ .syntax unified
+
+// Target Sections for thunks at a lower address than the callers.
+.section .R_ARM_JUMP24_callee_low, "ax", %progbits
+ .thumb
+ .balign 0x1000
+ .globl thumb_callee1
+ .type thumb_callee1, %function
+thumb_callee1:
+ bx lr
+
+// CHECK-THUMB: Disassembly of section .R_ARM_JUMP24_callee_1:
+// CHECK-THUMB: thumb_callee1:
+// CHECK-THUMB: 1000:       70 47   bx
+ .section .R_ARM_THM_JUMP_callee_low, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_callee1
+ .type arm_callee1, %function
+arm_callee1:
+ bx lr
+// Disassembly of section .R_ARM_THM_JUMP_callee_1:
+// CHECK-ARM: arm_callee1:
+// CHECK-ARM-NEXT: 1100:         1e ff 2f e1     bx      lr
+
+ // Calling sections
+ // At present ARM and Thumb interworking thunks are always added to the calling
+ // section.
+ .section .arm_caller, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_caller
+ .type arm_caller, %function
+arm_caller:
+ // If target supports BLX and target is in range we don't need an
+ // interworking thunk for a BL or BLX instruction.
+ bl thumb_callee1
+ blx thumb_callee1
+ // A B instruction can't be transformed into a BLX and needs an interworking
+ // thunk
+ b thumb_callee1
+ // As long as the thunk is in range it can be reused
+ b thumb_callee1
+ // There can be more than one thunk associated with a section
+ b thumb_callee2
+ b thumb_callee3
+ // In range ARM targets do not require interworking thunks
+ b arm_callee1
+ beq arm_callee2
+ bne arm_callee3
+ bx lr
+// CHECK-ABS-ARM: Disassembly of section .arm_caller:
+// CHECK-ABS-ARM-NEXT: arm_caller:
+// CHECK-ABS-ARM-NEXT: 1300:       3e ff ff fa     blx     #-776 <thumb_callee1>
+// CHECK-ABS-ARM-NEXT: 1304:       3d ff ff fa     blx     #-780 <thumb_callee1>
+// CHECK-ABS-ARM-NEXT: 1308:       06 00 00 ea     b       #24 <arm_caller+0x28>
+// CHECK-ABS-ARM-NEXT: 130c:       05 00 00 ea     b       #20 <arm_caller+0x28>
+// CHECK-ABS-ARM-NEXT: 1310:       07 00 00 ea     b       #28 <arm_caller+0x34>
+// CHECK-ABS-ARM-NEXT: 1314:       09 00 00 ea     b       #36 <arm_caller+0x40>
+// CHECK-ABS-ARM-NEXT: 1318:       78 ff ff ea     b       #-544 <arm_callee1>
+// CHECK-ABS-ARM-NEXT: 131c:       b7 00 00 0a     beq     #732 <arm_callee2>
+// CHECK-ABS-ARM-NEXT: 1320:       b7 00 00 1a     bne     #732 <arm_callee3>
+// CHECK-ABS-ARM-NEXT: 1324:       1e ff 2f e1     bx      lr
+// 0x1001 = thumb_callee1
+// CHECK-ABS-ARM-NEXT: 1328:       01 c0 01 e3     movw    r12, #4097
+// CHECK-ABS-ARM-NEXT: 132c:       00 c0 40 e3     movt    r12, #0
+// CHECK-ABS-ARM-NEXT: 1330:       1c ff 2f e1     bx      r12
+// 0x1501 = thumb_callee2
+// CHECK-ABS-ARM-NEXT: 1334:       01 c5 01 e3     movw    r12, #5377
+// CHECK-ABS-ARM-NEXT: 1338:       00 c0 40 e3     movt    r12, #0
+// CHECK-ABS-ARM-NEXT: 133c:       1c ff 2f e1     bx      r12
+// 0x1503 = thumb_callee3
+// CHECK-ABS-ARM-NEXT: 1340:       03 c5 01 e3     movw    r12, #5379
+// CHECK-ABS-ARM-NEXT: 1344:       00 c0 40 e3     movt    r12, #0
+// CHECK-ABS-ARM-NEXT: 1348:       1c ff 2f e1     bx      r12
+
+// CHECK-PI-ARM: Disassembly of section .arm_caller:
+// CHECK-PI-ARM-NEXT: arm_caller:
+// CHECK-PI-ARM-NEXT: 1300:       3e ff ff fa     blx     #-776 <thumb_callee1>
+// CHECK-PI-ARM-NEXT: 1304:       3d ff ff fa     blx     #-780 <thumb_callee1>
+// 0x1308 + 8 + 0x18 = 0x1328
+// CHECK-PI-ARM-NEXT: 1308:       06 00 00 ea     b       #24 <arm_caller+0x28>
+// 0x130c + 8 + 0x14 = 0x1328
+// CHECK-PI-ARM-NEXT: 130c:       05 00 00 ea     b       #20 <arm_caller+0x28>
+// 0x1310 + 8 + 0x20 = 0x1338
+// CHECK-PI-ARM-NEXT: 1310:       08 00 00 ea     b       #32 <arm_caller+0x38>
+// 0x1314 + 8 + 0x2c = 0x1348
+// CHECK-PI-ARM-NEXT: 1314:       0b 00 00 ea     b       #44 <arm_caller+0x48>
+// CHECK-PI-ARM-NEXT: 1318:       78 ff ff ea     b       #-544 <arm_callee1>
+// CHECK-PI-ARM-NEXT: 131c:       b7 00 00 0a     beq     #732 <arm_callee2>
+// CHECK-PI-ARM-NEXT: 1320:       b7 00 00 1a     bne     #732 <arm_callee3>
+// CHECK-PI-ARM-NEXT: 1324:       1e ff 2f e1     bx      lr
+// 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1
+// CHECK-PI-ARM-NEXT: 1328:       c9 cc 0f e3     movw    r12, #64713
+// CHECK-PI-ARM-NEXT: 132c:       ff cf 4f e3     movt    r12, #65535
+// CHECK-PI-ARM-NEXT: 1330:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT: 1334:       1c ff 2f e1     bx      r12
+// 0x1340 + 8 + 0x1b9 = 0x1501
+// CHECK-PI-ARM-NEXT: 1338:       b9 c1 00 e3     movw    r12, #441
+// CHECK-PI-ARM-NEXT: 133c:       00 c0 40 e3     movt    r12, #0
+// CHECK-PI-ARM-NEXT: 1340:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT: 1344:       1c ff 2f e1     bx      r12
+// 1350 + 8 + 0x1ab = 0x1503
+// CHECK-PI-ARM-NEXT: 1348:       ab c1 00 e3     movw    r12, #427
+// CHECK-PI-ARM-NEXT: 134c:       00 c0 40 e3     movt    r12, #0
+// CHECK-PI-ARM-NEXT: 1350:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT: 1354:       1c ff 2f e1     bx      r12
+
+// All PLT entries are ARM, no need for interworking thunks
+// CHECK-PI-ARM-PLT: Disassembly of section .arm_caller:
+// CHECK-PI-ARM-PLT-NEXT: arm_caller:
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1300:       37 01 00 eb     bl      #1244
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1304:       36 01 00 eb     bl      #1240
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1308:       35 01 00 ea     b       #1236
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    130c:       34 01 00 ea     b       #1232
+// 0x17f4 PLT(thumb_callee2)
+// CHECK-PI-ARM-PLT-NEXT:    1310:       37 01 00 ea     b       #1244
+// 0x1804 PLT(thumb_callee3)
+// CHECK-PI-ARM-PLT-NEXT:    1314:       3a 01 00 ea     b       #1256
+// 0x1814 PLT(arm_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1318:       3d 01 00 ea     b       #1268
+// 0x1824 PLT(arm_callee2)
+// CHECK-PI-ARM-PLT-NEXT:    131c:       40 01 00 0a     beq     #1280
+// 0x1834 PLT(arm_callee3)
+// CHECK-PI-ARM-PLT-NEXT:    1320:       43 01 00 1a     bne     #1292
+// CHECK-PI-ARM-PLT-NEXT:    1324:       1e ff 2f e1     bx      lr
+
+ .section .thumb_caller, "ax", %progbits
+ .balign 0x100
+ .thumb
+ .globl thumb_caller
+ .type thumb_caller, %function
+thumb_caller:
+ // If target supports BLX and target is in range we don't need an
+ // interworking thunk for a BL or BLX instruction.
+ bl arm_callee1
+ blx arm_callee1
+ // A B instruction can't be transformed into a BLX and needs an interworking
+ // thunk
+ b.w arm_callee1
+ // As long as the thunk is in range it can be reused
+ b.w arm_callee2
+ // There can be more than one thunk associated with a section
+ b.w arm_callee3
+ // Conditional branches also require interworking thunks, they can use the
+ // same interworking thunks.
+ beq.w arm_callee1
+ beq.w arm_callee2
+ bne.w arm_callee3
+// CHECK-ABS-THUMB: Disassembly of section .thumb_caller:
+// CHECK-ABS-THUMB-NEXT: thumb_caller:
+// 0x1400 + 4 - 0x304 = 0x1100 = arm_callee1
+// CHECK-ABS-THUMB-NEXT: 1400:       ff f7 7e ee     blx     #-772
+// 0x1404 + 4 - 0x308 = 0x1100 = arm_callee1
+// CHECK-ABS-THUMB-NEXT: 1404:       ff f7 7c ee     blx     #-776
+// 0x1408 + 4 + 0x14 = 0x520
+// CHECK-ABS-THUMB-NEXT: 1408:       00 f0 0a b8     b.w     #20
+// 0x140c + 4 + 0x1a = 0x52a
+// CHECK-ABS-THUMB-NEXT: 140c:       00 f0 0d b8     b.w     #26
+// 0x1410 + 4 + 0x20 = 0x534
+// CHECK-ABS-THUMB-NEXT: 1410:       00 f0 10 b8     b.w     #32
+// 0x1414 + 4 + 8 = 0x520
+// CHECK-ABS-THUMB-NEXT: 1414:       00 f0 04 80     beq.w   #8
+// 0x1418 + 4 + 0xe = 0x52a
+// CHECK-ABS-THUMB-NEXT: 1418:       00 f0 07 80     beq.w   #14
+// 0x141c + 4 + 0x14 = 0x534
+// CHECK-ABS-THUMB-NEXT: 141c:       40 f0 0a 80     bne.w   #20
+// 0x1100 = arm_callee1
+// CHECK-ABS-THUMB-NEXT: 1420:       41 f2 00 1c     movw    r12, #4352
+// CHECK-ABS-THUMB-NEXT: 1424:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT: 1428:       60 47   bx      r12
+// 0x1600 = arm_callee2
+// CHECK-ABS-THUMB-NEXT: 142a:       41 f2 00 6c     movw    r12, #5632
+// CHECK-ABS-THUMB-NEXT: 142e:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT: 1432:       60 47   bx      r12
+// 0x1604 = arm_callee3
+// CHECK-ABS-THUMB-NEXT: 1434:       41 f2 04 6c     movw    r12, #5636
+// CHECK-ABS-THUMB-NEXT: 1438:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT: 143c:       60 47   bx      r12
+
+// CHECK-PI-THUMB: Disassembly of section .thumb_caller:
+// CHECK-PI-THUMB-NEXT: thumb_caller:
+// CHECK-PI-THUMB-NEXT: 1400:       ff f7 7e ee     blx     #-772
+// CHECK-PI-THUMB-NEXT: 1404:       ff f7 7c ee     blx     #-776
+// CHECK-PI-THUMB-NEXT: 1408:       00 f0 0a b8     b.w     #20
+// CHECK-PI-THUMB-NEXT: 140c:       00 f0 0e b8     b.w     #28
+// CHECK-PI-THUMB-NEXT: 1410:       00 f0 12 b8     b.w     #36
+// CHECK-PI-THUMB-NEXT: 1414:       00 f0 04 80     beq.w   #8
+// CHECK-PI-THUMB-NEXT: 1418:       00 f0 08 80     beq.w   #16
+// CHECK-PI-THUMB-NEXT: 141c:       40 f0 0c 80     bne.w   #24
+// 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1
+// CHECK-PI-THUMB-NEXT: 1420:       4f f6 d4 4c     movw    r12, #64724
+// CHECK-PI-THUMB-NEXT: 1424:       cf f6 ff 7c     movt    r12, #65535
+// CHECK-PI-THUMB-NEXT: 1428:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT: 142a:       60 47   bx      r12
+// 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2
+// CHECK-PI-THUMB-NEXT: 142c:       40 f2 c8 1c     movw    r12, #456
+// CHECK-PI-THUMB-NEXT: 1430:       c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-NEXT: 1434:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT: 1436:       60 47   bx      r12
+// 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3
+// CHECK-PI-THUMB-NEXT: 1438:       40 f2 c0 1c     movw    r12, #448
+// CHECK-PI-THUMB-NEXT: 143c:       c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-NEXT: 1440:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT: 1442:       60 47   bx      r12
+
+// CHECK-PI-THUMB-PLT: Disassembly of section .arm_caller:
+// CHECK-PI-THUMB-PLT-NEXT: thumb_caller:
+// 0x1400 + 4 + 0x410 = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1400:    00 f0 08 ea     blx     #1040
+// 0x1404 + 4 + 0x40c = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1404:    00 f0 06 ea     blx     #1036
+// 0x1408 + 4 + 0x14 = 0x1420 = IWV(PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1408:    00 f0 0a b8     b.w     #20
+// 0x140c + 4 + 0x1c = 0x142c = IWV(PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    140c:    00 f0 0e b8     b.w     #28
+// 0x1410 + 4 + 0x24 = 0x1438 = IWV(PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    1410:    00 f0 12 b8     b.w     #36
+// 0x1414 + 4 + 8 = 0x1420    = IWV(PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1414:    00 f0 04 80     beq.w   #8
+// 0x1418 + 4 + 0x10 = 0x142c = IWV(PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    1418:    00 f0 08 80     beq.w   #16
+// 0x141c + 4 + 0x18 = 0x1438 = IWV(PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    141c:    40 f0 0c 80     bne.w   #24
+// 0x1428 + 4 + 0x3e8 = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1420:    40 f2 e8 3c     movw    r12, #1000
+// CHECK-PI-THUMB-PLT-NEXT:    1424:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1428:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    142a:    60 47   bx      r12
+// 0x1434 + 4 + 0x3ec = 0x1824 = PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    142c:    40 f2 ec 3c     movw    r12, #1004
+// CHECK-PI-THUMB-PLT-NEXT:    1430:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1434:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    1436:    60 47   bx      r12
+// 0x1440 + 4 + 0x3f0 = 0x1834 = PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    1438:    40 f2 f0 3c     movw    r12, #1008
+// CHECK-PI-THUMB-PLT-NEXT:    143c:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1440:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    1442:    60 47   bx      r12
+
+// Target Sections for thunks at a higher address than the callers.
+.section .R_ARM_JUMP24_callee_high, "ax", %progbits
+ .thumb
+ .balign 0x100
+ .globl thumb_callee2
+ .type thumb_callee2, %function
+thumb_callee2:
+ bx lr
+
+ .globl thumb_callee3
+ .type thumb_callee3, %function
+thumb_callee3:
+ bx lr
+// CHECK-THUMB:  Disassembly of section .R_ARM_JUMP24_callee_2:
+// CHECK-THUMB-NEXT: thumb_callee2:
+// CHECK-THUMB-NEXT: 1500:       70 47   bx      lr
+// CHECK-THUMB: thumb_callee3:
+// CHECK-THUMB-NEXT: 1502:       70 47   bx      lr
+
+ .section .R_ARM_THM_JUMP_callee_high, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_callee2
+ .type arm_callee2, %function
+arm_callee2:
+ bx lr
+ .globl arm_callee3
+ .type arm_callee3, %function
+arm_callee3:
+ bx lr
+// CHECK-ARM: Disassembly of section .R_ARM_THM_JUMP_callee_2:
+// CHECK-ARM-NEXT: arm_callee2:
+// CHECK-ARM-NEXT:     1600:     1e ff 2f e1     bx      lr
+// CHECK-ARM: arm_callee3:
+// CHECK-ARM-NEXT:     1604:     1e ff 2f e1     bx      lr
+
+// _start section just calls the arm and thumb calling sections
+ .text
+ .arm
+ .globl _start
+ .balign 0x100
+ .type _start, %function
+_start:
+ bl arm_caller
+ bl thumb_caller
+ bx lr
+
+
+// CHECK-PI-ARM-PLT: Disassembly of section .plt:
+// CHECK-PI-ARM-PLT-NEXT: .plt:
+// CHECK-PI-ARM-PLT-NEXT: 17b0:         04 e0 2d e5     str     lr, [sp, #-4]!
+// CHECK-PI-ARM-PLT-NEXT: 17b4:         04 e0 9f e5     ldr     lr, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17b8:         0e e0 8f e0     add     lr, pc, lr
+// CHECK-PI-ARM-PLT-NEXT: 17bc:         08 f0 be e5     ldr     pc, [lr, #8]!
+// CHECK-PI-ARM-PLT-NEXT: 17c0:         d4 00 00 00
+// 0x17c8 + 8 + 0xd0 = 0x18a0 arm_caller
+// CHECK-PI-ARM-PLT-NEXT: 17c4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17c8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17cc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17d0:         d0 00 00 00
+// 0x17d8 + 8 + 0xc4 = 0x18a4 thumb_caller
+// CHECK-PI-ARM-PLT-NEXT: 17d4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17d8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17dc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17e0:         c4 00 00 00
+// 0x17e8 + 8 + 0xb8 = 0x18a8 thumb_callee1
+// CHECK-PI-ARM-PLT-NEXT: 17e4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17e8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17ec:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17f0:         b8 00 00 00
+// 0x17f8 + 8 + 0xac = 0x18ac thumb_callee2
+// CHECK-PI-ARM-PLT-NEXT: 17f4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17f8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17fc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1800:         ac 00 00 00
+// 0x1808 + 8 + 0xa0 = 0x18b0 thumb_callee3
+// CHECK-PI-ARM-PLT-NEXT: 1804:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1808:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 180c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1810:         a0 00 00 00
+// 0x1818 + 8 + 0x94 = 0x18b4 arm_callee1
+// CHECK-PI-ARM-PLT-NEXT: 1814:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1818:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 181c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1820:         94 00 00 00
+// 0x1828 + 8 + 0x88 = 0x18b8 arm_callee2
+// CHECK-PI-ARM-PLT-NEXT: 1824:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1828:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 182c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1830:         88 00 00 00
+// 0x1838 + 8 + 0x7c = 0x18bc arm_callee3
+// CHECK-PI-ARM-PLT-NEXT: 1834:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1838:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 183c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1840:         7c 00 00 00
+
+// CHECK-DSO-REL:      0x18A0 R_ARM_JUMP_SLOT arm_caller
+// CHECK-DSO-REL-NEXT: 0x18A4 R_ARM_JUMP_SLOT thumb_caller
+// CHECK-DSO-REL-NEXT: 0x18A8 R_ARM_JUMP_SLOT thumb_callee1
+// CHECK-DSO-REL-NEXT: 0x18AC R_ARM_JUMP_SLOT thumb_callee2
+// CHECK-DSO-REL-NEXT: 0x18B0 R_ARM_JUMP_SLOT thumb_callee3
+// CHECK-DSO-REL-NEXT: 0x18B4 R_ARM_JUMP_SLOT arm_callee1
+// CHECK-DSO-REL-NEXT: 0x18B8 R_ARM_JUMP_SLOT arm_callee2
+// CHECK-DSO-REL-NEXT: 0x18BC R_ARM_JUMP_SLOT arm_callee3
diff --git a/test/ELF/arm-thumb-narrow-branch-check.s b/test/ELF/arm-thumb-narrow-branch-check.s
new file mode 100644 (file)
index 0000000..b601b6d
--- /dev/null
@@ -0,0 +1,72 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:          .R_ARM_PC11_1 : { *(.R_ARM_PC11_1) } \
+// RUN:          .caller : { *(.caller) } \
+// RUN:          .R_ARM_PC11_2 : { *(.R_ARM_PC11_2) } \
+// RUN:          .text : { *(.text) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %S/Inputs/arm-thumb-narrow-branch.o -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_PC11 relocation which is used with the narrow encoding of B.N
+// the source of these relocations is a binary file arm-thumb-narrow-branch.o
+// which has been assembled with the GNU assembler as llvm-mc doesn't emit it
+// as the range of +-2048 bytes is too small to be practically useful for out
+// of section branches.
+ .syntax unified
+
+.global callee_low_far
+.type callee_low_far,%function
+callee_low_far = 0x809
+
+ .section .R_ARM_PC11_1,"ax",%progbits
+ .thumb
+ .balign 0x1000
+ .type callee_low,%function
+ .globl callee_low
+callee_low:
+ bx lr
+
+ .text
+ .align 2
+ .thumb
+ .globl _start
+ .type _start, %function
+_start:
+ bl callers
+ bx lr
+
+ .section .R_ARM_PC11_2,"ax",%progbits
+ .thumb
+ .align 2
+ .type callee_high,%function
+ .globl callee_high
+callee_high:
+ bx lr
+
+.global callee_high_far
+.type callee_high_far,%function
+callee_high_far = 0x180d
+
+// CHECK: Disassembly of section .R_ARM_PC11_1:
+// CHECK-NEXT: callee_low:
+// CHECK-NEXT:    1000:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .caller:
+// CHECK-NEXT: callers:
+// 1004 - 0x800 (2048) + 4 = 0x808 = callee_low_far
+// CHECK-NEXT:    1004:       00 e4   b       #-2048
+// 1006 - 0xa (10) + 4 = 0x1000 = callee_low
+// CHECK-NEXT:    1006:       fb e7   b       #-10
+// 1008 + 4 + 4 = 0x1010 = callee_high
+// CHECK-NEXT:    1008:       02 e0   b       #4
+// 100a + 0x7fe (2046) + 4 = 0x180c = callee_high_far
+// CHECK-NEXT:    100a:       ff e3   b       #2046
+// CHECK-NEXT:    100c:       70 47   bx      lr
+// CHECK-NEXT:    100e:       00 bf   nop
+// CHECK-NEXT: Disassembly of section .R_ARM_PC11_2:
+// CHECK-NEXT: callee_high:
+// CHECK-NEXT:    1010:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    1014:       ff f7 f6 ff     bl      #-20
+// CHECK-NEXT:    1018:       70 47   bx      lr
diff --git a/test/ELF/arm-thumb-plt-reloc.s b/test/ELF/arm-thumb-plt-reloc.s
new file mode 100644 (file)
index 0000000..6294e90
--- /dev/null
@@ -0,0 +1,101 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t2
+// RUN: ld.lld %t1 %t2 -o %t
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t | FileCheck %s
+// RUN: ld.lld -shared %t1 %t2 -o %t3
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+// REQUIRES: arm
+//
+// Test PLT entry generation
+ .syntax unified
+ .text
+ .align 2
+ .globl _start
+ .type  _start,%function
+_start:
+// FIXME, interworking is only supported for BL via BLX at the moment, when
+// interworking thunks are available for b.w and b<cond>.w this can be altered
+// to test the different forms of interworking.
+ bl func1
+ bl func2
+ bl func3
+
+// Executable, expect no PLT
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func1:
+// CHECK-NEXT:   11000: 70 47   bx      lr
+// CHECK: func2:
+// CHECK-NEXT:   11002: 70 47   bx      lr
+// CHECK: func3:
+// CHECK-NEXT:   11004: 70 47   bx      lr
+// CHECK-NEXT:   11006: 00 00   movs    r0, r0
+// CHECK: _start:
+// 11008 + 4 -12 = 0x11000 = func1
+// CHECK-NEXT:   11008: ff f7 fa ff     bl      #-12
+// 1100c + 4 -14 = 0x11002 = func2
+// CHECK-NEXT:   1100c: ff f7 f9 ff     bl      #-14
+// 11010 + 4 -16 = 0x11004 = func3
+// CHECK-NEXT:   11010: ff f7 f8 ff     bl      #-16
+
+// Expect PLT entries as symbols can be preempted
+// .text is Thumb and .plt is ARM, llvm-objdump can currently only disassemble
+// as ARM or Thumb. Work around by disassembling twice.
+// DSOTHUMB: Disassembly of section .text:
+// DSOTHUMB: func1:
+// DSOTHUMB-NEXT:    1000:       70 47   bx      lr
+// DSOTHUMB: func2:
+// DSOTHUMB-NEXT:    1002:       70 47   bx      lr
+// DSOTHUMB: func3:
+// DSOTHUMB-NEXT:    1004:       70 47   bx      lr
+// DSOTHUMB-NEXT:    1006:       00 00   movs    r0, r0
+// DSOTHUMB: _start:
+// 0x1008 + 0x28 + 4 = 0x1034 = PLT func1
+// DSOTHUMB-NEXT:    1008:       00 f0 14 e8     blx     #40
+// 0x100c + 0x34 + 4 = 0x1044 = PLT func2
+// DSOTHUMB-NEXT:    100c:       00 f0 1a e8     blx     #52
+// 0x1010 + 0x40 + 4 = 0x1054 = PLT func3
+// DSOTHUMB-NEXT:    1010:       00 f0 20 e8     blx     #64
+// DSOARM: Disassembly of section .plt:
+// DSOARM: .plt:
+// DSOARM-NEXT:    1020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DSOARM-NEXT:    1024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DSOARM-NEXT:    1028:       0e e0 8f e0     add     lr, pc, lr
+// DSOARM-NEXT:    102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// DSOARM-NEXT:    1030:       d0 1f 00 00
+// 0x1028 + 8 + 1fd0 = 0x3000
+// DSOARM-NEXT:    1034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1038:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    103c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM-NEXT:    1040:       cc 1f 00 00
+// 0x1038 + 8 + 1fcc = 0x300c
+// DSOARM-NEXT:    1044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1048:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    104c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM-NEXT:    1050:       c0 1f 00 00
+// 0x1048 + 8 + 1fc0 = 0x3010
+// DSOARM-NEXT:    1054:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1058:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    105c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM-NEXT:    1060:       b4 1f 00 00
+// 0x1058 + 8 + 1fb4 = 0x3014
+
+// DSOREL:    Name: .got.plt
+// DSOREL-NEXT:    Type: SHT_PROGBITS
+// DSOREL-NEXT:    Flags [
+// DSOREL-NEXT:      SHF_ALLOC
+// DSOREL-NEXT:      SHF_WRITE
+// DSOREL-NEXT:    ]
+// DSOREL-NEXT:    Address: 0x3000
+// DSOREL-NEXT:    Offset:
+// DSOREL-NEXT:    Size: 24
+// DSOREL-NEXT:    Link:
+// DSOREL-NEXT:    Info:
+// DSOREL-NEXT:    AddressAlignment: 4
+// DSOREL-NEXT:    EntrySize:
+// DSOREL:  Relocations [
+// DSOREL-NEXT:  Section (4) .rel.plt {
+// DSOREL-NEXT:    0x300C R_ARM_JUMP_SLOT func1 0x0
+// DSOREL-NEXT:    0x3010 R_ARM_JUMP_SLOT func2 0x0
+// DSOREL-NEXT:    0x3014 R_ARM_JUMP_SLOT func3 0x0
diff --git a/test/ELF/as-needed-no-reloc.s b/test/ELF/as-needed-no-reloc.s
new file mode 100644 (file)
index 0000000..9cbe25c
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t %t.o --as-needed %t2.so
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck %s
+
+
+# There must be a NEEDED entry for each undefined
+
+# CHECK:      Name: bar
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Function
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined
+
+# CHECK: NEEDED SharedLibrary (as-needed-no-reloc{{.*}}2.so)
+
+        .globl _start
+_start:
+        .global bar
diff --git a/test/ELF/as-needed.s b/test/ELF/as-needed.s
new file mode 100644 (file)
index 0000000..4f1a48a
--- /dev/null
@@ -0,0 +1,45 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared2.s -o %t3.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared3.s -o %t4.o
+// RUN: ld.lld -shared %t2.o -soname shared1 -o %t2.so
+// RUN: ld.lld -shared %t3.o -soname shared2 -o %t3.so
+// RUN: ld.lld -shared %t4.o -soname shared3 -o %t4.so
+
+/// Check if --as-needed actually works.
+
+// RUN: ld.lld %t.o %t2.so %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+// RUN: ld.lld --as-needed %t.o %t2.so %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
+
+// RUN: ld.lld --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+/// GROUP directive is the same as --as-needed.
+
+// RUN: echo "GROUP(\"%t2.so\" \"%t3.so\" \"%t4.so\")" > %t.script
+// RUN: ld.lld %t.o %t.script -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+// RUN: echo "GROUP(AS_NEEDED(\"%t2.so\" \"%t3.so\" \"%t4.so\"))" > %t.script
+// RUN: ld.lld %t.o %t.script -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
+
+// CHECK: NEEDED SharedLibrary (shared1)
+// CHECK: NEEDED SharedLibrary (shared2)
+// CHECK: NEEDED SharedLibrary (shared3)
+
+// CHECK2:     NEEDED SharedLibrary (shared1)
+// CHECK2-NOT: NEEDED SharedLibrary (shared2)
+// CHECK2-NOT: NEEDED SharedLibrary (shared3)
+
+.global _start
+_start:
+.data
+.long bar
+.long zed
+.weak baz
+  call baz
diff --git a/test/ELF/avoid-empty-program-headers.s b/test/ELF/avoid-empty-program-headers.s
new file mode 100644 (file)
index 0000000..f731567
--- /dev/null
@@ -0,0 +1,78 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+.global _start
+_start:
+        retq
+
+.section .tbss,"awT",@nobits
+        .zero 4
+// FIXME: Test that we don't create unecessary empty PT_LOAD and PT_GNU_RELRO
+// for the .tbss section.
+
+// CHECK:      ProgramHeaders [
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_PHDR (0x6)
+// CHECK-NEXT:     Offset: 0x40
+// CHECK-NEXT:     VirtualAddress: 0x10040
+// CHECK-NEXT:     PhysicalAddress: 0x10040
+// CHECK-NEXT:     FileSize: 280
+// CHECK-NEXT:     MemSize: 280
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 8
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x10000
+// CHECK-NEXT:     PhysicalAddress: 0x10000
+// CHECK-NEXT:     FileSize: 344
+// CHECK-NEXT:     MemSize: 344
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     VirtualAddress: 0x11000
+// CHECK-NEXT:     PhysicalAddress: 0x11000
+// CHECK-NEXT:     FileSize: 1
+// CHECK-NEXT:     MemSize: 1
+// CHECK-NEXT:     Flags [ (0x5)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_X (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_TLS (0x7)
+// CHECK-NEXT:     Offset: 0x1001
+// CHECK-NEXT:     VirtualAddress: 0x11001
+// CHECK-NEXT:     PhysicalAddress: 0x11001
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 4
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 0
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/basic-aarch64.s b/test/ELF/basic-aarch64.s
new file mode 100644 (file)
index 0000000..84105f0
--- /dev/null
@@ -0,0 +1,193 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+# REQUIRES: aarch64
+
+# exits with return code 42 on FreeBSD/AArch64
+.globl _start
+_start:
+  mov    x0, 42
+  mov    x8, 1
+  svc    0
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_AARCH64 (0xB7)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x1088
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 5
+# CHECK-NEXT:   StringTableSectionIndex: 3
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x11000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1010
+# CHECK-NEXT:     Size: 72
+# CHECK-NEXT:     Link: 4
+# CHECK-NEXT:     Info: 2
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1058
+# CHECK-NEXT:     Size: 33
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .strtab (25)
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1079
+# CHECK-NEXT:     Size: 13
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: $x.0
+# CHECK-NEXT:     Value: 0x11000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10040
+# CHECK-NEXT:     PhysicalAddress: 0x10040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x11000
+# CHECK-NEXT:     PhysicalAddress: 0x11000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/basic-freebsd.s b/test/ELF/basic-freebsd.s
new file mode 100644 (file)
index 0000000..375fdb5
--- /dev/null
@@ -0,0 +1,25 @@
+# Verify that OSABI is set to the correct value.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+.globl _start
+_start:
+  mov $1, %rax
+  mov $42, %rdi
+  syscall
+
+# CHECK: ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_X86_64 (0x3E)
diff --git a/test/ELF/basic-mips.s b/test/ELF/basic-mips.s
new file mode 100644 (file)
index 0000000..c598c7b
--- /dev/null
@@ -0,0 +1,303 @@
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t.exe \
+# RUN:   | FileCheck %s
+
+# REQUIRES: mips
+
+# Exits with return code 1 on Linux.
+        .globl  __start
+__start:
+        li      $a0,1
+        li      $v0,4001
+        syscall
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 32-bit (0x1)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_MIPS (0x8)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x20000
+# CHECK-NEXT:   ProgramHeaderOffset: 0x34
+# CHECK-NEXT:   SectionHeaderOffset: 0x30088
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     EF_MIPS_ABI_O32
+# CHECK-NEXT:     EF_MIPS_ARCH_32R2
+# CHECK-NEXT:     EF_MIPS_CPIC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 52
+# CHECK-NEXT:   ProgramHeaderEntrySize: 32
+# CHECK-NEXT:   ProgramHeaderCount: 6
+# CHECK-NEXT:   SectionHeaderEntrySize: 40
+# CHECK-NEXT:   SectionHeaderCount: 10
+# CHECK-NEXT:   StringTableSectionIndex: 8
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .reginfo
+# CHECK-NEXT:     Type: SHT_MIPS_REGINFO (0x70000006)
+# CHECK-NEXT:     Flags [ (0x2)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x100F4
+# CHECK-NEXT:     Offset: 0xF4
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .MIPS.abiflags
+# CHECK-NEXT:     Type: SHT_MIPS_ABIFLAGS (0x7000002A)
+# CHECK-NEXT:     Flags [ (0x2)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10110
+# CHECK-NEXT:     Offset: 0x110
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .text (25)
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x20000
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .got (31)
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x10000003)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_MIPS_GPREL (0x10000000)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x30000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .data
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x40000
+# CHECK-NEXT:     Offset: 0x30000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 6
+# CHECK-NEXT:     Name: .bss
+# CHECK-NEXT:     Type: SHT_NOBITS (0x8)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x40000
+# CHECK-NEXT:     Offset: 0x30000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 7
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30000
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 9
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 16
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 8
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30030
+# CHECK-NEXT:     Size: 73
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 9
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30079
+# CHECK-NEXT:     Size: 13
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _gp
+# CHECK-NEXT:     Value: 0x37FF0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other [ (0x2)
+# CHECK-NEXT:       STV_HIDDEN (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Section: .got
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: __start
+# CHECK-NEXT:     Value: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x34
+# CHECK-NEXT:     VirtualAddress: 0x10034
+# CHECK-NEXT:     PhysicalAddress: 0x10034
+# CHECK-NEXT:     FileSize: 192
+# CHECK-NEXT:     MemSize: 192
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 296
+# CHECK-NEXT:     MemSize: 296
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     VirtualAddress: 0x20000
+# CHECK-NEXT:     PhysicalAddress: 0x20000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     VirtualAddress: 0x30000
+# CHECK-NEXT:     PhysicalAddress: 0x30000
+# CHECK-NEXT:     FileSize: 65536
+# CHECK-NEXT:     MemSize: 65536
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_RELRO (0x6474E552)
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     VirtualAddress: 0x30000
+# CHECK-NEXT:     PhysicalAddress: 0x30000
+# CHECK-NEXT:     FileSize: 8
+# CHECK-NEXT:     MemSize: 8
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 1
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_STACK
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:]
diff --git a/test/ELF/basic-ppc.s b/test/ELF/basic-ppc.s
new file mode 100644 (file)
index 0000000..83ace9a
--- /dev/null
@@ -0,0 +1,297 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
+# RUN: ld.lld -discard-all -shared %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# exits with return code 42 on FreeBSD
+.text
+ li      0,1
+ li      3,1
+ sc
+
+// CHECK: Format: ELF32-ppc
+// CHECK-NEXT: Arch: powerpc
+// CHECK-NEXT: AddressSize: 32bit
+// CHECK-NEXT: LoadName:
+// CHECK-NEXT: ElfHeader {
+// CHECK-NEXT:   Ident {
+// CHECK-NEXT:     Magic: (7F 45 4C 46)
+// CHECK-NEXT:     Class: 32-bit (0x1)
+// CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+// CHECK-NEXT:     FileVersion: 1
+// CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+// CHECK-NEXT:     ABIVersion: 0
+// CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Type: SharedObject (0x3)
+// CHECK-NEXT:   Machine: EM_PPC (0x14)
+// CHECK-NEXT:   Version: 1
+// CHECK-NEXT:   Entry: 0x0
+// CHECK-NEXT:   ProgramHeaderOffset: 0x34
+// CHECK-NEXT:   SectionHeaderOffset: 0x209C
+// CHECK-NEXT:   Flags [ (0x0)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   HeaderSize: 52
+// CHECK-NEXT:   ProgramHeaderEntrySize: 32
+// CHECK-NEXT:   ProgramHeaderCount: 7
+// CHECK-NEXT:   SectionHeaderEntrySize: 40
+// CHECK-NEXT:   SectionHeaderCount: 9
+// CHECK-NEXT:   StringTableSectionIndex: 7
+// CHECK-NEXT: }
+// CHECK-NEXT: Sections [
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 0
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Type: SHT_NULL (0x0)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 0
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 1
+// CHECK-NEXT:     Name: .dynsym (1)
+// CHECK-NEXT:     Type: SHT_DYNSYM (0xB)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x114
+// CHECK-NEXT:     Offset: 0x114
+// CHECK-NEXT:     Size: 16
+// CHECK-NEXT:     Link: 3
+// CHECK-NEXT:     Info: 1
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 16
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 2
+// CHECK-NEXT:     Name: .hash (9)
+// CHECK-NEXT:     Type: SHT_HASH (0x5)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x124
+// CHECK-NEXT:     Offset: 0x124
+// CHECK-NEXT:     Size: 16
+// CHECK-NEXT:     Link: 1
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 4
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000001 00000001 00000000 00000000  |................|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 3
+// CHECK-NEXT:     Name: .dynstr (15)
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x134
+// CHECK-NEXT:     Offset: 0x134
+// CHECK-NEXT:     Size: 1
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00                                   |.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 4
+// CHECK-NEXT:     Name: .text (23)
+// CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:       SHF_EXECINSTR (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x1000
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     Size: 12
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 38000001 38600001 44000002           |8...8`..D...|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 5
+// CHECK-NEXT:     Name: .dynamic (29)
+// CHECK-NEXT:     Type: SHT_DYNAMIC (0x6)
+// CHECK-NEXT:     Flags [ (0x3)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:       SHF_WRITE (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x2000
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     Size: 48
+// CHECK-NEXT:     Link: 3
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 8
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000006 00000114 0000000B 00000010  |................|
+// CHECK-NEXT:       0010: 00000005 00000134 0000000A 00000001  |.......4........|
+// CHECK-NEXT:       0020: 00000004 00000124 00000000 00000000  |.......$........|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 6
+// CHECK-NEXT:     Name: .symtab (38)
+// CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2030
+// CHECK-NEXT:     Size: 32
+// CHECK-NEXT:     Link: 8
+// CHECK-NEXT:     Info: 1
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 16
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:       0010: 00000001 00002000 00000000 00020005  |...... .........|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 7
+// CHECK-NEXT:     Name: .shstrtab (46)
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2050
+// CHECK-NEXT:     Size: 64
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 002E6479 6E73796D 002E6861 7368002E  |..dynsym..hash..|
+// CHECK-NEXT:       0010: 64796E73 7472002E 74657874 002E6479  |dynstr..text..dy|
+// CHECK-NEXT:       0020: 6E616D69 63002E73 796D7461 62002E73  |namic..symtab..s|
+// CHECK-NEXT:       0030: 68737472 74616200 2E737472 74616200  |hstrtab..strtab.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 8
+// CHECK-NEXT:     Name: .strtab (56)
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2090
+// CHECK-NEXT:     Size: 1
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 005F4459 4E414D49 4300               |._DYNAMIC.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK-NEXT: ProgramHeaders [
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_PHDR (0x6)
+// CHECK-NEXT:     Offset: 0x34
+// CHECK-NEXT:     VirtualAddress: 0x34
+// CHECK-NEXT:     PhysicalAddress: 0x34
+// CHECK-NEXT:     FileSize: 224
+// CHECK-NEXT:     MemSize: 224
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 309
+// CHECK-NEXT:     MemSize: 309
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     VirtualAddress: 0x1000
+// CHECK-NEXT:     PhysicalAddress: 0x1000
+// CHECK-NEXT:     FileSize: 12
+// CHECK-NEXT:     MemSize: 12
+// CHECK-NEXT:     Flags [ (0x5)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_X (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 48
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_DYNAMIC (0x2)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 48
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_RELRO (0x6474E552)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 48
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 0
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/basic.s b/test/ELF/basic.s
new file mode 100644 (file)
index 0000000..2844933
--- /dev/null
@@ -0,0 +1,230 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_X86_64 (0x3E)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x1070
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 5
+# CHECK-NEXT:   StringTableSectionIndex: 3
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x11000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 16
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1010
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 4
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1040
+# CHECK-NEXT:     Size: 33
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .strtab (25)
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1061
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10040
+# CHECK-NEXT:     PhysicalAddress: 0x10040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x11000
+# CHECK-NEXT:     PhysicalAddress: 0x11000
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# Test for the response file (POSIX quoting style)
+# RUN: echo " -o %t2" > %t.responsefile
+# RUN: ld.lld %t --rsp-quoting=posix @%t.responsefile
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+
+# Test for the response file (Windows quoting style)
+# RUN: echo " c:\blah\foo" > %t.responsefile
+# RUN: not ld.lld --rsp-quoting=windows %t @%t.responsefile 2>&1 | FileCheck \
+# RUN:   %s --check-prefix=WINRSP
+# WINRSP: cannot open c:\blah\foo
+
+# Test for the response file (invalid quoting style)
+# RUN: not ld.lld --rsp-quoting=patatino %t 2>&1 | FileCheck %s \
+# RUN:   --check-prefix=INVRSP
+# INVRSP: invalid response file quoting: patatino
+
+# RUN: not ld.lld %t.foo -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=MISSING %s
+# MISSING: cannot open {{.*}}.foo: {{[Nn]}}o such file or directory
+
+# RUN: not ld.lld -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=NO_INPUT %s
+# NO_INPUT: no input files.
+
+# RUN: not ld.lld %t.no.such.file -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=CANNOT_OPEN %s
+# CANNOT_OPEN: cannot open {{.*}}.no.such.file: {{[Nn]}}o such file or directory
+
+# RUN: not ld.lld %t -o 2>&1 | FileCheck --check-prefix=NO_O_VAL %s
+# NO_O_VAL: missing arg value for "-o", expected 1 argument.
+
+# RUN: not ld.lld --foo 2>&1 | FileCheck --check-prefix=UNKNOWN %s
+# UNKNOWN: unknown argument: --foo
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s
+# DUP: duplicate symbol: _start in {{.*}} and {{.*}}
+
+# RUN: not ld.lld %t -o %t -m wrong_emul 2>&1 | FileCheck --check-prefix=UNKNOWN_EMUL %s
+# UNKNOWN_EMUL: unknown emulation: wrong_emul
+
+# RUN: not ld.lld %t --lto-jobs=0 2>&1 | FileCheck --check-prefix=NOTHREADS %s
+# NOTHREADS: number of threads must be > 0
diff --git a/test/ELF/basic32.s b/test/ELF/basic32.s
new file mode 100644 (file)
index 0000000..44ebe7a
--- /dev/null
@@ -0,0 +1,163 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $1, %eax
+  mov $42, %ebx
+  int $0x80
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 32-bit (0x1)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_386 (0x3)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x11000
+# CHECK-NEXT:   ProgramHeaderOffset: 0x34
+# CHECK-NEXT:   SectionHeaderOffset: 0x1058
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 52
+# CHECK-NEXT:   ProgramHeaderEntrySize: 32
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 40
+# CHECK-NEXT:   SectionHeaderCount: 5
+# CHECK-NEXT:   StringTableSectionIndex: 3
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x11000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100C
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 4
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 16
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x102C
+# CHECK-NEXT:     Size: 33
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .strtab (25)
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x104D
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x34
+# CHECK-NEXT:     VirtualAddress: 0x10034
+# CHECK-NEXT:     PhysicalAddress: 0x10034
+# CHECK-NEXT:     FileSize: 128
+# CHECK-NEXT:     MemSize: 128
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 180
+# CHECK-NEXT:     MemSize: 180
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x11000
+# CHECK-NEXT:     PhysicalAddress: 0x11000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s
new file mode 100644 (file)
index 0000000..fb0bf7b
--- /dev/null
@@ -0,0 +1,290 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld -discard-all %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# exits with return code 42 on linux
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+# generate .toc and .toc1 sections to make sure that the ordering is as
+# intended (.toc before .toc1, and both before .opd).
+.section        ".toc1","aw"
+.quad          22, 37, 89, 47
+
+.section        ".toc","aw"
+.quad          45, 86, 72, 24
+
+.text
+.Lfoo:
+       li      0,1
+       li      3,42
+       sc
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_PPC64 (0x15)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x10020040
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x200C8
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 6
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 9
+# CHECK-NEXT:   StringTableSectionIndex: 7
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text (1)
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10010000
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .got
+# CHECK-NEXT:     Type: SHT_PROGBITS
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       SHF_ALLOC
+# CHECK-NEXT:       SHF_WRITE
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .toc
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:      0000: 00000000 0000002D 00000000 00000056 |.......-.......V|
+# CHECK-NEXT:      0010: 00000000 00000048 00000000 00000018 |.......H........|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .toc1
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020020
+# CHECK-NEXT:     Offset: 0x20020
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 00000000 00000016 00000000 00000025  |...............%|
+# CHECK-NEXT:       0010: 00000000 00000059 00000000 0000002F  |.......Y......./|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .opd
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020040
+# CHECK-NEXT:     Offset: 0x20040
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 00000000 10010000 00000000 10028000 |................|
+# CHECK-NEXT:       0010: 00000000 00000000                   |........|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 6
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20058
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 8
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 7
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20088
+# CHECK-NEXT:     Size: 54
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 8
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x200BE
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 005F7374 61727400                    |._start.|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10000040
+# CHECK-NEXT:     PhysicalAddress: 0x10000040
+# CHECK-NEXT:     FileSize: 336
+# CHECK-NEXT:     MemSize: 336
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x10000000
+# CHECK-NEXT:    PhysicalAddress: 0x10000000
+# CHECK-NEXT:    FileSize: 400
+# CHECK-NEXT:    MemSize: 400
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x10000
+# CHECK-NEXT:    VirtualAddress: 0x10010000
+# CHECK-NEXT:    PhysicalAddress: 0x10010000
+# CHECK-NEXT:    FileSize: 12
+# CHECK-NEXT:    MemSize: 12
+# CHECK-NEXT:    Flags [ (0x5)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_X (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x20000
+# CHECK-NEXT:    VirtualAddress: 0x10020000
+# CHECK-NEXT:    PhysicalAddress: 0x10020000
+# CHECK-NEXT:    FileSize: 88
+# CHECK-NEXT:    MemSize: 88
+# CHECK-NEXT:    Flags [ (0x6)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_RELRO
+# CHECK-NEXT:    Offset: 0x20000
+# CHECK-NEXT:    VirtualAddress: 0x10020000
+# CHECK-NEXT:    PhysicalAddress: 0x10020000
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [ (0x4)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 1
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_STACK (0x6474E551)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [ (0x6)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
diff --git a/test/ELF/bss.s b/test/ELF/bss.s
new file mode 100644 (file)
index 0000000..d0b43ec
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -sections %t2 | FileCheck %s
+// REQUIRES: x86
+
+// Test that bss takes no space on disk.
+
+// CHECK:        Name: .bss
+// CHECK-NEXT:   Type: SHT_NOBITS
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:     SHF_WRITE
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: 0x11000
+// CHECK-NEXT:   Offset: 0x1000
+// CHECK-NEXT:   Size: 4
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment:
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT: }
+
+        .global _start
+_start:
+
+        .bss
+        .zero 4
diff --git a/test/ELF/bsymbolic-undef.s b/test/ELF/bsymbolic-undef.s
new file mode 100644 (file)
index 0000000..6590bbc
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -Bsymbolic %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: undef@ (1)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+call undef@PLT
diff --git a/test/ELF/bsymbolic.s b/test/ELF/bsymbolic.s
new file mode 100644 (file)
index 0000000..d713588
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t0.so
+// RUN: ld.lld -shared -Bsymbolic %t.o -o %t1.so
+// RUN: ld.lld -shared -Bsymbolic-functions %t.o -o %t2.so
+// RUN: llvm-readobj -s %t0.so | FileCheck -check-prefix=NOOPTION %s
+// RUN: llvm-readobj -s %t1.so | FileCheck -check-prefix=SYMBOLIC %s
+// RUN: llvm-readobj -s %t2.so | FileCheck -check-prefix=SYMBOLIC %s
+
+// NOOPTION:     Section {
+// NOOPTION:       Name: .plt
+
+// SYMBOLIC: Section {
+// SYMBOLIC-NOT: Name: .plt
+
+.text
+.globl foo
+.type foo,@function
+foo:
+nop
+
+.globl bar
+.type bar,@function
+bar:
+nop
+
+.globl do
+.type do,@function
+do: 
+callq foo@PLT
+callq bar@PLT
+
+.weak zed
+.protected zed
+.quad zed
diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s
new file mode 100644 (file)
index 0000000..f1eac42
--- /dev/null
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld --build-id %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
+# RUN: ld.lld --build-id=md5 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=MD5 %s
+# RUN: ld.lld --build-id=sha1 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+# RUN: ld.lld --build-id=0x12345678 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=HEX %s
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
+# RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
+
+.globl _start
+_start:
+  nop
+
+.section .note.test, "a", @note
+   .quad 42
+
+# DEFAULT:      Contents of section .note.gnu.build-id:
+# DEFAULT-NEXT: 04000000 08000000 03000000 474e5500  ............GNU.
+# DEFAULT:      Contents of section .note.test:
+
+# MD5:      Contents of section .note.gnu.build-id:
+# MD5-NEXT: 04000000 10000000 03000000 474e5500  ............GNU.
+
+# SHA1:      Contents of section .note.gnu.build-id:
+# SHA1-NEXT: 04000000 14000000 03000000 474e5500  ............GNU.
+
+# HEX:      Contents of section .note.gnu.build-id:
+# HEX-NEXT: 04000000 04000000 03000000 474e5500  ............GNU.
+# HEX-NEXT: 12345678
+
+# NONE-NOT: Contents of section .note.gnu.build-id:
diff --git a/test/ELF/combrelocs.s b/test/ELF/combrelocs.s
new file mode 100644 (file)
index 0000000..5b876ee
--- /dev/null
@@ -0,0 +1,92 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.out
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x2000
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: aaa (1)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x2018
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: aaa (1)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x2010
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: bbb (2)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x2008
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: ccc (3)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x2020
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: ddd (4)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK:      DynamicSection [
+# CHECK-NEXT:   Tag
+# CHECK-NOT:    RELACOUNT
+
+# RUN: ld.lld -z nocombreloc -shared %t.o -o %t.out
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | \
+# RUN:    FileCheck --check-prefix=NOCOMB %s
+
+# NOCOMB:      Relocations [
+# NOCOMB-NEXT:    Section ({{.*}}) .rela.dyn {
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x2000
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: aaa (1)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x2008
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: ccc (3)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x2010
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: bbb (2)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x2018
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: aaa (1)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x2020
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: ddd (4)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:   }
+# NOCOMB-NEXT:  ]
+# NOCOMB:      DynamicSection [
+# NOCOMB-NEXT:   Tag
+# NOCOMB-NOT:    RELACOUNT
+
+.data
+ .quad aaa
+ .quad ccc
+ .quad bbb
+ .quad aaa
+ .quad ddd
diff --git a/test/ELF/comdat.s b/test/ELF/comdat.s
new file mode 100644 (file)
index 0000000..d422ee8
--- /dev/null
@@ -0,0 +1,83 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o
+// RUN: ld.lld -shared %t.o %t.o %t2.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s
+// REQUIRES: x86
+
+        .section       .text2,"axG",@progbits,foo,comdat,unique,0
+foo:
+        nop
+
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: foo:
+// CHECK-NEXT:   1000: {{.*}}  nop
+// CHECK-NOT: nop
+
+        .section bar, "ax"
+        call foo
+
+// CHECK: Disassembly of section bar:
+// CHECK-NEXT: bar:
+// 0x1000 - 0x1001 - 5 = -6
+// 0      - 0x1006 - 5 = -4107
+// CHECK-NEXT:   1001: {{.*}}  callq  -6
+// CHECK-NEXT:   1006: {{.*}}  callq  -4107
+
+        .section .text3,"axG",@progbits,zed,comdat,unique,0
+
+
+// READ:      Name: .text2
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Name: .text3
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Symbols [
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name:  (0)
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: foo
+// READ-NEXT:     Value
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: .text
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: _DYNAMIC
+// READ-NEXT:     Value: 0x2000
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other [ (0x2)
+// READ-NEXT:       STV_HIDDEN
+// READ-NEXT:     ]
+// READ-NEXT:     Section: .dynamic
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: abc
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Global
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT: ]
diff --git a/test/ELF/common.s b/test/ELF/common.s
new file mode 100644 (file)
index 0000000..f16f948
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2
+// RUN: ld.lld %t %t2 -o %t3
+// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 22
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Name: sym1
+// CHECK-NEXT: Value: 0x11004
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym2
+// CHECK-NEXT: Value: 0x1100C
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym3
+// CHECK-NEXT: Value: 0x11014
+// CHECK-NEXT: Size: 2
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym4
+// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+
+.globl _start
+_start:
+
+.comm sym1,4,4
+.comm sym2,8,4
+.comm sym3,2,2
+.comm sym4,4,2
diff --git a/test/ELF/compressed-debug-input.s b/test/ELF/compressed-debug-input.s
new file mode 100644 (file)
index 0000000..7339833
--- /dev/null
@@ -0,0 +1,61 @@
+# REQUIRES: zlib
+
+# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=COMPRESSED %s
+
+# COMPRESSED:      Section {
+# COMPRESSED:        Index: 2
+# COMPRESSED:        Name: .debug_str
+# COMPRESSED-NEXT:   Type: SHT_PROGBITS
+# COMPRESSED-NEXT:   Flags [
+# COMPRESSED-NEXT:     SHF_COMPRESSED (0x800)
+# COMPRESSED-NEXT:     SHF_MERGE (0x10)
+# COMPRESSED-NEXT:     SHF_STRINGS (0x20)
+# COMPRESSED-NEXT:   ]
+# COMPRESSED-NEXT:   Address:
+# COMPRESSED-NEXT:   Offset:
+# COMPRESSED-NEXT:   Size: 66
+# COMPRESSED-NEXT:   Link:
+# COMPRESSED-NEXT:   Info:
+# COMPRESSED-NEXT:   AddressAlignment: 1
+# COMPRESSED-NEXT:   EntrySize: 1
+# COMPRESSED-NEXT: }
+
+# RUN: ld.lld %t -o %t.so -shared
+# RUN: llvm-readobj -sections -section-data %t.so | FileCheck -check-prefix=UNCOMPRESSED %s
+
+# UNCOMPRESSED:      Section {
+# UNCOMPRESSED:        Index: 6
+# UNCOMPRESSED:        Name: .debug_str
+# UNCOMPRESSED-NEXT:   Type: SHT_PROGBITS
+# UNCOMPRESSED-NEXT:   Flags [
+# UNCOMPRESSED-NEXT:     SHF_MERGE (0x10)
+# UNCOMPRESSED-NEXT:     SHF_STRINGS (0x20)
+# UNCOMPRESSED-NEXT:   ]
+# UNCOMPRESSED-NEXT:   Address: 0x0
+# UNCOMPRESSED-NEXT:   Offset: 0x1060
+# UNCOMPRESSED-NEXT:   Size: 69
+# UNCOMPRESSED-NEXT:   Link: 0
+# UNCOMPRESSED-NEXT:   Info: 0
+# UNCOMPRESSED-NEXT:   AddressAlignment: 1
+# UNCOMPRESSED-NEXT:   EntrySize: 1
+# UNCOMPRESSED-NEXT:   SectionData (
+# UNCOMPRESSED-NEXT:     0000: 73686F72 7420756E 7369676E 65642069  |short unsigned i|
+# UNCOMPRESSED-NEXT:     0010: 6E740075 6E736967 6E656420 696E7400  |nt.unsigned int.|
+# UNCOMPRESSED-NEXT:     0020: 6C6F6E67 20756E73 69676E65 6420696E  |long unsigned in|
+# UNCOMPRESSED-NEXT:     0030: 74006368 61720075 6E736967 6E656420  |t.char.unsigned |
+# UNCOMPRESSED-NEXT:     0040: 63686172 00                          |char.|
+# UNCOMPRESSED-NEXT:   )
+# UNCOMPRESSED-NEXT: }
+
+.section .debug_str,"MS",@progbits,1
+.LASF2:
+ .string "short unsigned int"
+.LASF3:
+ .string "unsigned int"
+.LASF0:
+ .string "long unsigned int"
+.LASF8:
+ .string "char"
+.LASF1:
+ .string "unsigned char"
diff --git a/test/ELF/conflict.s b/test/ELF/conflict.s
new file mode 100644 (file)
index 0000000..7598eea
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86, shell
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: not ld.lld %t1.o %t1.o -o %t2 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+
+# DEMANGLE:    duplicate symbol: mul(double, double) in
+# DEMANGLE:    duplicate symbol: foo in
+
+# RUN: not ld.lld %t1.o %t1.o -o %t2 --no-demangle 2>&1 | \
+# RUN:   FileCheck -check-prefix=NO_DEMANGLE %s
+
+# NO_DEMANGLE: duplicate symbol: _Z3muldd in
+# NO_DEMANGLE: duplicate symbol: foo in
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/conflict.s -o %t2.o
+# RUN: llvm-ar rcs %t3.a %t2.o
+# RUN: not ld.lld %t1.o %t3.a -u baz -o %t2 2>&1 | FileCheck -check-prefix=ARCHIVE %s
+
+# ARCHIVE: duplicate symbol: foo in {{.*}}1.o and {{.*}}3.a({{.*}}2.o)
+
+.globl _Z3muldd, foo
+_Z3muldd:
+foo:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/copy-errors.s b/test/ELF/copy-errors.s
new file mode 100644 (file)
index 0000000..9d8b72d
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+.global _start
+_start:
+
+
+call bar
+// CHECK: cannot preempt symbol
+
+call zed
+// CHECK: symbol is missing type
diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s
new file mode 100644 (file)
index 0000000..4114d95
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o
+// RUN: ld.lld -shared %t1.o -o %t1.so
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s
+
+
+.quad foo
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against readonly segment
diff --git a/test/ELF/copy-rel-corrupted.s b/test/ELF/copy-rel-corrupted.s
new file mode 100644 (file)
index 0000000..a3f72f7
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-corrupted.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t.exe 2>&1 | FileCheck %s
+
+// CHECK: cannot create a copy relocation for x
+
+.global _start
+_start:
+        call x
diff --git a/test/ELF/copy-rel-pie-error.s b/test/ELF/copy-rel-pie-error.s
new file mode 100644 (file)
index 0000000..1f42702
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t.exe -pie 2>&1 | FileCheck %s
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against readonly segment
+// CHECK: can't create dynamic relocation R_X86_64_64 against readonly segment
+
+.global _start
+_start:
+        .quad bar
+        .quad foo
diff --git a/test/ELF/copy-rel-pie.s b/test/ELF/copy-rel-pie.s
new file mode 100644 (file)
index 0000000..be7d5ac
--- /dev/null
@@ -0,0 +1,44 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe -pie
+// RUN: llvm-readobj -s -r %t.exe | FileCheck %s
+// RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s
+
+.global _start
+_start:
+        call bar
+        call foo
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1010
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x3020
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x3020 R_X86_64_COPY foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rela.plt {
+// CHECK-NEXT:     0x3018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// (0x1010 + 0x10) - 0x1005 = 27
+// 0x3020          - 0x100a = 8214
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:     1000:       e8 1b 00 00 00  callq   27
+// DISASM-NEXT:     1005:       e8 16 20 00 00  callq   8214 <foo>
diff --git a/test/ELF/ctors_dtors_priority.s b/test/ELF/ctors_dtors_priority.s
new file mode 100644 (file)
index 0000000..10d6471
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority1.s -o %t-crtbegin.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority2.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority3.s -o %t-crtend.o
+// RUN: ld.lld %t1 %t2 %t-crtend.o %t-crtbegin.o -o %t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  nop
+
+.section .ctors, "aw", @progbits
+  .byte 1
+.section .ctors.100, "aw", @progbits
+  .byte 2
+.section .ctors.005, "aw", @progbits
+  .byte 3
+.section .ctors, "aw", @progbits
+  .byte 4
+.section .ctors, "aw", @progbits
+  .byte 5
+
+.section .dtors, "aw", @progbits
+  .byte 0x11
+.section .dtors.100, "aw", @progbits
+  .byte 0x12
+.section .dtors.005, "aw", @progbits
+  .byte 0x13
+.section .dtors, "aw", @progbits
+  .byte 0x14
+.section .dtors, "aw", @progbits
+  .byte 0x15
+
+// CHECK:      Contents of section .ctors:
+// CHECK-NEXT: a1010405 b10302c1
+// CHECK:      Contents of section .dtors:
+// CHECK-NEXT: a2111415 b21312c2
diff --git a/test/ELF/default-output.s b/test/ELF/default-output.s
new file mode 100644 (file)
index 0000000..c0766ac
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# Verify that default output filename is a.out.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: mkdir -p %t.dir
+# RUN: cd %t.dir
+# RUN: rm -f a.out
+# RUN: not llvm-readobj a.out > /dev/null 2>&1
+# RUN: ld.lld %t
+# RUN: llvm-readobj a.out > /dev/null 2>&1
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/discard-locals.s b/test/ELF/discard-locals.s
new file mode 100644 (file)
index 0000000..073e891
--- /dev/null
@@ -0,0 +1,50 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t
+// RUN: ld.lld -discard-locals %t -o %t2
+// RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.text
+.Lmyvar:
+.Lmyothervar:
+
+// CHECK:   Section {
+// CHECK:     Name: .strtab
+// CHECK-NEXT:     Type: SHT_STRTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 005F7374 61727400                    |._start.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECk-NEXT: ]
diff --git a/test/ELF/discard-merge-locals.s b/test/ELF/discard-merge-locals.s
new file mode 100644 (file)
index 0000000..01b4d33
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+       leaq    .L.str(%rip), %rdi
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+       .asciz  "foobar"
+
+// Test that the .L symbol is omitted
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x2000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/discard-merge-unnamed.s b/test/ELF/discard-merge-unnamed.s
new file mode 100644 (file)
index 0000000..be174f2
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: ld.lld %p/Inputs/discard-merge-unnamed.o -o %t2 -shared
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+
+// Test that the unnamed symbol is SHF_MERGE is omitted.
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x2000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/discard-none.s b/test/ELF/discard-none.s
new file mode 100644 (file)
index 0000000..e3a7a20
--- /dev/null
@@ -0,0 +1,54 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t
+// RUN: ld.lld -discard-none -shared %t -o %t2
+// RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+.text
+.Lmyvar:
+.Lmyothervar:
+
+// CHECK:   Section {
+// CHECK:     Name: .strtab
+// CHECK-NEXT:     Type: SHT_STRTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 002E4C6D 796F7468 65727661 72002E4C  |..Lmyothervar..L|
+// CHECK-NEXT:       0010: 6D797661 72005F44 594E414D 494300    |myvar._DYNAMIC.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+
+// CHECK:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: .Lmyothervar
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: .Lmyvar
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
diff --git a/test/ELF/dont-export-hidden.s b/test/ELF/dont-export-hidden.s
new file mode 100644 (file)
index 0000000..8819a6e
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %p/Inputs/shared.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld %t2.o %t.so -o %t.exe
+// RUN: llvm-readobj --dyn-symbols %t.exe | FileCheck %s
+
+        .global _start
+_start:
+        .global bar
+        .hidden bar
+bar:
+
+        .global bar2
+bar2:
+
+        .global foo
+foo:
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @ (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar2
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
diff --git a/test/ELF/driver.test b/test/ELF/driver.test
new file mode 100644 (file)
index 0000000..95e2100
--- /dev/null
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+
+# RUN: not ld.lld --unknown1 --unknown2 -m foo /no/such/file -lnosuchlib \
+# RUN:   2>&1 | FileCheck -check-prefix=UNKNOWN %s
+
+# UNKNOWN: unknown argument: --unknown1
+# UNKNOWN: unknown argument: --unknown2
+# UNKNOWN: unknown emulation: foo
+# UNKNOWN: cannot open /no/such/file
+# UNKNOWN: unable to find library -lnosuchlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t -o /no/such/file 2>&1 | FileCheck -check-prefix=MISSING %s
+# MISSING: failed to open /no/such/file
+
+# RUN: ld.lld --help 2>&1 | FileCheck -check-prefix=HELP %s
+# HELP: USAGE:
+
+# RUN: ld.lld --version 2>&1 | FileCheck -check-prefix=VERSION %s
+# VERSION: LLD
+
+## Attempt to link DSO with -r
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: not ld.lld -r %t.so %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: attempted static link of dynamic object
+
+## Attempt to use -r and -shared together
+# RUN: not ld.lld -r -shared %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: -r and -shared may not be used together
+
+## Attempt to use -r and --gc-sections together
+# RUN: not ld.lld -r --gc-sections %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: -r and --gc-sections may not be used together
+
+## Attempt to use -r and --icf together
+# RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: -r and --icf may not be used together
+
+## Attempt to use -r and -pie together
+# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: -r and -pie may not be used together
+
+## Attempt to use -shared and -pie together
+# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: -shared and -pie may not be used together
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s
new file mode 100644 (file)
index 0000000..a1d8d77
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld -z now -z nodelete -z origin -Bsymbolic %t %t.so -o %t1
+# RUN: ld.lld %t %t.so -o %t2
+# RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s
+# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+# FLAGS: DynamicSection [
+# FLAGS:   0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
+# FLAGS:   0x000000006FFFFFFB FLAGS_1 NOW NODELETE ORIGIN
+# FLAGS: ]
+
+# CHECK: DynamicSection [
+# CHECK-NOT:   0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
+# CHECK-NOT:   0x000000006FFFFFFB FLAGS_1 NOW NODELETE ORIGIN
+# CHECK: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/dt_tags.s b/test/ELF/dt_tags.s
new file mode 100644 (file)
index 0000000..f2759d6
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld %t %t.so -o %t.exe
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=EXE %s
+
+# EXE: DynamicSection [
+# EXE:   0x0000000000000015 DEBUG                0x0
+# EXE: ]
+
+# DSO: DynamicSection [
+# DSO-NOT:   0x0000000000000015 DEBUG                0x0
+# DSO: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/duplicate-internal.s b/test/ELF/duplicate-internal.s
new file mode 100644 (file)
index 0000000..d1ccf53
--- /dev/null
@@ -0,0 +1,11 @@
+# Should print an expected message in case of conflict with an internally generated symbol.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: duplicate symbol: _gp in {{.*}} and (internal)
+
+# REQUIRES: mips
+
+  .globl  _gp
+_gp = 0
diff --git a/test/ELF/duplicated-plt-entry.s b/test/ELF/duplicated-plt-entry.s
new file mode 100644 (file)
index 0000000..4644bed
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/duplicated-plt-entry.s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t2.so -shared
+
+// RUN: llvm-readobj -r %t2.so | FileCheck %s
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:       R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+callq bar@PLT
+callq bar@PLT
diff --git a/test/ELF/dynamic-list.s b/test/ELF/dynamic-list.s
new file mode 100644 (file)
index 0000000..5e257b3
--- /dev/null
@@ -0,0 +1,110 @@
+## There is some bad quoting interaction between lit's internal shell, which is
+## implemented in Python, and the Cygwin implementations of the Unix utilities.
+## Avoid running these tests on Windows for now by requiring a real shell.
+
+# REQUIRES: shell
+
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check exporting only one symbol.
+# RUN: echo "{ foo1; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+## And now using quoted strings (the output is the same since it does
+## use any wildcard character).
+# RUN: echo "{ \"foo1\"; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+## And now using --export-dynamic-symbol.
+# RUN: ld.lld --export-dynamic-symbol foo1 %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+# RUN: ld.lld --export-dynamic-symbol=foo1 %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1@ (1)
+# CHECK-NEXT:     Value: 0x11000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text (0x4)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ] 
+
+
+## Now export all the foo1, foo2, and foo31 symbols
+# RUN: echo "{ foo1; foo2; foo31; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2:      DynamicSymbols [
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: @ (0)
+# CHECK2-NEXT:     Value: 0x0
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Local
+# CHECK2-NEXT:     Type: None
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: Undefined
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo1@ (1)
+# CHECK2-NEXT:     Value: 0x11000
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo2@ (6)
+# CHECK2-NEXT:     Value: 0x11001
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo31@ (11)
+# CHECK2-NEXT:     Value: 0x11002
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT: ] 
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo31
+foo31:
+  ret
+
+.globl _start
+_start:
+  retq
diff --git a/test/ELF/dynamic-reloc-in-ro.s b/test/ELF/dynamic-reloc-in-ro.s
new file mode 100644 (file)
index 0000000..2ef36f6
--- /dev/null
@@ -0,0 +1,8 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+foo:
+.quad foo
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against readonly segment
diff --git a/test/ELF/dynamic-reloc-index.s b/test/ELF/dynamic-reloc-index.s
new file mode 100644 (file)
index 0000000..2d38c01
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+// We used to record the wrong symbol index for this test
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x13018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .global foobar
+foobar:
+        .global zedx
+zedx:
+        .global _start
+_start:
+.quad bar
diff --git a/test/ELF/dynamic-reloc-weak.s b/test/ELF/dynamic-reloc-weak.s
new file mode 100644 (file)
index 0000000..b4da2e5
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc-weak.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -r  %t | FileCheck %s
+// REQUIRES: x86
+
+        .globl _start
+_start:
+        .type sym1,@function
+        .weak sym1
+        .long sym1@gotpcrel
+
+        .type sym2,@function
+        .weak sym2
+        .long sym2@plt
+
+        .type sym3,@function
+        .weak sym3
+        .quad sym3
+
+        .type sym4,@function
+        .weak sym4
+        .quad sym4
+
+// Test that we produce dynamic relocation for every weak undefined symbol
+// we found.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_GLOB_DAT sym1 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_JUMP_SLOT sym2 0x0
+// CHECK-NEXT:     0x{{.*}} R_X86_64_JUMP_SLOT sym3 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s
new file mode 100644 (file)
index 0000000..5e23ba9
--- /dev/null
@@ -0,0 +1,65 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc.s -o %t3.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t3.o %t2.so -o %t
+// RUN: llvm-readobj -dynamic-table -r --expand-relocs -s %t | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Index: 1
+// CHECK-NEXT: Name: .dynsym
+
+// CHECK:      Name: .rela.plt
+// CHECK-NEXT: Type: SHT_RELA
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELAADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELASIZE:.*]]
+// CHECK-NEXT: Link: 1
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 24
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11000
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x13018
+// CHECK-NEXT:       Type: R_X86_64_JUMP_SLOT
+// CHECK-NEXT:       Symbol: bar
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: DynamicSection [
+// CHECK-NEXT:  Tag                Type                 Name/Value
+// CHECK-NEXT:  0x0000000000000001 NEEDED               SharedLibrary ({{.*}}2.so)
+// CHECK-NEXT:  0x0000000000000017 JMPREL
+// CHECK-NEXT:  0x0000000000000002 PLTRELSZ             24 (bytes)
+// CHECK-NEXT:  0x0000000000000003 PLTGOT
+// CHECK-NEXT:  0x0000000000000014 PLTREL               RELA
+// CHECK-NEXT:  0x0000000000000006 SYMTAB
+// CHECK-NEXT:  0x000000000000000B SYMENT               24 (bytes)
+// CHECK-NEXT:  0x0000000000000005 STRTAB
+// CHECK-NEXT:  0x000000000000000A STRSZ
+// CHECK-NEXT:  0x0000000000000004 HASH
+// CHECK-NEXT:  0x0000000000000015 DEBUG                0x0
+// CHECK-NEXT:  0x0000000000000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+.quad bar + 0x42
+.weak foo
+.quad foo
+call main
diff --git a/test/ELF/dynamic.s b/test/ELF/dynamic.s
new file mode 100644 (file)
index 0000000..2efd299
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t.o
+
+## Check that _DYNAMIC symbol is created when creating dynamic output,
+## and has hidden visibility and address equal to .dynamic section.
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -sections -symbols %t.so | FileCheck %s
+# CHECK:      Section {
+# CHECK:        Index: 5
+# CHECK:        Name: .dynamic
+# CHECK-NEXT:   Type: SHT_DYNAMIC
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x[[ADDR:.*]]
+# CHECK-NEXT:   Offset: 0x1000
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK:      Symbols [
+# CHECK:        Symbol {
+# CHECK:          Name: _DYNAMIC
+# CHECK-NEXT:     Value: 0x[[ADDR]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other [ (0x2)
+# CHECK-NEXT:       STV_HIDDEN
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Section: .dynamic
+# CHECK-NEXT:   }
+
+# RUN: ld.lld %t.o -o %t.o
+# RUN: llvm-readobj -sections -symbols %t.o | FileCheck -check-prefix=NODYN %s
+# NODYN:    Symbols [
+# NODYN-NOT: Name: _DYNAMIC
+# NODYN:    ]
+
+.globl _start
+_start:
diff --git a/test/ELF/dynsym-pie.s b/test/ELF/dynsym-pie.s
new file mode 100644 (file)
index 0000000..9d3a9ff
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld -pie %t -o %t.out
+# RUN: llvm-readobj -t -dyn-symbols %t.out | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: @
+# CHECK-NEXT:    Value: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Undefined
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
+
+.text
+.globl _start
+_start:
+
+.global default
+default:
+
+.global protected
+protected:
+
+.global hidden
+hidden:
+
+.global internal
+internal:
+
+.global protected_with_hidden
+.protected
+protected_with_hidden:
diff --git a/test/ELF/edata-etext.s b/test/ELF/edata-etext.s
new file mode 100644 (file)
index 0000000..e0538d6
--- /dev/null
@@ -0,0 +1,117 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -sections -symbols %t | FileCheck %s
+
+## This checks that:
+## 1) Address of _etext is the first location after the last read-only loadable segment.
+## 2) Address of _edata points to the end of the last non SHT_NOBITS section.
+##    That is how gold/bfd do. At the same time specs says: "If the address of _edata is
+##    greater than the address of _etext, the address of _end is same as the address
+##    of _edata." (https://docs.oracle.com/cd/E53394_01/html/E54766/u-etext-3c.html).
+## 3) Address of _end is different from _edata because of 2.
+# CHECK:      Section {
+# CHECK:         Index: 1
+# CHECK:         Name: .text
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_EXECINSTR
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x11000
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    Size: 1
+# CHECK-NEXT:    Link:
+# CHECK-NEXT:    Info:
+# CHECK-NEXT:    AddressAlignment:
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 2
+# CHECK-NEXT:    Name: .data
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x12000
+# CHECK-NEXT:    Offset: 0x2000
+# CHECK-NEXT:    Size: 2
+# CHECK-NEXT:    Link:
+# CHECK-NEXT:    Info:
+# CHECK-NEXT:    AddressAlignment:
+# CHECK-NEXT:    EntrySize:
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 3
+# CHECK-NEXT:    Name: .bss
+# CHECK-NEXT:    Type: SHT_NOBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x12004
+# CHECK-NEXT:    Offset: 0x2002
+# CHECK-NEXT:    Size: 6
+# CHECK-NEXT:    Link:
+# CHECK-NEXT:    Info:
+# CHECK-NEXT:    AddressAlignment:
+# CHECK-NEXT:    EntrySize:
+# CHECK-NEXT:  }
+# CHECK:      Symbols [
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name:
+# CHECK-NEXT:    Value: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Undefined
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: _start
+# CHECK-NEXT:    Value: 0x11000
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: .text
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: _edata
+# CHECK-NEXT:    Value: 0x12002
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Absolute
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: _end
+# CHECK-NEXT:    Value: 0x1200A
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Absolute
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: _etext
+# CHECK-NEXT:    Value: 0x11001
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Absolute
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
+
+.global _start,_end,_etext,_edata
+.text
+_start:
+  nop
+.data
+  .word 1
+.bss
+  .align 4
+  .space 6
diff --git a/test/ELF/eh-align-cie.s b/test/ELF/eh-align-cie.s
new file mode 100644 (file)
index 0000000..e85cbd2
--- /dev/null
@@ -0,0 +1,57 @@
+// REQUIRES: x86
+
+       .cfi_startproc
+       .cfi_personality 0x1b, bar
+       .cfi_endproc
+
+.global bar
+.hidden bar
+bar:
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s
+
+// Check the size of the CIE (0x18 + 4) an FDE (0x10 + 4)
+// OBJ: Name: .eh_frame
+// OBJ-NEXT:    Type:
+// OBJ-NEXT:    Flags [
+// OBJ-NEXT:      SHF_ALLOC
+// OBJ-NEXT:    ]
+// OBJ-NEXT:    Address:
+// OBJ-NEXT:    Offset:
+// OBJ-NEXT:    Size:
+// OBJ-NEXT:    Link:
+// OBJ-NEXT:    Info:
+// OBJ-NEXT:    AddressAlignment:
+// OBJ-NEXT:    EntrySize:
+// OBJ-NEXT:    SectionData (
+// OBJ-NEXT:      0000: 18000000 00000000 017A5052 00017810
+// OBJ-NEXT:      0010: 061B0000 00001B0C 07089001 10000000
+// OBJ-NEXT:      0020: 20000000 00000000 00000000 00000000
+// OBJ-NEXT:    )
+
+
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+// Check that the size of the CIE was changed to (0x1C + 4) and the FDE one was
+// changed to (0x14 + 4)
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Flags
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 1C000000 00000000 017A5052 00017810
+// CHECK-NEXT:   0010: 061B260E 00001B0C 07089001 00000000
+// CHECK-NEXT:   0020: 14000000 24000000 100E0000 00000000
+// CHECK-NEXT:   0030: 00000000 00000000
+// CHECK-NEXT: )
diff --git a/test/ELF/eh-frame-dyn-rel.s b/test/ELF/eh-frame-dyn-rel.s
new file mode 100644 (file)
index 0000000..62d5695
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o %t.o -o %t -shared 2>&1 | FileCheck %s
+
+        .section        bar,"axG",@progbits,foo,comdat
+        .cfi_startproc
+        .cfi_personality 0x8c, foo
+        .cfi_endproc
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against readonly segment
diff --git a/test/ELF/eh-frame-gc.s b/test/ELF/eh-frame-gc.s
new file mode 100644 (file)
index 0000000..b2e21f4
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: ld.lld -shared --gc-sections %t.o -o %t
+# RUN: llvm-readobj  -s %t | FileCheck %s
+
+## Check that section containing personality is
+## not garbage collected.
+# CHECK: Sections [
+# CHECK: Name: .test_personality_section
+
+.text
+.globl foo
+.type foo,@function
+foo:
+ .cfi_startproc
+ .cfi_personality 155, DW.ref.__gxx_personality_v0
+ .cfi_endproc
+
+.section .test_personality_section
+DW.ref.__gxx_personality_v0:
diff --git a/test/ELF/eh-frame-hdr-abs-fde.s b/test/ELF/eh-frame-hdr-abs-fde.s
new file mode 100644 (file)
index 0000000..37705d6
--- /dev/null
@@ -0,0 +1,33 @@
+# Check reading PC values of FDEs and writing lookup table in the .eh_frame_hdr
+# if CIE augmentation string has 'L' token and PC values are encoded using
+# absolute (not relative) format.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr %t.o -o %t
+# RUN: llvm-objdump -s -dwarf=frames %t | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .eh_frame_hdr:
+# CHECK-NEXT:  10178 011b033b ffffffcc 00000001 0000fe88
+#                                               ^-- 0x20000 - 0x10178
+#                                                   .text   - .eh_frame_hdr
+# CHECK-NEXT:  10188 ffffffe8
+# CHECK-NEXT: Contents of section .text:
+# CHECK-NEXT:  20000 00000000
+
+# CHECK: Augmentation:          "zLR"
+# CHECK: Augmentation data:     00 0B
+#                                  ^-- DW_EH_PE_udata4 | DW_EH_PE_signed
+
+       .text
+  .globl __start
+__start:
+       .cfi_startproc
+  .cfi_lsda 0, _ex
+  nop
+       .cfi_endproc
+
+  .data
+_ex:
+  .word 0
diff --git a/test/ELF/eh-frame-hdr-augmentation.s b/test/ELF/eh-frame-hdr-augmentation.s
new file mode 100644 (file)
index 0000000..91e6a9c
--- /dev/null
@@ -0,0 +1,38 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t -shared
+// RUN: llvm-objdump --dwarf=frames %t | FileCheck %s
+
+// CHECK: .eh_frame contents:
+
+// CHECK:      00000000 0000001c ffffffff CIE
+// CHECK-NEXT:   Version:                       1
+// CHECK-NEXT:   Augmentation:             "zPLR"
+// CHECK-NEXT:   Code alignment factor: 1
+// CHECK-NEXT:   Data alignment factor: -8
+// CHECK-NEXT:   Return address column: 16
+// CHECK-NEXT:   Augmentation data:
+
+// CHECK:      DW_CFA_def_cfa:  reg7 +8
+// CHECK-NEXT: DW_CFA_offset:   reg16 -8
+// CHECK-NEXT: DW_CFA_nop:
+// CHECK-NEXT: DW_CFA_nop:
+
+// CHECK:      00000020 00000014 00000024 FDE cie=00000024 pc=00000dd8...00000dd8
+// CHECK-NEXT:   DW_CFA_nop:
+// CHECK-NEXT:   DW_CFA_nop:
+// CHECK-NEXT:   DW_CFA_nop:
+
+        .cfi_startproc
+        .cfi_personality 0x9b, g
+        .cfi_lsda 0x1b, h
+        .cfi_endproc
+
+        .global g
+        .hidden g
+g:
+
+        .global h
+        .hidden h
+h:
+
diff --git a/test/ELF/eh-frame-hdr-icf.s b/test/ELF/eh-frame-hdr-icf.s
new file mode 100644 (file)
index 0000000..2e7b335
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --eh-frame-hdr
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .eh_frame_hdr:
+# CHECK-NEXT: 101a0 011b033b b4ffffff 01000000 600e0000
+#                                     ^ FDE count
+# CHECK-NEXT: 101b0 d0ffffff 00000000 00000000
+#                   ^ FDE for f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  .cfi_startproc
+  ret
+  .cfi_endproc
+
+.section .text.f2, "ax"
+f2:
+  .cfi_startproc
+  ret
+  .cfi_endproc
diff --git a/test/ELF/eh-frame-hdr-no-out.s b/test/ELF/eh-frame-hdr-no-out.s
new file mode 100644 (file)
index 0000000..edbafad
--- /dev/null
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: not ld.lld --eh-frame-hdr %p/Inputs/invalid-cie-version2.elf -o %t >& %t.log
+// RUN: FileCheck %s < %t.log
+
+// invalid-cie-version2.elf contains unsupported version of CIE = 2.
+// CHECK: FDE version 1 or 3 expected, but got 2
diff --git a/test/ELF/eh-frame-hdr-no-out2.s b/test/ELF/eh-frame-hdr-no-out2.s
new file mode 100644 (file)
index 0000000..0eeb0ea
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -s -program-headers %t | FileCheck %s --check-prefix=NOHDR
+
+.section foo,"ax",@progbits
+ nop
+
+.text
+.globl _start
+_start:
+
+// There is no .eh_frame section,
+// therefore .eh_frame_hdr also not created.
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
new file mode 100644 (file)
index 0000000..16fb49a
--- /dev/null
@@ -0,0 +1,127 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=NOHDR
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=HDR
+// RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=HDRDISASM
+
+.section foo,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.text
+.globl _start
+_start:
+
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME
+
+//HDRDISASM:      Disassembly of section foo:
+//HDRDISASM-NEXT: foo:
+//HDRDISASM-NEXT:    11000: 90 nop
+//HDRDISASM-NEXT: Disassembly of section bar:
+//HDRDISASM-NEXT: bar:
+//HDRDISASM-NEXT:    11001: 90 nop
+//HDRDISASM-NEXT: Disassembly of section dah:
+//HDRDISASM-NEXT: dah:
+//HDRDISASM-NEXT:    11002: 90 nop
+
+// HDR:       Sections [
+// HDR:        Section {
+// HDR:        Index: 1
+// HDR-NEXT:    Name: .eh_frame
+// HDR-NEXT:    Type: SHT_PROGBITS
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x10158
+// HDR-NEXT:    Offset: 0x158
+// HDR-NEXT:    Size: 96
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 8
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 14000000 00000000 017A5200 01781001  |
+// HDR-NEXT:      0010: 1B0C0708 90010000 14000000 1C000000  |
+// HDR-NEXT:      0020: 880E0000 01000000 00000000 00000000  |
+// HDR-NEXT:      0030: 14000000 34000000 710E0000 01000000  |
+// HDR-NEXT:      0040: 00000000 00000000 14000000 4C000000  |
+// HDR-NEXT:      0050: 5A0E0000 01000000 00000000 00000000  |
+//            CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
+//            FDE(1): 14000000 1C000000 880E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x880E0000) = 0x10158 + 0x0020 = 0x10178
+//                    The starting address to which this FDE applies = 0xE88 + 0x10178 = 0x11000
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(2): 14000000 34000000 710E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x710E0000) = 0x10158 + 0x0038 = 0x10190
+//                    The starting address to which this FDE applies = 0xE71 + 0x10190 = 0x11001
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(3): 14000000 4C000000 5A0E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x5A0E0000) = 0x10158 + 0x0050 = 0x101A8
+//                    The starting address to which this FDE applies = 0xE5A + 0x101A8 = 0x11002
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+// HDR-NEXT:    )
+// HDR-NEXT:  }
+// HDR-NEXT:  Section {
+// HDR-NEXT:    Index: 2
+// HDR-NEXT:    Name: .eh_frame_hdr
+// HDR-NEXT:    Type: SHT_PROGBITS
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x101B8
+// HDR-NEXT:    Offset: 0x1B8
+// HDR-NEXT:    Size: 36
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 1
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 011B033B 9CFFFFFF 03000000 480E0000  |
+// HDR-NEXT:      0010: B8FFFFFF 490E0000 D0FFFFFF 4A0E0000  |
+// HDR-NEXT:      0020: E8FFFFFF                             |
+//                Header (always 4 bytes): 0x011B033B
+//                   9CFFFFFF = .eh_frame(0x10158) - .eh_frame_hdr(0x101B8) - 4
+//                   03000000 = 3 = the number of FDE pointers in the table.
+//                Entry(1): 480E0000 B8FFFFFF
+//                   480E0000 = 0x11000 - .eh_frame_hdr(0x101B8) = 0xE48
+//                   B8FFFFFF = address of FDE(1) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 - 0x101B8 = 0xFFFFFFB8
+//                Entry(2): 490E0000 D0FFFFFF
+//                   490E0000 = 0x11001 - .eh_frame_hdr(0x101B8) = 0xE49
+//                   D0FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFD0
+//                Entry(3): 4A0E0000 E8FFFFFF
+//                   4A0E0000 = 0x11002 - .eh_frame_hdr(0x101B8) = 0xE4A
+//                   E8FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFE8
+// HDR-NEXT:    )
+// HDR-NEXT:  }
+// HDR:     ProgramHeaders [
+// HDR:      ProgramHeader {
+// HDR:       Type: PT_GNU_EH_FRAME
+// HDR-NEXT:   Offset: 0x1B8
+// HDR-NEXT:   VirtualAddress: 0x101B8
+// HDR-NEXT:   PhysicalAddress: 0x101B8
+// HDR-NEXT:   FileSize: 36
+// HDR-NEXT:   MemSize: 36
+// HDR-NEXT:   Flags [
+// HDR-NEXT:     PF_R
+// HDR-NEXT:   ]
+// HDR-NEXT:   Alignment: 1
+// HDR-NEXT: }
diff --git a/test/ELF/eh-frame-marker.s b/test/ELF/eh-frame-marker.s
new file mode 100644 (file)
index 0000000..a5de2a7
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared
+// We used to crash on this.
+        .section .eh_frame
+foo:
+        .long 0
diff --git a/test/ELF/eh-frame-merge.s b/test/ELF/eh-frame-merge.s
new file mode 100644 (file)
index 0000000..2610d4d
--- /dev/null
@@ -0,0 +1,58 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+        .section       foo,"ax",@progbits
+       .cfi_startproc
+        nop
+       .cfi_endproc
+
+        .section       bar,"axG",@progbits,foo,comdat
+        .cfi_startproc
+        nop
+        nop
+       .cfi_endproc
+
+// FIXME: We could really use a .eh_frame parser.
+// The intention is to show that:
+// * There is only one copy of the CIE
+// * There are two copies of the first FDE
+// * There is only one copy of the second FDE
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 96
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 14000000 00000000 017A5200 01781001  |
+// CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000  |
+// CHECK-NEXT: 0020: 180E0000 01000000 00000000 00000000  |
+// CHECK-NEXT: 0030: 14000000 34000000 020E0000 02000000  |
+// CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000  |
+// CHECK-NEXT: 0050: E90D0000 01000000 00000000 00000000  |
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1002
diff --git a/test/ELF/eh-frame-multilpe-cie.s b/test/ELF/eh-frame-multilpe-cie.s
new file mode 100644 (file)
index 0000000..12781ff
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared
+// We would fail to parse multiple cies in the same file.
+
+        .cfi_startproc
+        .cfi_personality 0x9b, foo
+        .cfi_endproc
+
+        .cfi_startproc
+        .cfi_endproc
+
+foo:
diff --git a/test/ELF/eh-frame-plt.s b/test/ELF/eh-frame-plt.s
new file mode 100644 (file)
index 0000000..e84d93c
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+       .globl  _start
+_start:
+       .cfi_startproc
+       .cfi_personality 3, bar
+       .cfi_endproc
+
+// CHECK:      Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/eh-frame-rel.s b/test/ELF/eh-frame-rel.s
new file mode 100644 (file)
index 0000000..a417dc1
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %t.o -o %t -shared
+// We used to try to read the relocations as RELA and error out
+
+       .cfi_startproc
+       .cfi_endproc
diff --git a/test/ELF/eh-frame-type.test b/test/ELF/eh-frame-type.test
new file mode 100644 (file)
index 0000000..7562997
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t -shared
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK:      Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
diff --git a/test/ELF/ehframe-relocation.s b/test/ELF/ehframe-relocation.s
new file mode 100644 (file)
index 0000000..8d5e149
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ehframe-relocation.s  -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x10120
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+// CHECK-NOT: .eh_frame
+
+// 0x10120 = 65824
+// 0x10120 + 5 = 65829
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:    11000: {{.*}} movq 65824, %rax
+// DISASM-NEXT:    11008: {{.*}} movq 65829, %rax
+
+.section .eh_frame,"ax",@unwind
+
+.section .text
+.globl _start
+_start:
+ movq .eh_frame, %rax
+ movq .eh_frame + 5, %rax
diff --git a/test/ELF/empty-archive.s b/test/ELF/empty-archive.s
new file mode 100644 (file)
index 0000000..ffb0a78
--- /dev/null
@@ -0,0 +1,3 @@
+// RUN: llvm-ar rc %t.a
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o %t.a -o t
diff --git a/test/ELF/empty-ver.s b/test/ELF/empty-ver.s
new file mode 100644 (file)
index 0000000..f200d28
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared -version-script %p/Inputs/empty-ver.ver
+// RUN: llvm-readobj -version-info %t.so | FileCheck %s
+
+// CHECK:      Version symbols {
+// CHECK-NEXT:   Section Name:
+// CHECK-NEXT:   Address:
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Link:
+// CHECK-NEXT:   Symbols [
+// CHECK-NEXT:     Symbol {
+// CHECK-NEXT:       Version: 0
+// CHECK-NEXT:       Name: @
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Symbol {
+// CHECK-NEXT:       Version: 2
+// CHECK-NEXT:       Name: foo@ver
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ]
+// CHECK-NEXT: }
+
+
+.global foo@ver
+foo@ver:
diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s
new file mode 100644 (file)
index 0000000..7cc764f
--- /dev/null
@@ -0,0 +1,293 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64
+# RUN: ld.lld -m elf_x86_64 %tx64 -o %t2x64
+# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
+# RUN: ld.lld %tx64 -o %t3x64
+# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
+# X86-64:      ElfHeader {
+# X86-64-NEXT:   Ident {
+# X86-64-NEXT:     Magic: (7F 45 4C 46)
+# X86-64-NEXT:     Class: 64-bit (0x2)
+# X86-64-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86-64-NEXT:     FileVersion: 1
+# X86-64-NEXT:     OS/ABI: SystemV (0x0)
+# X86-64-NEXT:     ABIVersion: 0
+# X86-64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86-64-NEXT:   }
+# X86-64-NEXT:   Type: Executable (0x2)
+# X86-64-NEXT:   Machine: EM_X86_64 (0x3E)
+# X86-64-NEXT:   Version: 1
+# X86-64-NEXT:   Entry:
+# X86-64-NEXT:   ProgramHeaderOffset: 0x40
+# X86-64-NEXT:   SectionHeaderOffset:
+# X86-64-NEXT:   Flags [ (0x0)
+# X86-64-NEXT:   ]
+# X86-64-NEXT:   HeaderSize: 64
+# X86-64-NEXT:   ProgramHeaderEntrySize: 56
+# X86-64-NEXT:   ProgramHeaderCount:
+# X86-64-NEXT:   SectionHeaderEntrySize: 64
+# X86-64-NEXT:   SectionHeaderCount:
+# X86-64-NEXT:   StringTableSectionIndex:
+# X86-64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnux32 %s -o %tx32
+# RUN: ld.lld -m elf32_x86_64 %tx32 -o %t2x32
+# RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s
+# RUN: ld.lld %tx32 -o %t3x32
+# RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s
+# X32:      ElfHeader {
+# X32-NEXT:   Ident {
+# X32-NEXT:     Magic: (7F 45 4C 46)
+# X32-NEXT:     Class: 32-bit (0x1)
+# X32-NEXT:     DataEncoding: LittleEndian (0x1)
+# X32-NEXT:     FileVersion: 1
+# X32-NEXT:     OS/ABI: SystemV (0x0)
+# X32-NEXT:     ABIVersion: 0
+# X32-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X32-NEXT:   }
+# X32-NEXT:   Type: Executable (0x2)
+# X32-NEXT:   Machine: EM_X86_64 (0x3E)
+# X32-NEXT:   Version: 1
+# X32-NEXT:   Entry:
+# X32-NEXT:   ProgramHeaderOffset: 0x34
+# X32-NEXT:   SectionHeaderOffset:
+# X32-NEXT:   Flags [ (0x0)
+# X32-NEXT:   ]
+# X32-NEXT:   HeaderSize: 52
+# X32-NEXT:   ProgramHeaderEntrySize: 32
+# X32-NEXT:   ProgramHeaderCount:
+# X32-NEXT:   SectionHeaderEntrySize: 40
+# X32-NEXT:   SectionHeaderCount:
+# X32-NEXT:   StringTableSectionIndex:
+# X32-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86
+# RUN: ld.lld -m elf_i386 %tx86 -o %t2x86
+# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
+# RUN: ld.lld %tx86 -o %t3x86
+# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
+# X86:      ElfHeader {
+# X86-NEXT:   Ident {
+# X86-NEXT:     Magic: (7F 45 4C 46)
+# X86-NEXT:     Class: 32-bit (0x1)
+# X86-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86-NEXT:     FileVersion: 1
+# X86-NEXT:     OS/ABI: SystemV (0x0)
+# X86-NEXT:     ABIVersion: 0
+# X86-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86-NEXT:   }
+# X86-NEXT:   Type: Executable (0x2)
+# X86-NEXT:   Machine: EM_386 (0x3)
+# X86-NEXT:   Version: 1
+# X86-NEXT:   Entry:
+# X86-NEXT:   ProgramHeaderOffset: 0x34
+# X86-NEXT:   SectionHeaderOffset:
+# X86-NEXT:   Flags [ (0x0)
+# X86-NEXT:   ]
+# X86-NEXT:   HeaderSize: 52
+# X86-NEXT:   ProgramHeaderEntrySize: 32
+# X86-NEXT:   ProgramHeaderCount:
+# X86-NEXT:   SectionHeaderEntrySize: 40
+# X86-NEXT:   SectionHeaderCount:
+# X86-NEXT:   StringTableSectionIndex:
+# X86-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd
+# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86_fbsd
+# RUN: llvm-readobj -file-headers %t2x86_fbsd | FileCheck --check-prefix=X86FBSD %s
+# RUN: ld.lld %tx86fbsd -o %t3x86fbsd
+# RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s
+# X86FBSD:      ElfHeader {
+# X86FBSD-NEXT:   Ident {
+# X86FBSD-NEXT:     Magic: (7F 45 4C 46)
+# X86FBSD-NEXT:     Class: 32-bit (0x1)
+# X86FBSD-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86FBSD-NEXT:     FileVersion: 1
+# X86FBSD-NEXT:     OS/ABI: FreeBSD (0x9)
+# X86FBSD-NEXT:     ABIVersion: 0
+# X86FBSD-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86FBSD-NEXT:   }
+# X86FBSD-NEXT:   Type: Executable (0x2)
+# X86FBSD-NEXT:   Machine: EM_386 (0x3)
+# X86FBSD-NEXT:   Version: 1
+# X86FBSD-NEXT:   Entry:
+# X86FBSD-NEXT:   ProgramHeaderOffset: 0x34
+# X86FBSD-NEXT:   SectionHeaderOffset:
+# X86FBSD-NEXT:   Flags [ (0x0)
+# X86FBSD-NEXT:   ]
+# X86FBSD-NEXT:   HeaderSize: 52
+# X86FBSD-NEXT:   ProgramHeaderEntrySize: 32
+# X86FBSD-NEXT:   ProgramHeaderCount:
+# X86FBSD-NEXT:   SectionHeaderEntrySize: 40
+# X86FBSD-NEXT:   SectionHeaderCount:
+# X86FBSD-NEXT:   StringTableSectionIndex:
+# X86FBSD-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64
+# RUN: ld.lld -m elf64ppc %tppc64 -o %t2ppc64
+# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s
+# RUN: ld.lld %tppc64 -o %t3ppc64
+# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s
+# PPC64:      ElfHeader {
+# PPC64-NEXT:   Ident {
+# PPC64-NEXT:     Magic: (7F 45 4C 46)
+# PPC64-NEXT:     Class: 64-bit (0x2)
+# PPC64-NEXT:     DataEncoding: BigEndian (0x2)
+# PPC64-NEXT:     FileVersion: 1
+# PPC64-NEXT:     OS/ABI: SystemV (0x0)
+# PPC64-NEXT:     ABIVersion: 0
+# PPC64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# PPC64-NEXT:   }
+# PPC64-NEXT:   Type: Executable (0x2)
+# PPC64-NEXT:   Machine: EM_PPC64 (0x15)
+# PPC64-NEXT:   Version: 1
+# PPC64-NEXT:   Entry:
+# PPC64-NEXT:   ProgramHeaderOffset: 0x40
+# PPC64-NEXT:   SectionHeaderOffset:
+# PPC64-NEXT:   Flags [ (0x0)
+# PPC64-NEXT:   ]
+# PPC64-NEXT:   HeaderSize: 64
+# PPC64-NEXT:   ProgramHeaderEntrySize: 56
+# PPC64-NEXT:   ProgramHeaderCount:
+# PPC64-NEXT:   SectionHeaderEntrySize: 64
+# PPC64-NEXT:   SectionHeaderCount:
+# PPC64-NEXT:   StringTableSectionIndex:
+# PPC64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %tmips
+# RUN: ld.lld -m elf32btsmip -e _start %tmips -o %t2mips
+# RUN: llvm-readobj -file-headers %t2mips | FileCheck --check-prefix=MIPS %s
+# RUN: ld.lld %tmips -e _start -o %t3mips
+# RUN: llvm-readobj -file-headers %t3mips | FileCheck --check-prefix=MIPS %s
+# MIPS:      ElfHeader {
+# MIPS-NEXT:   Ident {
+# MIPS-NEXT:     Magic: (7F 45 4C 46)
+# MIPS-NEXT:     Class: 32-bit (0x1)
+# MIPS-NEXT:     DataEncoding: BigEndian (0x2)
+# MIPS-NEXT:     FileVersion: 1
+# MIPS-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS-NEXT:     ABIVersion: 0
+# MIPS-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS-NEXT:   }
+# MIPS-NEXT:   Type: Executable (0x2)
+# MIPS-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS-NEXT:   Version: 1
+# MIPS-NEXT:   Entry:
+# MIPS-NEXT:   ProgramHeaderOffset: 0x34
+# MIPS-NEXT:   SectionHeaderOffset:
+# MIPS-NEXT:   Flags [
+# MIPS-NEXT:     EF_MIPS_ABI_O32
+# MIPS-NEXT:     EF_MIPS_ARCH_32R2
+# MIPS-NEXT:     EF_MIPS_CPIC
+# MIPS-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %tmipsel
+# RUN: ld.lld -m elf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld -melf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld %tmipsel -e _start -o %t3mipsel
+# RUN: llvm-readobj -file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s
+# MIPSEL:      ElfHeader {
+# MIPSEL-NEXT:   Ident {
+# MIPSEL-NEXT:     Magic: (7F 45 4C 46)
+# MIPSEL-NEXT:     Class: 32-bit (0x1)
+# MIPSEL-NEXT:     DataEncoding: LittleEndian (0x1)
+# MIPSEL-NEXT:     FileVersion: 1
+# MIPSEL-NEXT:     OS/ABI: SystemV (0x0)
+# MIPSEL-NEXT:     ABIVersion: 0
+# MIPSEL-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPSEL-NEXT:   }
+# MIPSEL-NEXT:   Type: Executable (0x2)
+# MIPSEL-NEXT:   Machine: EM_MIPS (0x8)
+# MIPSEL-NEXT:   Version: 1
+# MIPSEL-NEXT:   Entry:
+# MIPSEL-NEXT:   ProgramHeaderOffset: 0x34
+# MIPSEL-NEXT:   SectionHeaderOffset:
+# MIPSEL-NEXT:   Flags [
+# MIPSEL-NEXT:     EF_MIPS_ABI_O32
+# MIPSEL-NEXT:     EF_MIPS_ARCH_32R2
+# MIPSEL-NEXT:     EF_MIPS_CPIC
+# MIPSEL-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %tmips64
+# RUN: ld.lld -m elf64btsmip -e _start %tmips64 -o %t2mips64
+# RUN: llvm-readobj -file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s
+# RUN: ld.lld %tmips64 -e _start -o %t3mips64
+# RUN: llvm-readobj -file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s
+# MIPS64:      ElfHeader {
+# MIPS64-NEXT:   Ident {
+# MIPS64-NEXT:     Magic: (7F 45 4C 46)
+# MIPS64-NEXT:     Class: 64-bit (0x2)
+# MIPS64-NEXT:     DataEncoding: BigEndian (0x2)
+# MIPS64-NEXT:     FileVersion: 1
+# MIPS64-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS64-NEXT:     ABIVersion: 0
+# MIPS64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS64-NEXT:   }
+# MIPS64-NEXT:   Type: Executable (0x2)
+# MIPS64-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS64-NEXT:   Version: 1
+# MIPS64-NEXT:   Entry:
+# MIPS64-NEXT:   ProgramHeaderOffset: 0x40
+# MIPS64-NEXT:   SectionHeaderOffset:
+# MIPS64-NEXT:   Flags [
+# MIPS64-NEXT:     EF_MIPS_ARCH_64R2
+# MIPS64-NEXT:     EF_MIPS_CPIC
+# MIPS64-NEXT:     EF_MIPS_PIC
+# MIPS64-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux %s -o %tmips64el
+# RUN: ld.lld -m elf64ltsmip -e _start %tmips64el -o %t2mips64el
+# RUN: llvm-readobj -file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s
+# RUN: ld.lld %tmips64el -e _start -o %t3mips64el
+# RUN: llvm-readobj -file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s
+# MIPS64EL:      ElfHeader {
+# MIPS64EL-NEXT:   Ident {
+# MIPS64EL-NEXT:     Magic: (7F 45 4C 46)
+# MIPS64EL-NEXT:     Class: 64-bit (0x2)
+# MIPS64EL-NEXT:     DataEncoding: LittleEndian (0x1)
+# MIPS64EL-NEXT:     FileVersion: 1
+# MIPS64EL-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS64EL-NEXT:     ABIVersion: 0
+# MIPS64EL-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS64EL-NEXT:   }
+# MIPS64EL-NEXT:   Type: Executable (0x2)
+# MIPS64EL-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS64EL-NEXT:   Version: 1
+# MIPS64EL-NEXT:   Entry:
+# MIPS64EL-NEXT:   ProgramHeaderOffset: 0x40
+# MIPS64EL-NEXT:   SectionHeaderOffset:
+# MIPS64EL-NEXT:   Flags [
+# MIPS64EL-NEXT:     EF_MIPS_ARCH_64R2
+# MIPS64EL-NEXT:     EF_MIPS_CPIC
+# MIPS64EL-NEXT:     EF_MIPS_PIC
+# MIPS64EL-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64
+# RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64
+# RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s
+# RUN: ld.lld %taarch64 -o %t3aarch64
+# RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s
+# AARCH64:      ElfHeader {
+# AARCH64-NEXT:   Ident {
+# AARCH64-NEXT:     Magic: (7F 45 4C 46)
+# AARCH64-NEXT:     Class: 64-bit (0x2)
+# AARCH64-NEXT:     DataEncoding: LittleEndian (0x1)
+# AARCH64-NEXT:     FileVersion: 1
+# AARCH64-NEXT:     OS/ABI: SystemV (0x0)
+# AARCH64-NEXT:     ABIVersion: 0
+# AARCH64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# AARCH64-NEXT:   }
+# AARCH64-NEXT:   Type: Executable (0x2)
+# AARCH64-NEXT:   Machine: EM_AARCH64 (0xB7)
+# AARCH64-NEXT:   Version: 1
+# AARCH64-NEXT:   Entry:
+# AARCH64-NEXT:   ProgramHeaderOffset: 0x40
+# AARCH64-NEXT:   SectionHeaderOffset:
+# AARCH64-NEXT:   Flags [ (0x0)
+# AARCH64-NEXT:   ]
+
+# REQUIRES: x86,ppc,mips,aarch64
+
+.globl _start
+_start:
diff --git a/test/ELF/end-preserve.s b/test/ELF/end-preserve.s
new file mode 100644 (file)
index 0000000..71d86d1
--- /dev/null
@@ -0,0 +1,16 @@
+// Should preserve the value of the "end" symbol if it is defined.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-nm %t | FileCheck %s
+
+// CHECK: 0000000000000005 A end
+
+.global _start,end
+end = 5
+.text
+_start:
+    nop
+.bss
+    .space 6
diff --git a/test/ELF/end-update.s b/test/ELF/end-update.s
new file mode 100644 (file)
index 0000000..8654ef1
--- /dev/null
@@ -0,0 +1,29 @@
+// Should set the value of the "end" symbol if it is undefined.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s
+
+// CHECK: Sections [
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type:
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x12000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 6
+// CHECK: ]
+// CHECK: Symbols [
+// CHECK:     Name: end
+// CHECK-NEXT:     Value: 0x12006
+// CHECK: ]
+
+.global _start,end
+.text
+_start:
+    nop
+.bss
+    .space 6
diff --git a/test/ELF/end.s b/test/ELF/end.s
new file mode 100644 (file)
index 0000000..689157f
--- /dev/null
@@ -0,0 +1,79 @@
+// Should set the value of the "_end" symbol to the end of the data segment.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+// By default, the .bss section is the latest section of the data segment.
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=DEFAULT
+
+// DEFAULT: Sections [
+// DEFAULT:     Name: .bss
+// DEFAULT-NEXT:     Type:
+// DEFAULT-NEXT:     Flags [
+// DEFAULT-NEXT:       SHF_ALLOC
+// DEFAULT-NEXT:       SHF_WRITE
+// DEFAULT-NEXT:     ]
+// DEFAULT-NEXT:     Address: 0x12002
+// DEFAULT-NEXT:     Offset:
+// DEFAULT-NEXT:     Size: 6
+// DEFAULT: ]
+// DEFAULT: Symbols [
+// DEFAULT:     Name: _end
+// DEFAULT-NEXT:     Value: 0x12008
+// DEFAULT: ]
+
+// If there is no .bss section, "_end" should point to the end of the .data section.
+// RUN: echo "SECTIONS { \
+// RUN:          /DISCARD/ : { *(.bss) } }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=NOBSS
+
+// NOBSS: Sections [
+// NOBSS:     Name: .data
+// NOBSS-NEXT:     Type:
+// NOBSS-NEXT:     Flags [
+// NOBSS-NEXT:       SHF_ALLOC
+// NOBSS-NEXT:       SHF_WRITE
+// NOBSS-NEXT:     ]
+// NOBSS-NEXT:     Address: 0x159
+// NOBSS-NEXT:     Offset:
+// NOBSS-NEXT:     Size: 2
+// NOBSS: ]
+// NOBSS: Symbols [
+// NOBSS:     Name: _end
+// NOBSS-NEXT:     Value: 0x15B
+// NOBSS: ]
+
+// If the layout of the sections is changed, "_end" should point to the end of allocated address space.
+// RUN: echo "SECTIONS { \
+// RUN:          .bss : { *(.bss) } \
+// RUN:          .data : { *(.data) } \
+// RUN:          .text : { *(.text) } }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=TEXTATEND
+
+// TEXTATEND: Sections [
+// TEXTATEND:     Name: .text
+// TEXTATEND-NEXT:     Type:
+// TEXTATEND-NEXT:     Flags [
+// TEXTATEND-NEXT:       SHF_ALLOC
+// TEXTATEND-NEXT:       SHF_EXECINSTR
+// TEXTATEND-NEXT:     ]
+// TEXTATEND-NEXT:     Address: 0x160
+// TEXTATEND-NEXT:     Offset:
+// TEXTATEND-NEXT:     Size: 1
+// TEXTATEND: ]
+// TEXTATEND: Symbols [
+// TEXTATEND:     Name: _end
+// TEXTATEND-NEXT:     Value: 0x161
+// TEXTATEND: ]
+
+.global _start,_end
+.text
+_start:
+    nop
+.data
+    .word 1
+.bss
+    .space 6
diff --git a/test/ELF/entry.s b/test/ELF/entry.s
new file mode 100644 (file)
index 0000000..6175c76
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: not ld.lld %t1 -o %t2
+# RUN: ld.lld %t1 -o %t2 -e entry
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=SYM %s
+# RUN: ld.lld %t1 -shared -o %t2 -e entry
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DSO %s
+# RUN: ld.lld %t1 -o %t2 --entry=4096
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DEC %s
+# RUN: ld.lld %t1 -o %t2 --entry 0xcafe
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=HEX %s
+# RUN: ld.lld %t1 -o %t2 -e 0777
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=OCT %s
+
+# SYM: Entry: 0x11000
+# DSO: Entry: 0x1000
+# DEC: Entry: 0x1000
+# HEX: Entry: 0xCAFE
+# OCT: Entry: 0x1FF
+
+.globl entry
+entry:
diff --git a/test/ELF/fatal-warnings.s b/test/ELF/fatal-warnings.s
new file mode 100644 (file)
index 0000000..0bc2a2b
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common.s -o %t2.o
+
+# RUN: ld.lld --warn-common %t1.o %t2.o -o %t1.out 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+# ERR: multiple common of
+
+# RUN: not ld.lld --warn-common --fatal-warnings %t1.o %t2.o -o %t2.out 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+
+.globl _start
+_start:
+
+.type arr,@object
+.comm arr,4,4
diff --git a/test/ELF/file-sym.s b/test/ELF/file-sym.s
new file mode 100644 (file)
index 0000000..eddb461
--- /dev/null
@@ -0,0 +1,12 @@
+# Check that we do not keep STT_FILE symbols in the symbol table
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -symbols %t.so | FileCheck %s
+
+# REQUIRES: x86
+
+# CHECK-NOT: xxx
+
+.file "xxx"
+.file ""
diff --git a/test/ELF/gc-merge-local-sym.s b/test/ELF/gc-merge-local-sym.s
new file mode 100644 (file)
index 0000000..b02a3a4
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared -O3 --gc-sections
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 1
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 61626300 |abc.|
+// CHECK-NEXT: )
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK-NOT:          Name: bar
+
+        .global foo
+foo:
+        leaq    .L.str(%rip), %rsi
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "abc"
+bar:
+        .asciz  "def"
diff --git a/test/ELF/gc-sections-eh.s b/test/ELF/gc-sections-eh.s
new file mode 100644 (file)
index 0000000..88c3dd0
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld %t -o %t2 --gc-sections
+# RUN: llvm-readobj -t %t2 | FileCheck %s
+# RUN: llvm-objdump --dwarf=frames %t2 | FileCheck --check-prefix=EH %s
+
+# RUN: ld.lld %t -o %t3
+# RUN: llvm-readobj -t %t3 | FileCheck --check-prefix=NOGC %s
+# RUN: llvm-objdump --dwarf=frames %t3 | FileCheck --check-prefix=EHNOGC %s
+
+# CHECK-NOT: foo
+# NOGC:      foo
+
+# EH:     FDE cie={{.*}} pc=
+# EH-NOT: FDE
+
+# EHNOGC: FDE cie={{.*}} pc=
+# EHNOGC: FDE cie={{.*}} pc=
+
+       .section        .text,"ax",@progbits,unique,0
+       .globl  foo
+foo:
+       .cfi_startproc
+       .cfi_endproc
+
+       .section        .text,"ax",@progbits,unique,1
+       .globl  _start
+_start:
+       .cfi_startproc
+       .cfi_endproc
diff --git a/test/ELF/gc-sections-local-sym.s b/test/ELF/gc-sections-local-sym.s
new file mode 100644 (file)
index 0000000..89121e2
--- /dev/null
@@ -0,0 +1,57 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared --gc-sections
+// RUN: llvm-readobj -t -s -section-data %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global foo
+foo:
+
+.section .bar,"a"
+zed:
+
+// CHECK:      Name: .strtab
+// CHECK-NEXT: Type: SHT_STRTAB
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00666F6F 005F4459 4E414D49 4300      |.foo._DYNAMIC.|
+// CHECK-NEXT: )
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/gc-sections-lsda.s b/test/ELF/gc-sections-lsda.s
new file mode 100644 (file)
index 0000000..b5bed8f
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld -shared --gc-sections %t.o -o %t
+
+// Test that we handle .eh_frame keeping sections alive. We could be more
+// precise and gc the entire contents of this file, but test that at least
+// we are consistent: if we keep .abc, we have to keep .foo
+
+// RUN: llvm-readobj -s %t | FileCheck %s
+// CHECK:  Name: .abc
+// CHECK: Name: .foo (38)
+
+        .cfi_startproc
+        .cfi_lsda 0x1b,zed
+        .cfi_endproc
+        .section        .abc,"a"
+zed:
+        .long   bar-.
+        .section        .foo,"ax"
+bar:
diff --git a/test/ELF/gc-sections-merge-addend.s b/test/ELF/gc-sections-merge-addend.s
new file mode 100644 (file)
index 0000000..8595f58
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 1
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 62617200                    |bar.|
+// CHECK-NEXT: )
+
+        .section        .data.f,"aw",@progbits
+        .globl  f
+f:
+        .quad .rodata.str1.1 + 4
+
+        .section        .data.g,"aw",@progbits
+        .hidden g
+        .globl  g
+g:
+        .quad .rodata.str1.1
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-merge-implicit-addend.s b/test/ELF/gc-sections-merge-implicit-addend.s
new file mode 100644 (file)
index 0000000..8a7c804
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 1
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 62617200                    |bar.|
+// CHECK-NEXT: )
+
+        .section        .data.f,"aw",@progbits
+        .globl  f
+f:
+        .long .rodata.str1.1 + 4
+
+        .section        .data.g,"aw",@progbits
+        .hidden g
+        .globl  g
+g:
+        .long .rodata.str1.1
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-merge.s b/test/ELF/gc-sections-merge.s
new file mode 100644 (file)
index 0000000..ef26886
--- /dev/null
@@ -0,0 +1,61 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld %t.o -o %t.gc.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+// RUN: llvm-readobj -s -section-data %t.gc.so | FileCheck --check-prefix=GC %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 1
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 666F6F00 62617200                    |foo.bar.|
+// CHECK-NEXT: )
+
+// GC:      Name: .rodata
+// GC-NEXT: Type: SHT_PROGBITS
+// GC-NEXT: Flags [
+// GC-NEXT:   SHF_ALLOC
+// GC-NEXT:   SHF_MERGE
+// GC-NEXT:   SHF_STRINGS
+// GC-NEXT: ]
+// GC-NEXT: Address:
+// GC-NEXT: Offset:
+// GC-NEXT: Size: 4
+// GC-NEXT: Link: 0
+// GC-NEXT: Info: 0
+// GC-NEXT: AddressAlignment: 1
+// GC-NEXT: EntrySize: 1
+// GC-NEXT: SectionData (
+// GC-NEXT:   0000: 666F6F00                                |foo.|
+// GC-NEXT: )
+
+        .section        .text.f,"ax",@progbits
+        .globl  f
+f:
+        leaq    .L.str(%rip), %rax
+        retq
+
+        .section        .text.g,"ax",@progbits
+        .hidden g
+        .globl  g
+g:
+        leaq    .L.str.1(%rip), %rax
+        retq
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-print.s b/test/ELF/gc-sections-print.s
new file mode 100644 (file)
index 0000000..59177a6
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t --gc-sections --print-gc-sections -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s
+
+# PRINT:      removing unused section from '.text.x' in file
+# PRINT-NEXT: removing unused section from '.text.y' in file
+
+.globl _start
+.protected a, x, y
+_start:
+ call a
+
+.section .text.a,"ax",@progbits
+a:
+ nop
+
+.section .text.x,"ax",@progbits
+x:
+ nop
+
+.section .text.y,"ax",@progbits
+y:
+ nop
diff --git a/test/ELF/gc-sections-protected.s b/test/ELF/gc-sections-protected.s
new file mode 100644 (file)
index 0000000..9f1efed
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
+
+.protected g
+.globl g
+g:
+retq
diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s
new file mode 100644 (file)
index 0000000..d52eae2
--- /dev/null
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t %t.o --as-needed %t2.so
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck %s
+
+# This test the property that we have a needed line for every undefined.
+# It would also be OK to drop bar2 and the need for the .so
+
+
+# CHECK: Name: bar
+# CHECK: Name: bar2
+# CHECK: Name: foo
+# CHECK: NEEDED SharedLibrary ({{.*}}.so)
+
+
+.section .text.foo, "ax"
+.globl foo
+foo:
+call bar
+
+.section .text.bar, "ax"
+.globl bar
+bar:
+ret
+
+.section .text._start, "ax"
+.globl _start
+_start:
+ret
+
+.section .text.unused, "ax"
+call bar2
diff --git a/test/ELF/gc-sections-weak.s b/test/ELF/gc-sections-weak.s
new file mode 100644 (file)
index 0000000..625b613
--- /dev/null
@@ -0,0 +1,24 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gc-sections-weak.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+.global foo
+foo:
+nop
+
+.data
+.global bar1
+bar1:
+.quad foo
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
diff --git a/test/ELF/gc-sections.s b/test/ELF/gc-sections.s
new file mode 100644 (file)
index 0000000..93f7dc6
--- /dev/null
@@ -0,0 +1,102 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=NOGC %s
+# RUN: ld.lld --gc-sections %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s
+# RUN: ld.lld --export-dynamic --gc-sections %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC2 %s
+
+# NOGC: Name: .eh_frame
+# NOGC: Name: .text
+# NOGC: Name: .ctors
+# NOGC: Name: .dtors
+# NOGC: Name: .init
+# NOGC: Name: .fini
+# NOGC: Name: a
+# NOGC: Name: b
+# NOGC: Name: c
+# NOGC: Name: x
+# NOGC: Name: y
+# NOGC: Name: __preinit_array_start
+# NOGC: Name: __preinit_array_end
+# NOGC: Name: d
+
+# GC1:     Name: .eh_frame
+# GC1:     Name: .text
+# GC1:     Name: .ctors
+# GC1:     Name: .dtors
+# GC1:     Name: .init
+# GC1:     Name: .fini
+# GC1:     Name: a
+# GC1:     Name: b
+# GC1:     Name: c
+# GC1-NOT: Name: x
+# GC1-NOT: Name: y
+# GC1:     Name: __preinit_array_start
+# GC1:     Name: __preinit_array_end
+# GC1-NOT: Name: d
+
+# GC2:     Name: .eh_frame
+# GC2:     Name: .text
+# GC2:     Name: .ctors
+# GC2:     Name: .dtors
+# GC2:     Name: .init
+# GC2:     Name: .fini
+# GC2:     Name: a
+# GC2:     Name: b
+# GC2:     Name: c
+# GC2-NOT: Name: x
+# GC2-NOT: Name: y
+# GC2:     Name: __preinit_array_start
+# GC2:     Name: __preinit_array_end
+# GC2:     Name: d
+
+.globl _start, d
+.protected a, b, c, x, y
+_start:
+  call a
+
+.section .text.a,"ax",@progbits
+a:
+  call _start
+  call b
+
+.section .text.b,"ax",@progbits
+b:
+  call c
+
+.section .text.c,"ax",@progbits
+c:
+  nop
+
+.section .text.d,"ax",@progbits
+d:
+  nop
+
+.section .text.x,"ax",@progbits
+x:
+  call y
+
+.section .text.y,"ax",@progbits
+y:
+  call x
+
+.section .ctors,"aw",@progbits
+  .quad 0
+
+.section .dtors,"aw",@progbits
+  .quad 0
+
+.section .init,"aw",@init_array
+  .quad 0
+
+.section .fini,"aw",@fini_array
+  .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+  .quad 0
+
+.section .eh_frame,"a",@unwind
+  .quad 0
diff --git a/test/ELF/global_offset_table.s b/test/ELF/global_offset_table.s
new file mode 100644 (file)
index 0000000..47e95e9
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+.global _start
+_start:
+.long _GLOBAL_OFFSET_TABLE_
diff --git a/test/ELF/global_offset_table_shared.s b/test/ELF/global_offset_table_shared.s
new file mode 100644 (file)
index 0000000..7935925
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+.long _GLOBAL_OFFSET_TABLE_
+
+// CHECK:      Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s
new file mode 100644 (file)
index 0000000..4e84599
--- /dev/null
@@ -0,0 +1,195 @@
+# REQUIRES: x86,ppc
+
+# RUN: echo ".globl foo" > %te.s
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux      %te.s -o %te-i386.o
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux      %s    -o %t-i386.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux    %s    -o %t-x86_64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %s    -o %t-ppc64.o
+
+# RUN: ld.lld -shared --hash-style=gnu  -o %te-i386.so  %te-i386.o
+# RUN: ld.lld -shared  -hash-style=gnu  -o %t-i386.so   %t-i386.o
+# RUN: ld.lld -shared  -hash-style=gnu  -o %t-x86_64.so %t-x86_64.o
+# RUN: ld.lld -shared --hash-style both -o %t-ppc64.so  %t-ppc64.o
+
+# RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \
+# RUN:   | FileCheck %s -check-prefix=EMPTY
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-i386.so \
+# RUN:   | FileCheck %s -check-prefix=I386
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-x86_64.so \
+# RUN:   | FileCheck %s -check-prefix=X86_64
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \
+# RUN:   | FileCheck %s -check-prefix=PPC64
+
+# EMPTY:      DynamicSymbols [
+# EMPTY:        Symbol {
+# EMPTY:          Name: foo@
+# EMPTY-NEXT:     Value: 0x0
+# EMPTY-NEXT:     Size: 0
+# EMPTY-NEXT:     Binding: Global
+# EMPTY-NEXT:     Type: None
+# EMPTY-NEXT:     Other: 0
+# EMPTY-NEXT:     Section: Undefined
+# EMPTY-NEXT:   }
+# EMPTY-NEXT: ]
+# EMPTY:      GnuHashTable {
+# EMPTY-NEXT:   Num Buckets: 0
+# EMPTY-NEXT:   First Hashed Symbol Index: 2
+# EMPTY-NEXT:   Num Mask Words: 1
+# EMPTY-NEXT:   Shift Count: 5
+# EMPTY-NEXT:   Bloom Filter: [0x0]
+# EMPTY-NEXT:   Buckets: []
+# EMPTY-NEXT:   Values: []
+# EMPTY-NEXT: }
+
+# I386:      Format: ELF32-i386
+# I386:      Arch: i386
+# I386:      AddressSize: 32bit
+# I386:      Sections [
+# I386:          Name: .gnu.hash
+# I386-NEXT:     Type: SHT_GNU_HASH
+# I386-NEXT:     Flags [
+# I386-NEXT:       SHF_ALLOC
+# I386-NEXT:     ]
+# I386-NEXT:     Address:
+# I386-NEXT:     Offset:
+# I386-NEXT:     Size: 32
+# I386-NEXT:     Link:
+# I386-NEXT:     Info: 0
+# I386-NEXT:     AddressAlignment: 4
+# I386-NEXT:     EntrySize: 4
+# I386:      ]
+# I386:      DynamicSymbols [
+# I386:        Symbol {
+# I386:          Name: @
+# I386:          Binding: Local
+# I386:          Section: Undefined
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: baz@
+# I386:          Binding: Global
+# I386:          Section: Undefined
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: bar@
+# I386:          Binding: Global
+# I386:          Section: .text
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: foo@
+# I386:          Binding: Global
+# I386:          Section: .text
+# I386:        }
+# I386:      ]
+# I386:      GnuHashTable {
+# I386-NEXT:   Num Buckets: 1
+# I386-NEXT:   First Hashed Symbol Index: 2
+# I386-NEXT:   Num Mask Words: 1
+# I386-NEXT:   Shift Count: 5
+# I386-NEXT:   Bloom Filter: [0x14000220]
+# I386-NEXT:   Buckets: [2]
+# I386-NEXT:   Values: [0xB8860BA, 0xB887389]
+# I386-NEXT: }
+
+# X86_64:      Format: ELF64-x86-64
+# X86_64:      Arch: x86_64
+# X86_64:      AddressSize: 64bit
+# X86_64:      Sections [
+# X86_64:          Name: .gnu.hash
+# X86_64-NEXT:     Type: SHT_GNU_HASH
+# X86_64-NEXT:     Flags [
+# X86_64-NEXT:       SHF_ALLOC
+# X86_64-NEXT:     ]
+# X86_64-NEXT:     Address:
+# X86_64-NEXT:     Offset:
+# X86_64-NEXT:     Size: 36
+# X86_64-NEXT:     Link:
+# X86_64-NEXT:     Info: 0
+# X86_64-NEXT:     AddressAlignment: 8
+# X86_64-NEXT:     EntrySize: 0
+# X86_64-NEXT:   }
+# X86_64:      ]
+# X86_64:      DynamicSymbols [
+# X86_64:        Symbol {
+# X86_64:          Name: @
+# X86_64:          Binding: Local
+# X86_64:          Section: Undefined
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: baz@
+# X86_64:          Binding: Global
+# X86_64:          Section: Undefined
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: bar@
+# X86_64:          Binding: Global
+# X86_64:          Section: .text
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: foo@
+# X86_64:          Binding: Global
+# X86_64:          Section: .text
+# X86_64:        }
+# X86_64:      ]
+# X86_64:      GnuHashTable {
+# X86_64-NEXT:   Num Buckets: 1
+# X86_64-NEXT:   First Hashed Symbol Index: 2
+# X86_64-NEXT:   Num Mask Words: 1
+# X86_64-NEXT:   Shift Count: 6
+# X86_64-NEXT:   Bloom Filter: [0x400000000004204]
+# X86_64-NEXT:   Buckets: [2]
+# X86_64-NEXT:   Values: [0xB8860BA, 0xB887389]
+# X86_64-NEXT: }
+
+# PPC64:      Format: ELF64-ppc64
+# PPC64:      Arch: powerpc64
+# PPC64:      AddressSize: 64bit
+# PPC64:      Sections [
+# PPC64:          Name: .gnu.hash
+# PPC64-NEXT:     Type: SHT_GNU_HASH
+# PPC64-NEXT:     Flags [
+# PPC64-NEXT:       SHF_ALLOC
+# PPC64-NEXT:     ]
+# PPC64-NEXT:     Address: 0x228
+# PPC64-NEXT:     Offset: 0x228
+# PPC64-NEXT:     Size: 36
+# PPC64-NEXT:     Link: 1
+# PPC64-NEXT:     Info: 0
+# PPC64-NEXT:     AddressAlignment: 8
+# PPC64-NEXT:     EntrySize: 0
+# PPC64-NEXT:   }
+# PPC64:      ]
+# PPC64:      DynamicSymbols [
+# PPC64:        Symbol {
+# PPC64:          Name: @
+# PPC64:          Binding: Local
+# PPC64:          Section: Undefined
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: baz@
+# PPC64:          Binding: Global
+# PPC64:          Section: Undefined
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: bar@
+# PPC64:          Binding: Global
+# PPC64:          Section: .text
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: foo@
+# PPC64:          Binding: Global
+# PPC64:          Section: .text
+# PPC64:        }
+# PPC64:      ]
+# PPC64:      GnuHashTable {
+# PPC64-NEXT:   Num Buckets: 1
+# PPC64-NEXT:   First Hashed Symbol Index: 2
+# PPC64-NEXT:   Num Mask Words: 1
+# PPC64-NEXT:   Shift Count: 6
+# PPC64-NEXT:   Bloom Filter: [0x400000000004204]
+# PPC64-NEXT:   Buckets: [2]
+# PPC64-NEXT:   Values: [0xB8860BA, 0xB887389]
+# PPC64-NEXT: }
+
+.globl foo,bar,baz
+foo:
+bar:
diff --git a/test/ELF/gnu-ifunc-gotpcrel.s b/test/ELF/gnu-ifunc-gotpcrel.s
new file mode 100644 (file)
index 0000000..08aa0af
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-gotpcrel.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %t2.so -o %t
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT:   0x120B0 R_X86_64_GLOB_DAT foo 0x0
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+mov foo@gotpcrel(%rip), %rax
diff --git a/test/ELF/gnu-ifunc-i386.s b/test/ELF/gnu-ifunc-i386.s
new file mode 100644 (file)
index 0000000..bc2d0f9
--- /dev/null
@@ -0,0 +1,132 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rel.plt
+// CHECK-NEXT:  Type: SHT_REL
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0xD4
+// CHECK-NEXT:  Size: 16
+// CHECK-NEXT:  Link: 5
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 4
+// CHECK-NEXT:  EntrySize: 8
+// CHECK-NEXT: }
+// CHECK:     Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+// CHECK-NEXT:     0x1200C R_386_IRELATIVE
+// CHECK-NEXT:     0x12010 R_386_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name:
+// CHECK-NEXT:   Value: 0x0
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: Undefined
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __rel_iplt_end
+// CHECK-NEXT:   Value: 0x100E4
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __rel_iplt_start
+// CHECK-NEXT:   Value: [[RELA]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: _start
+// CHECK-NEXT:   Value: 0x11002
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: bar
+// CHECK-NEXT:   Value: 0x11001
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: foo
+// CHECK-NEXT:   Value: 0x11000
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT:]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT: 11000: c3 retl
+// DISASM:      bar:
+// DISASM-NEXT: 11001: c3 retl
+// DISASM:      _start:
+// DISASM-NEXT:    11002: e8 29 00 00 00 calll 41
+// DISASM-NEXT:    11007: e8 34 00 00 00 calll 52
+// DISASM-NEXT:    1100c: ba d4 00 01 00 movl $65748, %edx
+// DISASM-NEXT:    11011: ba e4 00 01 00 movl $65764, %edx
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020: ff 35 04 20 01 00 pushl 73732
+// DISASM-NEXT:    11026: ff 25 08 20 01 00 jmpl *73736
+// DISASM-NEXT:    1102c: 90 nop
+// DISASM-NEXT:    1102d: 90 nop
+// DISASM-NEXT:    1102e: 90 nop
+// DISASM-NEXT:    1102f: 90 nop
+// DISASM-NEXT:    11030: ff 25 0c 20 01 00 jmpl *73740
+// DISASM-NEXT:    11036: 68 00 00 00 00    pushl $0
+// DISASM-NEXT:    1103b: e9 e0 ff ff ff    jmp -32 <.plt>
+// DISASM-NEXT:    11040: ff 25 10 20 01 00 jmpl *73744
+// DISASM-NEXT:    11046: 68 08 00 00 00    pushl $8
+// DISASM-NEXT:    1104b: e9 d0 ff ff ff    jmp -48 <.plt>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ movl $__rel_iplt_start,%edx
+ movl $__rel_iplt_end,%edx
diff --git a/test/ELF/gnu-ifunc-nosym-i386.s b/test/ELF/gnu-ifunc-nosym-i386.s
new file mode 100644 (file)
index 0000000..d22cedb
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that no __rel_iplt_end/__rel_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rel_iplt_end
+// CHECK-NOT: __rel_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
diff --git a/test/ELF/gnu-ifunc-nosym.s b/test/ELF/gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..08e498e
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that no __rela_iplt_end/__rela_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rela_iplt_end
+// CHECK-NOT: __rela_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
diff --git a/test/ELF/gnu-ifunc-relative.s b/test/ELF/gnu-ifunc-relative.s
new file mode 100644 (file)
index 0000000..dc35102
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -r -t %tout | FileCheck %s
+// REQUIRES: x86
+
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.globl _start
+_start:
+ call foo
+
+// CHECK:      Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   R_X86_64_IRELATIVE - 0x[[ADDR:.*]]
+// CHECK-NEXT: }
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x[[ADDR]]
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: GNU_IFunc
diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s
new file mode 100644 (file)
index 0000000..5336c89
--- /dev/null
@@ -0,0 +1,130 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rela.plt
+// CHECK-NEXT:  Type: SHT_RELA
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0x158
+// CHECK-NEXT:  Size: 48
+// CHECK-NEXT:  Link: 5
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 8
+// CHECK-NEXT:  EntrySize: 24
+// CHECK-NEXT: }
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x12018 R_X86_64_IRELATIVE
+// CHECK-NEXT:     0x12020 R_X86_64_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      Symbols [
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name:
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: Undefined
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_end
+// CHECK-NEXT:    Value: 0x10188
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_start
+// CHECK-NEXT:    Value: [[RELA]]
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x11002
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x11001
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x11000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000: c3 retq
+// DISASM:      bar:
+// DISASM-NEXT:    11001: c3 retq
+// DISASM:      _start:
+// DISASM-NEXT:    11002: e8 29 00 00 00 callq 41
+// DISASM-NEXT:    11007: e8 34 00 00 00 callq 52
+// DISASM-NEXT:    1100c: ba 58 01 01 00 movl $65880, %edx
+// DISASM-NEXT:    11011: ba 88 01 01 00 movl $65928, %edx
+// DISASM-NEXT:    11016: ba 89 01 01 00 movl $65929, %edx
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020: ff 35 e2 0f 00 00 pushq 4066(%rip)
+// DISASM-NEXT:    11026: ff 25 e4 0f 00 00 jmpq *4068(%rip)
+// DISASM-NEXT:    1102c: 0f 1f 40 00       nopl (%rax)
+// DISASM-NEXT:    11030: ff 25 e2 0f 00 00 jmpq *4066(%rip)
+// DISASM-NEXT:    11036: 68 00 00 00 00    pushq $0
+// DISASM-NEXT:    1103b: e9 e0 ff ff ff    jmp -32
+// DISASM-NEXT:    11040: ff 25 da 0f 00 00 jmpq *4058(%rip)
+// DISASM-NEXT:    11046: 68 01 00 00 00    pushq $1
+// DISASM-NEXT:    1104b: e9 d0 ff ff ff    jmp -48
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ movl $__rela_iplt_start,%edx
+ movl $__rela_iplt_end,%edx
+ movl $__rela_iplt_end + 1,%edx
diff --git a/test/ELF/gnu-unique.s b/test/ELF/gnu-unique.s
new file mode 100644 (file)
index 0000000..afc0da2
--- /dev/null
@@ -0,0 +1,37 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+//
+// RUN: ld.lld %t -shared -o %tout.so
+// RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s
+//
+// RUN: ld.lld %t -shared -o %tout.so --no-gnu-unique
+// RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=NO %s
+
+// Check that STB_GNU_UNIQUE is treated as a global and ends up in the dynamic
+// symbol table as STB_GNU_UNIQUE.
+
+.global _start
+.text
+_start:
+
+.data
+.type symb, @gnu_unique_object
+symb:
+
+# GNU:        Name: symb@
+# GNU-NEXT:   Value:
+# GNU-NEXT:   Size: 0
+# GNU-NEXT:   Binding: Unique
+# GNU-NEXT:   Type: Object
+# GNU-NEXT:   Other: 0
+# GNU-NEXT:   Section: .data
+# GNU-NEXT: }
+
+# NO:        Name: symb@
+# NO-NEXT:   Value:
+# NO-NEXT:   Size: 0
+# NO-NEXT:   Binding: Global
+# NO-NEXT:   Type: Object
+# NO-NEXT:   Other: 0
+# NO-NEXT:   Section: .data
+# NO-NEXT: }
diff --git a/test/ELF/gnustack.s b/test/ELF/gnustack.s
new file mode 100644 (file)
index 0000000..6fc9373
--- /dev/null
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld %t1 -z execstack -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RWX %s
+# RUN: ld.lld %t1 -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s
+
+# RW:       Sections [
+# RW-NOT:   Name: .note.GNU-stack
+# RW:       ProgramHeaders [
+# RW:        ProgramHeader {
+# RW:        Type: PT_GNU_STACK
+# RW-NEXT:   Offset: 0x0
+# RW-NEXT:   VirtualAddress: 0x0
+# RW-NEXT:   PhysicalAddress: 0x0
+# RW-NEXT:   FileSize: 0
+# RW-NEXT:   MemSize: 0
+# RW-NEXT:   Flags [
+# RW-NEXT:     PF_R
+# RW-NEXT:     PF_W
+# RW-NEXT:   ]
+# RW-NEXT:   Alignment: 0
+# RW-NEXT:   }
+# RW-NEXT: ]
+
+# RWX-NOT: Name: .note.GNU-stack
+# RWX-NOT: Type: PT_GNU_STACK
+
+.globl _start
+_start:
diff --git a/test/ELF/got-aarch64.s b/test/ELF/got-aarch64.s
new file mode 100644 (file)
index 0000000..b4aa456
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -s -r %t.so | FileCheck %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+// REQUIRES: aarch64
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2090 R_AARCH64_GLOB_DAT dat 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Page(0x2098) - Page(0x1000) = 0x1000 = 4096
+// 0x2098 & 0xff8 = 0x98 = 152
+
+// DISASM: main:
+// DISASM-NEXT:     1000: {{.*}} adrp x0, #4096
+// DISASM-NEXT:     1004: {{.*}} ldr x0, [x0, #144]
+
+.global main,foo,dat
+.text
+main:
+    adrp x0, :got:dat
+    ldr x0, [x0, :got_lo12:dat]
+.data
+dat:
+    .word 42
diff --git a/test/ELF/got-i386.s b/test/ELF/got-i386.s
new file mode 100644 (file)
index 0000000..679eb2e
--- /dev/null
@@ -0,0 +1,56 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -r -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+
+// CHECK:      Symbol {
+// CHECK:       Name: bar
+// CHECK-NEXT:  Value: 0x12000
+// CHECK-NEXT:  Size: 10
+// CHECK-NEXT:  Binding: Global
+// CHECK-NEXT:  Type: Object
+// CHECK-NEXT:  Other: 0
+// CHECK-NEXT:  Section: .bss
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:  Name: obj
+// CHECK-NEXT:  Value: 0x1200A
+// CHECK-NEXT:  Size: 10
+// CHECK-NEXT:  Binding: Global
+// CHECK-NEXT:  Type: Object
+// CHECK-NEXT:  Other: 0
+// CHECK-NEXT:  Section: .bss
+// CHECK-NEXT: }
+
+// 0x12000 - 0 = addr(.got) = 0x12000
+// 0x1200A - 10 = addr(.got) = 0x12000
+// 0x1200A + 5 - 15 = addr(.got) = 0x12000
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: c7 81 00 00 00 00 01 00 00 00 movl $1, (%ecx)
+// DISASM-NEXT: 1100a: c7 81 0a 00 00 00 02 00 00 00 movl $2, 10(%ecx)
+// DISASM-NEXT: 11014: c7 81 0f 00 00 00 03 00 00 00 movl $3, 15(%ecx)
+
+.global _start
+_start:
+  movl $1, bar@GOTOFF(%ecx)
+  movl $2, obj@GOTOFF(%ecx)
+  movl $3, obj+5@GOTOFF(%ecx)
+  .type bar, @object
+  .comm bar, 10
+  .type obj, @object
+  .comm obj, 10
diff --git a/test/ELF/got-plt-header.s b/test/ELF/got-plt-header.s
new file mode 100644 (file)
index 0000000..691516d
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        call foo@plt
+
+// Check that the first .got.plt entry has the address of the dynamic table.
+
+// CHECK:      Type: SHT_DYNAMIC
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2000
+
+// CHECK:      Name: .got.plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x3000
+// CHECK-NEXT: Offset: 0x3000
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00200000 00000000 00000000 00000000
diff --git a/test/ELF/got.s b/test/ELF/got.s
new file mode 100644 (file)
index 0000000..600377d
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x120B0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x120B0 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:     0x120B8 R_X86_64_GLOB_DAT zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+//  0x120B0 - (0x11000 + 2) - 4 = 4266
+//  0x120B0 - (0x11006 + 2) - 4 = 4260
+//  0x120A8 - (0x1100c + 2) - 4 = 4262
+
+// DISASM:      _start:
+// DISASM-NEXT:   11000:  {{.*}}  jmpq  *4266(%rip)
+// DISASM-NEXT:   11006:  {{.*}}  jmpq  *4260(%rip)
+// DISASM-NEXT:   1100c:  {{.*}}  jmpq  *4262(%rip)
+
+.global _start
+_start:
+  jmp *bar@GOTPCREL(%rip)
+  jmp *bar@GOTPCREL(%rip)
+  jmp *zed@GOTPCREL(%rip)
diff --git a/test/ELF/gotpc-relax-nopic.s b/test/ELF/gotpc-relax-nopic.s
new file mode 100644 (file)
index 0000000..2781735
--- /dev/null
@@ -0,0 +1,81 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj -symbols -r %t1 | FileCheck --check-prefix=SYMRELOC %s
+# RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+## There is no relocations.
+# SYMRELOC:      Relocations [
+# SYMRELOC-NEXT: ]
+# SYMRELOC:      Symbols [
+# SYMRELOC:       Symbol {
+# SYMRELOC:        Name: bar
+# SYMRELOC-NEXT:   Value: 0x12000
+
+## 73728 = 0x12000 (bar)
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: _start:
+# DISASM-NEXT:    11000:  48 81 d0 00 20 01 00  adcq  $73728, %rax
+# DISASM-NEXT:    11007:  48 81 c3 00 20 01 00  addq  $73728, %rbx
+# DISASM-NEXT:    1100e:  48 81 e1 00 20 01 00  andq  $73728, %rcx
+# DISASM-NEXT:    11015:  48 81 fa 00 20 01 00  cmpq  $73728, %rdx
+# DISASM-NEXT:    1101c:  48 81 cf 00 20 01 00  orq   $73728, %rdi
+# DISASM-NEXT:    11023:  48 81 de 00 20 01 00  sbbq  $73728, %rsi
+# DISASM-NEXT:    1102a:  48 81 ed 00 20 01 00  subq  $73728, %rbp
+# DISASM-NEXT:    11031:  49 81 f0 00 20 01 00  xorq  $73728, %r8
+# DISASM-NEXT:    11038:  49 f7 c7 00 20 01 00  testq $73728, %r15
+
+# RUN: ld.lld -shared %t.o -o %t2
+# RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=SEC-PIC    %s
+# RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM-PIC %s
+# SEC-PIC:      Section {
+# SEC-PIC:        Index:
+# SEC-PIC:        Name: .got
+# SEC-PIC-NEXT:   Type: SHT_PROGBITS
+# SEC-PIC-NEXT:   Flags [
+# SEC-PIC-NEXT:     SHF_ALLOC
+# SEC-PIC-NEXT:     SHF_WRITE
+# SEC-PIC-NEXT:   ]
+# SEC-PIC-NEXT:   Address: 0x2090
+# SEC-PIC-NEXT:   Offset: 0x2090
+# SEC-PIC-NEXT:   Size: 8
+# SEC-PIC-NEXT:   Link:
+# SEC-PIC-NEXT:   Info:
+# SEC-PIC-NEXT:   AddressAlignment:
+# SEC-PIC-NEXT:   EntrySize:
+# SEC-PIC-NEXT: }
+
+## Check that there was no relaxation performed. All values refer to got entry.
+## Ex: 0x1000 + 4233 + 7 = 0x2090
+##     0x102a + 4191 + 7 = 0x2090
+# DISASM-PIC:      Disassembly of section .text:
+# DISASM-PIC-NEXT: _start:
+# DISASM-PIC-NEXT:  1000: 48 13 05 89 10 00 00 adcq  4233(%rip), %rax
+# DISASM-PIC-NEXT:  1007: 48 03 1d 82 10 00 00 addq  4226(%rip), %rbx
+# DISASM-PIC-NEXT:  100e: 48 23 0d 7b 10 00 00 andq  4219(%rip), %rcx
+# DISASM-PIC-NEXT:  1015: 48 3b 15 74 10 00 00 cmpq  4212(%rip), %rdx
+# DISASM-PIC-NEXT:  101c: 48 0b 3d 6d 10 00 00 orq   4205(%rip), %rdi
+# DISASM-PIC-NEXT:  1023: 48 1b 35 66 10 00 00 sbbq  4198(%rip), %rsi
+# DISASM-PIC-NEXT:  102a: 48 2b 2d 5f 10 00 00 subq  4191(%rip), %rbp
+# DISASM-PIC-NEXT:  1031: 4c 33 05 58 10 00 00 xorq  4184(%rip), %r8
+# DISASM-PIC-NEXT:  1038: 4c 85 3d 51 10 00 00 testq 4177(%rip), %r15
+
+.data
+.type   bar, @object
+bar:
+ .byte   1
+ .size   bar, .-bar
+
+.text
+.globl  _start
+.type   _start, @function
+_start:
+  adcq    bar@GOTPCREL(%rip), %rax
+  addq    bar@GOTPCREL(%rip), %rbx
+  andq    bar@GOTPCREL(%rip), %rcx
+  cmpq    bar@GOTPCREL(%rip), %rdx
+  orq     bar@GOTPCREL(%rip), %rdi
+  sbbq    bar@GOTPCREL(%rip), %rsi
+  subq    bar@GOTPCREL(%rip), %rbp
+  xorq    bar@GOTPCREL(%rip), %r8
+  testq   %r15, bar@GOTPCREL(%rip)
diff --git a/test/ELF/gotpc-relax-und-dso.s b/test/ELF/gotpc-relax-und-dso.s
new file mode 100644 (file)
index 0000000..ed6c4bc
--- /dev/null
@@ -0,0 +1,72 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %S/Inputs/gotpc-relax-und-dso.s -o %tdso.o
+# RUN: ld.lld -shared %tdso.o -o %t.so
+# RUN: ld.lld -shared %t.o %t.so -o %tout
+# RUN: llvm-readobj -r -s %tout | FileCheck --check-prefix=RELOC %s
+# RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
+
+# RELOC:      Relocations [
+# RELOC-NEXT:   Section ({{.*}}) .rela.dyn {
+# RELOC-NEXT:     R_X86_64_GLOB_DAT dsofoo 0x0
+# RELOC-NEXT:     R_X86_64_GLOB_DAT foo 0x0
+# RELOC-NEXT:     R_X86_64_GLOB_DAT und 0x0
+# RELOC-NEXT:   }
+# RELOC-NEXT: ]
+
+# 0x101e + 7 - 36 = 0x1001
+# 0x1025 + 7 - 43 = 0x1001
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:     nop
+# DISASM:      hid:
+# DISASM-NEXT:     nop
+# DISASM:      _start:
+# DISASM-NEXT:    movq    4247(%rip), %rax
+# DISASM-NEXT:    movq    4240(%rip), %rax
+# DISASM-NEXT:    movq    4241(%rip), %rax
+# DISASM-NEXT:    movq    4234(%rip), %rax
+# DISASM-NEXT:    leaq    -36(%rip), %rax
+# DISASM-NEXT:    leaq    -43(%rip), %rax
+# DISASM-NEXT:    movq    4221(%rip), %rax
+# DISASM-NEXT:    movq    4214(%rip), %rax
+# DISASM-NEXT:    movq    4191(%rip), %rax
+# DISASM-NEXT:    movq    4184(%rip), %rax
+# DISASM-NEXT:    movq    4185(%rip), %rax
+# DISASM-NEXT:    movq    4178(%rip), %rax
+# DISASM-NEXT:    leaq    -92(%rip), %rax
+# DISASM-NEXT:    leaq    -99(%rip), %rax
+# DISASM-NEXT:    movq    4165(%rip), %rax
+# DISASM-NEXT:    movq    4158(%rip), %rax
+
+.text
+.globl foo
+.type foo, @function
+foo:
+ nop
+
+.globl hid
+.hidden hid
+.type hid, @function
+hid:
+ nop
+
+.globl _start
+.type _start, @function
+_start:
+ movq und@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
diff --git a/test/ELF/gotpc-relax.s b/test/ELF/gotpc-relax.s
new file mode 100644 (file)
index 0000000..422e104
--- /dev/null
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOC %s
+# RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+## There is no relocations.
+# RELOC:    Relocations [
+# RELOC:    ]
+
+# 0x11003 + 7 - 10 = 0x11000
+# 0x1100a + 7 - 17 = 0x11000
+# 0x11011 + 7 - 23 = 0x11001
+# 0x11018 + 7 - 30 = 0x11001
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:   11000: 90 nop
+# DISASM:      hid:
+# DISASM-NEXT:   11001: 90 nop
+# DISASM:      ifunc:
+# DISASM-NEXT:   11002: c3 retq
+# DISASM:      _start:
+# DISASM-NEXT: leaq -10(%rip), %rax
+# DISASM-NEXT: leaq -17(%rip), %rax
+# DISASM-NEXT: leaq -23(%rip), %rax
+# DISASM-NEXT: leaq -30(%rip), %rax
+# DISASM-NEXT: movq 4058(%rip), %rax
+# DISASM-NEXT: movq 4051(%rip), %rax
+# DISASM-NEXT: leaq -52(%rip), %rax
+# DISASM-NEXT: leaq -59(%rip), %rax
+# DISASM-NEXT: leaq -65(%rip), %rax
+# DISASM-NEXT: leaq -72(%rip), %rax
+# DISASM-NEXT: movq 4016(%rip), %rax
+# DISASM-NEXT: movq 4009(%rip), %rax
+# DISASM-NEXT: callq -93 <foo>
+# DISASM-NEXT: callq -99 <foo>
+# DISASM-NEXT: callq -104 <hid>
+# DISASM-NEXT: callq -110 <hid>
+# DISASM-NEXT: callq *3979(%rip)
+# DISASM-NEXT: callq *3973(%rip)
+# DISASM-NEXT: jmp   -128 <foo>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -134 <foo>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -139 <hid>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -145 <hid>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmpq  *3943(%rip)
+# DISASM-NEXT: jmpq  *3937(%rip)
+
+.text
+.globl foo
+.type foo, @function
+foo:
+ nop
+
+.globl hid
+.hidden hid
+.type hid, @function
+hid:
+ nop
+
+.text
+.type ifunc STT_GNU_IFUNC
+.globl ifunc
+.type ifunc, @function
+ifunc:
+ ret
+
+.globl _start
+.type _start, @function
+_start:
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+
+ call *foo@GOTPCREL(%rip)
+ call *foo@GOTPCREL(%rip)
+ call *hid@GOTPCREL(%rip)
+ call *hid@GOTPCREL(%rip)
+ call *ifunc@GOTPCREL(%rip)
+ call *ifunc@GOTPCREL(%rip)
+ jmp *foo@GOTPCREL(%rip)
+ jmp *foo@GOTPCREL(%rip)
+ jmp *hid@GOTPCREL(%rip)
+ jmp *hid@GOTPCREL(%rip)
+ jmp *ifunc@GOTPCREL(%rip)
+ jmp *ifunc@GOTPCREL(%rip)
diff --git a/test/ELF/gotpcrelx.s b/test/ELF/gotpcrelx.s
new file mode 100644 (file)
index 0000000..95dbf66
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple x86_64-pc-linux-gnu \
+// RUN: %s -o %t.o
+// RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELS %s
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -r %t.so | FileCheck %s
+
+movq foo@GOTPCREL(%rip), %rax
+movq bar@GOTPCREL(%rip), %rax
+
+// RELS: Relocations [
+// RELS-NEXT:   Section ({{.*}}) .rela.text {
+// RELS-NEXT:     R_X86_64_REX_GOTPCRELX foo 0xFFFFFFFFFFFFFFFC
+// RELS-NEXT:     R_X86_64_REX_GOTPCRELX bar 0xFFFFFFFFFFFFFFFC
+// RELS-NEXT:   }
+// RELS-NEXT: ]
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2098 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:     0x2090 R_X86_64_GLOB_DAT foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/i386-got-and-copy.s b/test/ELF/i386-got-and-copy.s
new file mode 100644 (file)
index 0000000..f5b0b8e
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# If there are two relocations such that the first one requires
+# dynamic COPY relocation, the second one requires GOT entry
+# creation, linker should create both - dynamic relocation
+# and GOT entry.
+
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux \
+# RUN:         %S/Inputs/copy-in-shared.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r %t.exe | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (4) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_386_COPY foo
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global _start
+_start:
+  movl $foo, (%esp)     # R_386_32 - requires R_386_COPY relocation
+  movl foo@GOT, %eax    # R_386_GOT32 - requires GOT entry
diff --git a/test/ELF/i386-gotpc.s b/test/ELF/i386-gotpc.s
new file mode 100644 (file)
index 0000000..14c2fcb
--- /dev/null
@@ -0,0 +1,20 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+
+movl $_GLOBAL_OFFSET_TABLE_, %eax
+
+// CHECK:      Name: .got (38)
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2030
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: .text:
+// DISASM-NEXT:    1000: {{.*}}         movl    $4144, %eax
+//                                              0x2030 - 0x1000 = 4144
diff --git a/test/ELF/i386-merge.s b/test/ELF/i386-merge.s
new file mode 100644 (file)
index 0000000..5d48d4d
--- /dev/null
@@ -0,0 +1,50 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+// CHECK:      Name: .mysec
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x114
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 |
+// CHECK-NEXT: )
+
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 14010000 |
+// CHECK-NEXT: )
+
+// The content of .data should be the address of .mysec. 14010000 is 0x114 in
+// little endian.
+
+        .data
+        .long .mysec+4
+
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .long   0x42
+        .long   0x42
diff --git a/test/ELF/i386-relative.s b/test/ELF/i386-relative.s
new file mode 100644 (file)
index 0000000..d814b5b
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+// CHECK-NEXT:     R_386_RELATIVE - 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .long foo
diff --git a/test/ELF/i386-relax-reloc.s b/test/ELF/i386-relax-reloc.s
new file mode 100644 (file)
index 0000000..a7fdc40
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o -relax-relocations
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+foo:
+        movl bar@GOT(%ebx), %eax
+        movl bar+8@GOT(%ebx), %eax
+
+// CHECK: foo:
+// CHECK-NEXT: movl    -4(%ebx), %eax
+// CHECK-NEXT: movl    4(%ebx), %eax
diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s
new file mode 100644 (file)
index 0000000..a2c25e2
--- /dev/null
@@ -0,0 +1,110 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld -shared %t.o %tso -o %t1
+// RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=GOTRELSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASMSHARED %s
+
+// GOTRELSHARED:     Section {
+// GOTRELSHARED:      Index: 8
+// GOTRELSHARED:      Name: .got
+// GOTRELSHARED-NEXT:   Type: SHT_PROGBITS
+// GOTRELSHARED-NEXT:   Flags [
+// GOTRELSHARED-NEXT:     SHF_ALLOC
+// GOTRELSHARED-NEXT:     SHF_WRITE
+// GOTRELSHARED-NEXT:   ]
+// GOTRELSHARED-NEXT:   Address: 0x1050
+// GOTRELSHARED-NEXT:   Offset: 0x1050
+// GOTRELSHARED-NEXT:   Size: 16
+// GOTRELSHARED-NEXT:   Link: 0
+// GOTRELSHARED-NEXT:   Info: 0
+// GOTRELSHARED-NEXT:   AddressAlignment: 4
+// GOTRELSHARED-NEXT:   EntrySize: 0
+// GOTRELSHARED-NEXT: }
+// GOTRELSHARED:      Relocations [
+// GOTRELSHARED-NEXT:   Section ({{.*}}) .rel.dyn {
+// GOTRELSHARED-NEXT:     0x2002 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x200A R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x2013 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x201C R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x2024 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x202D R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x2036 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x203F R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x1050 R_386_TLS_TPOFF tlslocal0 0x0
+// GOTRELSHARED-NEXT:     0x1054 R_386_TLS_TPOFF tlslocal1 0x0
+// GOTRELSHARED-NEXT:     0x1058 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTRELSHARED-NEXT:     0x105C R_386_TLS_TPOFF tlsshared1 0x0
+// GOTRELSHARED-NEXT:   }
+// GOTRELSHARED-NEXT: ]
+
+// DISASMSHARED:       Disassembly of section test:
+// DISASMSHARED-NEXT:  _start:
+// (.got)[0] = 0x2050 = 8272
+// (.got)[1] = 0x2054 = 8276
+// (.got)[2] = 0x2058 = 8280
+// (.got)[3] = 0x205C = 8284
+// DISASMSHARED-NEXT:  2000:    8b 0d 50 10 00 00       movl    4176, %ecx
+// DISASMSHARED-NEXT:  2006:    65 8b 01        movl    %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  2009:    a1 50 10 00 00  movl    4176, %eax
+// DISASMSHARED-NEXT:  200e:    65 8b 00        movl    %gs:(%eax), %eax
+// DISASMSHARED-NEXT:  2011:    03 0d 50 10 00 00       addl    4176, %ecx
+// DISASMSHARED-NEXT:  2017:    65 8b 01        movl    %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  201a:    8b 0d 54 10 00 00       movl    4180, %ecx
+// DISASMSHARED-NEXT:  2020:    65 8b 01        movl    %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  2023:    a1 54 10 00 00  movl    4180, %eax
+// DISASMSHARED-NEXT:  2028:    65 8b 00        movl    %gs:(%eax), %eax
+// DISASMSHARED-NEXT:  202b:    03 0d 54 10 00 00       addl    4180, %ecx
+// DISASMSHARED-NEXT:  2031:    65 8b 01        movl    %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  2034:    8b 0d 58 10 00 00       movl    4184, %ecx
+// DISASMSHARED-NEXT:  203a:    65 8b 01        movl    %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  203d:    03 0d 5c 10 00 00       addl    4188, %ecx
+// DISASMSHARED-NEXT:  2043:    65 8b 01        movl    %gs:(%ecx), %eax
+
+.type tlslocal0,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal0
+.align 4
+tlslocal0:
+ .long 0
+ .size tlslocal0, 4
+
+.type tlslocal1,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal1
+.align 4
+tlslocal1:
+ .long 0
+ .size tlslocal1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section test, "axw"
+.globl _start
+_start:
+movl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal0@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlsshared0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+addl tlsshared1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
diff --git a/test/ELF/icf1.s b/test/ELF/icf1.s
new file mode 100644 (file)
index 0000000..bb06007
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2, "ax"
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf2.s b/test/ELF/icf2.s
new file mode 100644 (file)
index 0000000..be59511
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $60, %rdi
+  call f2
diff --git a/test/ELF/icf3.s b/test/ELF/icf3.s
new file mode 100644 (file)
index 0000000..9f39ff6
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+# This section is not mergeable because the content is different from f2.
+.section .text.f1, "ax"
+f1:
+  mov $60, %rdi
+  call f2
+  mov $0, %rax
diff --git a/test/ELF/icf4.s b/test/ELF/icf4.s
new file mode 100644 (file)
index 0000000..ad16d48
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $1, %rax
+
+.section .text.f2, "ax"
+f2:
+  mov $0, %rax
diff --git a/test/ELF/icf5.s b/test/ELF/icf5.s
new file mode 100644 (file)
index 0000000..cf46658
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $0, %rax
+
+.section .text.f2, "awx"
+f2:
+  mov $0, %rax
diff --git a/test/ELF/icf6.s b/test/ELF/icf6.s
new file mode 100644 (file)
index 0000000..ecb62fe
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .init, "ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .fini, "ax"
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf7.s b/test/ELF/icf7.s
new file mode 100644 (file)
index 0000000..f1fca5b
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+# RUN: llvm-objdump -t %t2 | FileCheck -check-prefix=ALIGN %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+# ALIGN: 0000000000011000 .text 00000000 _start
+# ALIGN: 0000000000011100 .text 00000000 f1
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+  .align 1
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2, "ax"
+  .align 256
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/image-base.s b/test/ELF/image-base.s
new file mode 100644 (file)
index 0000000..0be5059
--- /dev/null
@@ -0,0 +1,60 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -image-base=0x1000000 %t -o %t1
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+.global _start
+_start:
+  nop
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x1000040
+# CHECK-NEXT:     PhysicalAddress: 0x1000040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x1000000
+# CHECK-NEXT:     PhysicalAddress: 0x1000000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x1001000
+# CHECK-NEXT:     PhysicalAddress: 0x1001000
+# CHECK-NEXT:     FileSize: 1
+# CHECK-NEXT:     MemSize: 1
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_W (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
diff --git a/test/ELF/incompatible-ar-first.s b/test/ELF/incompatible-ar-first.s
new file mode 100644 (file)
index 0000000..8a8aaec
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive.s -o %ta.o
+// RUN: llvm-ar rc %t.a %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o
+// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck %s
+
+// We used to crash when
+// * The first object seen by the symbol table is from an archive.
+// * -m was not used.
+// CHECK: a.o is incompatible with {{.*}}b.o
+
+// REQUIRES: x86
diff --git a/test/ELF/incompatible.s b/test/ELF/incompatible.s
new file mode 100644 (file)
index 0000000..82055b7
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tb.o
+// RUN: ld.lld -shared %tb.o -o %ti686.so
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tc.o
+
+// RUN: not ld.lld %ta.o %tb.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-AND-B %s
+// A-AND-B: b.o is incompatible with {{.*}}a.o
+
+// RUN: not ld.lld %tb.o %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=B-AND-C %s
+// B-AND-C: c.o is incompatible with {{.*}}b.o
+
+// RUN: not ld.lld %ta.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-AND-SO %s
+// A-AND-SO: i686.so is incompatible with {{.*}}a.o
+
+// RUN: not ld.lld %tc.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-AND-SO %s
+// C-AND-SO: i686.so is incompatible with {{.*}}c.o
+
+// RUN: not ld.lld %ti686.so %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=SO-AND-C %s
+// SO-AND-C: c.o is incompatible with {{.*}}i686.so
+
+// RUN: not ld.lld -m elf64ppc %ta.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-ONLY %s
+// A-ONLY: a.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf64ppc %tb.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=B-ONLY %s
+// B-ONLY: b.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf64ppc %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-ONLY %s
+// C-ONLY: c.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf_i386 %tc.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-AND-SO-I386 %s
+// C-AND-SO-I386: c.o is incompatible with elf_i386
+
+// RUN: not ld.lld -m elf_i386 %ti686.so %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=SO-AND-C-I386 %s
+// SO-AND-C-I386: c.o is incompatible with elf_i386
+
+
+// We used to fail to identify this incompatibility and crash trying to
+// read a 64 bit file as a 32 bit one.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o
+// RUN: llvm-ar rc %t.a %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o
+// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck --check-prefix=ARCHIVE %s
+// ARCHIVE: a.o is incompatible with {{.*}}b.o
+.global _start
+_start:
+.data
+        .long foo
+
+// REQUIRES: x86,aarch64
diff --git a/test/ELF/init-fini.s b/test/ELF/init-fini.s
new file mode 100644 (file)
index 0000000..4006790
--- /dev/null
@@ -0,0 +1,43 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+// Should use "_init" and "_fini" by default when fills dynamic table
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s
+// BYDEF: INIT 0x11010
+// BYDEF: FINI 0x11020
+
+// -init and -fini override symbols to use
+// RUN: ld.lld -shared %t -o %t2 -init _foo -fini _bar
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s
+// OVR: INIT 0x11030
+// OVR: FINI 0x11040
+
+// Check aliases as well
+// RUN: ld.lld -shared %t -o %t2 -init=_foo -fini=_bar
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s
+
+// Should add a dynamic table entry even if a given symbol stay undefined
+// RUN: ld.lld -shared %t -o %t2 -init=_undef -fini=_undef
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s
+// UNDEF: INIT 0x0
+// UNDEF: FINI 0x0
+
+// Should not add new entries to the symbol table
+// and should not require given symbols to be resolved
+// RUN: ld.lld -shared %t -o %t2 -init=_unknown -fini=_unknown
+// RUN: llvm-readobj -symbols -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s
+// NOENTRY: Symbols [
+// NOENTRY-NOT: Name: _unknown
+// NOENTRY: ]
+// NOENTRY: DynamicSection [
+// NOENTRY-NOT: INIT
+// NOENTRY-NOT: FINI
+// NOENTRY: ]
+
+.global _start,_init,_fini,_foo,_bar,_undef
+_start:
+_init = 0x11010
+_fini = 0x11020
+_foo  = 0x11030
+_bar  = 0x11040
diff --git a/test/ELF/init_fini_priority.s b/test/ELF/init_fini_priority.s
new file mode 100644 (file)
index 0000000..84e5dc3
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  nop
+
+.section .init_array, "aw", @init_array
+  .align 8
+  .byte 1
+.section .init_array.100, "aw", @init_array
+  .long 2
+.section .init_array.5, "aw", @init_array
+  .byte 3
+.section .init_array, "aw", @init_array
+  .byte 4
+.section .init_array, "aw", @init_array
+  .byte 5
+
+.section .fini_array, "aw", @fini_array
+  .align 8
+  .byte 0x11
+.section .fini_array.100, "aw", @fini_array
+  .long 0x12
+.section .fini_array.5, "aw", @fini_array
+  .byte 0x13
+.section .fini_array, "aw", @fini_array
+  .byte 0x14
+.section .fini_array, "aw", @fini_array
+  .byte 0x15
+
+// CHECK:      Contents of section .init_array:
+// CHECK-NEXT: 03020000 00000000 010405
+// CHECK:      Contents of section .fini_array:
+// CHECK-NEXT: 13120000 00000000 111415
diff --git a/test/ELF/invalid-cie-length.s b/test/ELF/invalid-cie-length.s
new file mode 100644 (file)
index 0000000..e9ad3ca
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+        .section .eh_frame
+        .byte 0
+
+// CHECK: CIE/FDE too small
diff --git a/test/ELF/invalid-cie-length2.s b/test/ELF/invalid-cie-length2.s
new file mode 100644 (file)
index 0000000..94a677e
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+        .section .eh_frame
+        .long 42
+
+// CHECK: CIE/FIE ends past the end of the section
diff --git a/test/ELF/invalid-cie-length3.s b/test/ELF/invalid-cie-length3.s
new file mode 100644 (file)
index 0000000..665fc80
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0xFFFFFFFC
+
+// CHECK: CIE/FIE ends past the end of the section
diff --git a/test/ELF/invalid-cie-length4.s b/test/ELF/invalid-cie-length4.s
new file mode 100644 (file)
index 0000000..daa20d1
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0xFFFFFFFF
+ .byte 0
+
+// CHECK: CIE/FDE too large
diff --git a/test/ELF/invalid-cie-length5.s b/test/ELF/invalid-cie-length5.s
new file mode 100644 (file)
index 0000000..bfa35ed
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0xFFFFFFFF
+ .quad 0xFFFFFFFFFFFFFFF4
+
+// CHECK: CIE/FDE too large
diff --git a/test/ELF/invalid-cie-reference.s b/test/ELF/invalid-cie-reference.s
new file mode 100644 (file)
index 0000000..fba2467
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+        .section .eh_frame
+        .long 0x14
+        .long 0x0
+        .byte 0x01
+        .byte 0x7a
+        .byte 0x52
+        .byte 0x00
+        .byte 0x01
+        .byte 0x78
+        .byte 0x10
+        .byte 0x01
+        .byte 0x1b
+        .byte 0x0c
+        .byte 0x07
+        .byte 0x08
+        .byte 0x90
+        .byte 0x01
+        .short 0x0
+
+        .long 0x14
+        .long 0x1b
+        .long .text
+        .long 0x0
+        .long 0x0
+        .long 0x0
+
+// CHECK: invalid CIE reference
diff --git a/test/ELF/invalid-dynamic-list.test b/test/ELF/invalid-dynamic-list.test
new file mode 100644 (file)
index 0000000..0e7c820
--- /dev/null
@@ -0,0 +1,37 @@
+## Different "echo" commands on Windows interpret quoted strings and
+## wildcards in similar but different way (On Windows, ARGV tokenization
+## and wildcard expansion are not done by the shell but by each command.)
+## Because of that reason, this test fails on some Windows environment.
+## We can't write quoted strings that are interpreted the same way
+## by all echo commands. So, we don't want to run this on Windows.
+
+# REQUIRES: shell
+
+# RUN: mkdir -p %t.dir
+
+# RUN: echo foobar > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: line 1: { expected, but got foobar
+
+# RUN: echo "{ foobar;" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: line 1: unexpected EOF
+
+## Missing ';' before '}'
+# RUN: echo "{ foobar }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: line 1: ; expected, but got }
+
+## Missing final ';'
+# RUN: echo "{ foobar; }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: line 1: unexpected EOF
+
+## Missing \" in foobar definition
+# RUN echo "{ \"foobar; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: line 1: unexpected EOF
+
+# RUN: echo "{ extern \"BOGUS\" { test }; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: line 1: ; expected, but got BOGUS
diff --git a/test/ELF/invalid-elf.test b/test/ELF/invalid-elf.test
new file mode 100644 (file)
index 0000000..c3a97d3
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: llvm-mc %s -o %t -filetype=obj -triple x86_64-pc-linux
+
+# RUN: not ld.lld %t %p/Inputs/invalid-data-encoding.a -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-DATA-ENC %s
+# INVALID-DATA-ENC: invalid data encoding: test.o
+
+# RUN: not ld.lld %t %p/Inputs/invalid-file-class.a -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-FILE-CLASS %s
+# INVALID-FILE-CLASS: invalid file class: test.o
+
+# RUN: not ld.lld %p/Inputs/invalid-symtab-sh_info.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s
+# INVALID-SYMTAB-SHINFO: invalid sh_info in symbol table
+
+# RUN: not ld.lld %p/Inputs/invalid-binding.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-BINDING %s
+# INVALID-BINDING: unexpected binding
+
+# RUN: not ld.lld %p/Inputs/invalid-section-index.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SECTION-INDEX-LLD %s
+# INVALID-SECTION-INDEX-LLD: invalid section index
+
+# RUN: not ld.lld %p/Inputs/invalid-shstrndx.so -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SECTION-INDEX %s
+# INVALID-SECTION-INDEX: Invalid section index
+
+# RUN: not ld.lld %p/Inputs/invalid-shentsize-zero.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SHENTSIZE-ZERO %s
+# INVALID-SHENTSIZE-ZERO: SHF_MERGE section size must be a multiple of sh_entsize
+
+# RUN: not ld.lld %p/Inputs/invalid-multiple-eh-relocs.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-EH-RELOCS %s
+# INVALID-EH-RELOCS: multiple relocation sections to .eh_frame are not supported
+
+.long foo
diff --git a/test/ELF/invalid-fde-rel.s b/test/ELF/invalid-fde-rel.s
new file mode 100644 (file)
index 0000000..9fb73d2
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+        .section .eh_frame
+        .long 0x14
+        .long 0x0
+        .byte 0x01
+        .byte 0x7a
+        .byte 0x52
+        .byte 0x00
+        .byte 0x01
+        .byte 0x78
+        .byte 0x10
+        .byte 0x01
+        .byte 0x1b
+        .byte 0x0c
+        .byte 0x07
+        .byte 0x08
+        .byte 0x90
+        .byte 0x01
+        .short 0x0
+
+        .long 0x14
+        .long 0x1c
+        .long 0x0
+        .long 0x0
+        .long 0x0
+        .long 0x0
+
+// CHECK: FDE doesn't reference another section
diff --git a/test/ELF/invalid-linkerscript.test b/test/ELF/invalid-linkerscript.test
new file mode 100644 (file)
index 0000000..e088166
--- /dev/null
@@ -0,0 +1,54 @@
+## Different "echo" commands on Windows interpret quoted strings and
+## wildcards in similar but different way (On Windows, ARGV tokenization
+## and wildcard expansion are not done by the shell but by each command.)
+## Because of that reason, this test fails on some Windows environment.
+## We can't write quoted strings that are interpreted the same way
+## by all echo commands. So, we don't want to run this on Windows.
+
+# REQUIRES: shell
+
+# RUN: mkdir -p %t.dir
+
+## Note that we are using "cannot open no-such-file: " as a marker that the
+## linker keep going when it found an error. That specific error message is not
+## related to the linker script tests.
+
+# RUN: echo foobar > %t1
+# RUN: not ld.lld %t1 no-such-file 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: unknown directive: foobar
+# ERR1: cannot open no-such-file:
+
+# RUN: echo "foo \"bar" > %t2
+# RUN: not ld.lld %t2 no-such-file 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: unclosed quote
+# ERR2: cannot open no-such-file:
+
+# RUN: echo "/*" > %t3
+# RUN: not ld.lld %t3 no-such-file 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: unclosed comment
+# ERR3: cannot open no-such-file:
+
+# RUN: echo "EXTERN (" > %t4
+# RUN: not ld.lld %t4 no-such-file 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: unexpected EOF
+# ERR4: cannot open no-such-file:
+
+# RUN: echo "EXTERN (" > %t5
+# RUN: not ld.lld %t5 no-such-file 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: unexpected EOF
+# ERR5: cannot open no-such-file:
+
+# RUN: echo "EXTERN xyz" > %t6
+# RUN: not ld.lld %t6 no-such-file 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: ( expected, but got xyz
+# ERR6: cannot open no-such-file:
+
+# RUN: echo "INCLUDE /no/such/file" > %t7
+# RUN: not ld.lld %t7 no-such-file 2>&1 | FileCheck -check-prefix=ERR7 %s
+# ERR7: cannot open /no/such/file
+# ERR7: cannot open no-such-file:
+
+# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
+# RUN: not ld.lld %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
+# ERR8: unexpected token: y
+# ERR8: cannot open no-such-file:
diff --git a/test/ELF/invalid-relocations.test b/test/ELF/invalid-relocations.test
new file mode 100644 (file)
index 0000000..cfeb44b
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Type:            SHT_PROGBITS
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Info:            12 # Invalid index
+    Relocations:
+      - Offset:          0x0000000000000001
+        Symbol:          lulz
+        Type:            R_X86_64_PC32
+Symbols:
+  Global:
+    - Name:            lulz
+
+# CHECK: invalid relocated section index
diff --git a/test/ELF/libsearch.s b/test/ELF/libsearch.s
new file mode 100644 (file)
index 0000000..782d755
--- /dev/null
@@ -0,0 +1,89 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/libsearch-dyn.s -o %tdyn.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/libsearch-st.s -o %tst.o
+// RUN: mkdir -p %t.dir
+// RUN: ld.lld -shared %tdyn.o -o %t.dir/libls.so
+// RUN: cp -f %t.dir/libls.so %t.dir/libls2.so
+// RUN: rm -f %t.dir/libls.a
+// RUN: llvm-ar rcs %t.dir/libls.a %tst.o
+// REQUIRES: x86
+
+// Should fail if no library specified
+// RUN: not ld.lld -l 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIBRARY %s
+// NOLIBRARY: missing arg value for "-l", expected 1 argument.
+
+// Should not link because of undefined symbol _bar
+// RUN: not ld.lld -o %t3 %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=UNDEFINED %s
+// UNDEFINED: undefined symbol: _bar
+
+// Should fail if cannot find specified library (without -L switch)
+// RUN: not ld.lld -o %t3 %t.o -lls 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIB %s
+// NOLIB: unable to find library -lls
+
+// Should use explicitly specified static library
+// Also ensure that we accept -L <arg>
+// RUN: ld.lld -o %t3 %t.o -L %t.dir -l:libls.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// STATIC: Symbols [
+// STATIC: Name: _static
+// STATIC: ]
+
+// Should use explicitly specified dynamic library
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -l:libls.so
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// DYNAMIC: Symbols [
+// DYNAMIC-NOT: Name: _static
+// DYNAMIC: ]
+
+// Should prefer dynamic to static
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+// Check for library search order
+// RUN: mkdir -p %t.dir2
+// RUN: cp %t.dir/libls.a %t.dir2
+// RUN: ld.lld -o %t3 %t.o -L%t.dir2 -L%t.dir -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+
+// -L can be placed after -l
+// RUN: ld.lld -o %t3 %t.o -lls -L%t.dir
+
+// Check long forms as well
+// RUN: ld.lld -o %t3 %t.o --library-path=%t.dir --library=ls
+
+// Should not search for dynamic libraries if -Bstatic is specified
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: not ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls2 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIB2 %s
+// NOLIB2: unable to find library -lls2
+
+// -Bdynamic should restore default behaviour
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -Bdynamic -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+// -Bstatic and -Bdynamic should affect only libraries which follow them
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -lls -Bstatic -Bdynamic
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls -Bdynamic
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+
+// Check aliases as well
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -dn -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -non_shared -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -static -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -dy -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -call_shared -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/linkerscript-align.s b/test/ELF/linkerscript-align.s
new file mode 100644 (file)
index 0000000..5f6e6f7
--- /dev/null
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x10000; \
+# RUN:  .aaa : \
+# RUN:  { \
+# RUN:   *(.aaa) \
+# RUN:  } \
+# RUN:  . = ALIGN(4096); \
+# RUN:  .bbb : \
+# RUN:  { \
+# RUN:   *(.bbb) \
+# RUN:  } \
+# RUN:  . = ALIGN(4096 * 4); \
+# RUN:  .ccc : \
+# RUN:  { \
+# RUN:   *(.ccc) \
+# RUN:  } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .aaa          00000008 0000000000010000 DATA
+# CHECK-NEXT:   2 .bbb          00000008 0000000000011000 DATA
+# CHECK-NEXT:   3 .ccc          00000008 0000000000014000 DATA
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
diff --git a/test/ELF/linkerscript-diagnostic.s b/test/ELF/linkerscript-diagnostic.s
new file mode 100644 (file)
index 0000000..f42cbe8
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Take some valid script with multiline comments
+## and check it actually works:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: ld.lld -shared %t -o %t1 --script %t.script
+
+## Change ":" to "+" at line 2, check that error
+## message starts from correct line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text + { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: line 2:
+
+## Change ":" to "+" at line 3 now, check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep + { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: line 3:
+
+## Change ":" to "+" at line 6, after multiline comment,
+## check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp + { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: line 6:
+
+## Check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "UNKNOWN_TAG {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR6 %s < %t.log
+# ERR6:      line 1:
+# ERR6-NEXT: UNKNOWN_TAG {
+# RUN: grep '^^' %t.log
+
+## One more check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR7 %s < %t.log
+# ERR7:      line 4: : expected, but got .temp
+# ERR7-NEXT: boom .temp : { *(.temp) } }
+# RUN: grep '^     ^' %t.log
diff --git a/test/ELF/linkerscript-locationcounter.s b/test/ELF/linkerscript-locationcounter.s
new file mode 100644 (file)
index 0000000..c6e8e7e
--- /dev/null
@@ -0,0 +1,340 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0xFFF0; \
+# RUN:  . = . + 0x10; \
+# RUN:  .plus : { *(.plus) } \
+# RUN:  . = 0x11010 - 0x10; \
+# RUN:  .minus : { *(.minus) } \
+# RUN:  . = 0x24000 / 0x2; \
+# RUN:  .div : { *(.div) } \
+# RUN:  . = 0x11000 + 0x1000 * 0x2; \
+# RUN:  .mul : { *(.mul) } \
+# RUN:  . = 0x10000 + (0x1000 + 0x1000) * 0x2; \
+# RUN:  .bracket : { *(.bracket) } \
+# RUN:  . = 0x17000 & 0x15000; \
+# RUN:  .and : { *(.and) } \
+# RUN:  . = 0x1 ? 0x16000 : 0x999999; \
+# RUN:  .ternary1 : { *(.ternary1) } \
+# RUN:  . = 0x0 ? 0x999999 : 0x17000; \
+# RUN:  .ternary2 : { *(.ternary2) } \
+# RUN:  . = 0x0 < 0x1 ? 0x18000 : 0x999999; \
+# RUN:  .less : { *(.less) } \
+# RUN:  . = 0x1 <= 0x1 ? 0x19000 : 0x999999; \
+# RUN:  .lesseq : { *(.lesseq) } \
+# RUN:  . = 0x1 > 0x0 ? 0x20000 : 0x999999; \
+# RUN:  .great : { *(.great) } \
+# RUN:  . = 0x1 >= 0x1 ? 0x21000 : 0x999999; \
+# RUN:  .greateq : { *(.greateq) } \
+# RUN:  . = 0x1 == 0x1 ? 0x22000 : 0x999999; \
+# RUN:  .eq : { *(.eq) } \
+# RUN:  . = 0x2 != 0x1 ? 0x23000 : 0x999999; \
+# RUN:  .neq : { *(.neq) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -s %t2 | FileCheck %s
+
+# CHECK: Section {
+# CHECK:   Index: 1
+# CHECK:   Name: .plus
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 2
+# CHECK-NEXT:   Name: .minus
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x11000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .div
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x12000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 4
+# CHECK-NEXT:   Name: .mul
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x13000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 5
+# CHECK-NEXT:   Name: .bracket
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x14000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .and
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x15000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .ternary1
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x16000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .ternary2
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x17000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .less
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x18000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .lesseq
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x19000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .great
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x20000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .greateq
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x21000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .eq
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x22000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .neq
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x23000
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+
+## Mailformed number error.
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x12Q41; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=NUMERR %s
+# NUMERR: malformed number: 0x12Q41
+
+## Missing closing bracket.
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x10000 + (0x1000 + 0x1000 * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=BRACKETERR %s
+# BRACKETERR: unexpected EOF
+
+## Missing opening bracket.
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x10000 + 0x1000 + 0x1000) * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=BRACKETERR2 %s
+# BRACKETERR2: stray token: )
+
+## Empty expression.
+# RUN: echo "SECTIONS { \
+# RUN:  . = ; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=ERREXPR %s
+# ERREXPR: error in location counter expression
+
+## Div by zero error.
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x10000 / 0x0; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=DIVZERO %s
+# DIVZERO: division by zero
+
+## Broken ternary operator expression.
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1 ? 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=TERNERR %s
+# TERNERR: unexpected EOF
+
+.globl _start
+_start:
+nop
+
+.section .plus, "a"
+.quad 0
+
+.section .minus, "a"
+.quad 0
+
+.section .div, "a"
+.quad 0
+
+.section .mul, "a"
+.quad 0
+
+.section .bracket, "a"
+.quad 0
+
+.section .and, "a"
+.quad 0
+
+.section .ternary1, "a"
+.quad 0
+
+.section .ternary2, "a"
+.quad 0
+
+.section .less, "a"
+.quad 0
+
+.section .lesseq, "a"
+.quad 0
+
+.section .great, "a"
+.quad 0
+
+.section .greateq, "a"
+.quad 0
+
+.section .eq, "a"
+.quad 0
+
+.section .neq, "a"
+.quad 0
diff --git a/test/ELF/linkerscript-orphans.s b/test/ELF/linkerscript-orphans.s
new file mode 100644 (file)
index 0000000..fa7d30b
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { .writable : { *(.writable) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=TEXTORPHAN %s
+
+# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=WRITABLEORPHAN %s
+
+# TEXTORPHAN:      Sections:
+# TEXTORPHAN-NEXT: Idx Name
+# TEXTORPHAN-NEXT:   0
+# TEXTORPHAN-NEXT:   1 .writable
+# TEXTORPHAN-NEXT:   2 .text
+
+# WRITABLEORPHAN:      Sections:
+# WRITABLEORPHAN-NEXT: Idx Name
+# WRITABLEORPHAN-NEXT:   0
+# WRITABLEORPHAN-NEXT:   1 .text
+# WRITABLEORPHAN-NEXT:   2 .writable
+
+.global _start
+_start:
+ nop
+
+.section .writable,"aw"
+ .zero 4
diff --git a/test/ELF/linkerscript-ouputformat.s b/test/ELF/linkerscript-ouputformat.s
new file mode 100644 (file)
index 0000000..3c6cfdc
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_FORMAT(x, y, z)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_FORMAT(x, y)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: not ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
diff --git a/test/ELF/linkerscript-outputarch.s b/test/ELF/linkerscript-outputarch.s
new file mode 100644 (file)
index 0000000..9908961
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_ARCH(x)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_ARCH(x, y)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: not ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
diff --git a/test/ELF/linkerscript-phdr-check.s b/test/ELF/linkerscript-phdr-check.s
new file mode 100644 (file)
index 0000000..c7229ed
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_PHDR (0x6)
+# CHECK-NEXT:    Offset: 0x40
+# CHECK-NEXT:    VirtualAddress: 0xFFFF040
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript-repsection-va.s b/test/ELF/linkerscript-repsection-va.s
new file mode 100644 (file)
index 0000000..4feeaa0
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : {*(.foo.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .foo          00000004 0000000000000158 DATA
+# CHECK-NEXT:   2 .foo          00000004 000000000000015c DATA
+# CHECK-NEXT:   3 .text         00000001 0000000000000160 TEXT DATA
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript-sections-keep.s b/test/ELF/linkerscript-sections-keep.s
new file mode 100644 (file)
index 0000000..fae6383
--- /dev/null
@@ -0,0 +1,80 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## First check that section "keep" is garbage collected without using KEEP
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  .keep : { *(.keep) } \
+# RUN:  .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SECGC %s
+# SECGC:      Sections:
+# SECGC-NEXT: Idx Name          Size      Address          Type
+# SECGC-NEXT:   0               00000000 0000000000000000
+# SECGC-NEXT:   1 .text         00000007 0000000000000158 TEXT DATA
+# SECGC-NEXT:   2 .temp         00000004 000000000000015f DATA
+
+## Now apply KEEP command to preserve the section.
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  .keep : { KEEP(*(.keep)) } \
+# RUN:  .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SECNOGC %s
+# SECNOGC:      Sections:
+# SECNOGC-NEXT: Idx Name          Size      Address          Type
+# SECNOGC-NEXT:   0               00000000 0000000000000000
+# SECNOGC-NEXT:   1 .text         00000007 0000000000000158 TEXT DATA
+# SECNOGC-NEXT:   2 .keep         00000004 000000000000015f DATA
+# SECNOGC-NEXT:   3 .temp         00000004 0000000000000163 DATA
+
+## A section name matches two entries in the SECTIONS directive. The
+## first one doesn't have KEEP, the second one does. If section that have
+## KEEP is the first in order then section is NOT collected.
+# RUN: echo "SECTIONS { \
+# RUN:  .keep : { KEEP(*(.keep)) } \
+# RUN:  .nokeep : { *(.keep) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s
+# MIXED1:      Sections:
+# MIXED1-NEXT: Idx Name          Size      Address         Type
+# MIXED1-NEXT:   0               00000000 0000000000000000
+# MIXED1-NEXT:   1 .keep         00000004 0000000000000120 DATA
+# MIXED1-NEXT:   2 .temp         00000004 0000000000000124 DATA
+# MIXED1-NEXT:   3 .text         00000007 0000000000000128 TEXT DATA
+# MIXED1-NEXT:   4 .symtab       00000060 0000000000000000
+# MIXED1-NEXT:   5 .shstrtab     0000002d 0000000000000000
+# MIXED1-NEXT:   6 .strtab       00000012 0000000000000000
+
+## The same, but now section without KEEP is at first place.
+## gold and bfd linkers disagree here. gold collects .keep while
+## bfd keeps it. Our current behavior is compatible with bfd although
+## we can choose either way.
+# RUN: echo "SECTIONS { \
+# RUN:  .nokeep : { *(.keep) } \
+# RUN:  .keep : { KEEP(*(.keep)) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s
+# MIXED2:      Sections:
+# MIXED2-NEXT: Idx Name          Size      Address         Type
+# MIXED2-NEXT:   0               00000000 0000000000000000
+# MIXED2-NEXT:   1 .nokeep       00000004 0000000000000120 DATA
+# MIXED2-NEXT:   2 .temp         00000004 0000000000000124 DATA
+# MIXED2-NEXT:   3 .text         00000007 0000000000000128 TEXT DATA
+# MIXED2-NEXT:   4 .symtab       00000060 0000000000000000
+# MIXED2-NEXT:   5 .shstrtab     0000002f 0000000000000000
+# MIXED2-NEXT:   6 .strtab       00000012 0000000000000000
+
+.global _start
+_start:
+ mov temp, %eax
+
+.section .keep, "a"
+keep:
+ .long 1
+
+.section .temp, "a"
+temp:
+ .long 2
diff --git a/test/ELF/linkerscript-sections-padding.s b/test/ELF/linkerscript-sections-padding.s
new file mode 100644 (file)
index 0000000..545739e
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that padding value works:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x112233445566778899 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES %s
+# YES: 00000120  66 22 33 44 55 66 77 88 99 11 22 33 44 55 66 77
+
+## Confirming that address was correct:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x998877665544332211 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES2 %s
+# YES2: 00000120  66 88 77 66 55 44 33 22 11 99 88 77 66 55 44
+
+## Default padding value is 0x00:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=NO %s
+# NO: 00000120  66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+## Filler should be a hex value (1):
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =99 }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR %s
+# ERR: filler should be a hexadecimal value
+
+## Filler should be a hex value (2):
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR2 %s
+# ERR2: not a hexadecimal value: XX
+
+.section        .mysec.1,"a"
+.align  16
+.byte   0x66
+
+.section        .mysec.2,"a"
+.align  16
+.byte   0x66
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript-sections.s b/test/ELF/linkerscript-sections.s
new file mode 100644 (file)
index 0000000..b68dac7
--- /dev/null
@@ -0,0 +1,119 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Empty SECTIONS command.
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+# SECTIONS command with the same order as default.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+#             Idx Name          Size
+# SEC-DEFAULT: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DEFAULT: 2 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-DEFAULT: 5 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-DEFAULT: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DEFAULT: 7 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-DEFAULT: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# Sections are put in order specified in linker script.
+# RUN: echo "SECTIONS { \
+# RUN:          .bss : { *(.bss) } \
+# RUN:          other : { *(other) } \
+# RUN:          .shstrtab : { *(.shstrtab) } \
+# RUN:          .symtab : { *(.symtab) } \
+# RUN:          .strtab : { *(.strtab) } \
+# RUN:          .data : { *(.data) } \
+# RUN:          .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t3 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN:   FileCheck -check-prefix=SEC-ORDER %s
+
+#           Idx Name          Size
+# SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 3 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-ORDER: 4 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-ORDER: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+
+# .text and .data have swapped names but proper sizes and types.
+# RUN: echo "SECTIONS { \
+# RUN:          .data : { *(.text) } \
+# RUN:          .text : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t4 | \
+# RUN:   FileCheck -check-prefix=SEC-SWAP-NAMES %s
+
+#                Idx Name          Size
+# SEC-SWAP-NAMES: 1 .data         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-SWAP-NAMES: 2 .text         00000020 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-SWAP-NAMES: 5 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 7 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# .shstrtab from the input object file is discarded.
+# RUN: echo "SECTIONS { \
+# RUN:          /DISCARD/ : { *(.shstrtab) } }" > %t.script
+# RUN: ld.lld -o %t5 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t5 | \
+# RUN:   FileCheck -check-prefix=SEC-DISCARD %s
+
+#             Idx Name          Size
+# SEC-DISCARD: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DISCARD: 2 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-DISCARD: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DISCARD: 6 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-DISCARD: 7 .strtab       00000008 {{[0-9a-f]*}}
+
+# Multiple SECTIONS command specifying additional input section descriptions
+# for the same output section description - input sections are merged into
+# one output section.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } } \
+# RUN:       SECTIONS { \
+# RUN:          .data : { *(other) } }" > %t.script
+# RUN: ld.lld -o %t6 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t6 | \
+# RUN:   FileCheck -check-prefix=SEC-MULTI %s
+
+#           Idx Name          Size
+# SEC-MULTI: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-MULTI: 2 .data         00000023 {{[0-9a-f]*}} DATA
+# SEC-MULTI: 3 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-MULTI: 4 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-MULTI: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-MULTI: 6 .shstrtab     0000002c {{[0-9a-f]*}}
+# SEC-MULTI: 7 .strtab       00000008 {{[0-9a-f]*}}
+
+.globl _start
+_start:
+    mov $60, %rax
+    mov $42, %rdi
+
+.section .data,"aw"
+.quad 10, 10, 20, 20
+.section other,"aw"
+.short 10
+.byte 20
+.section .shstrtab,""
+.short 20
+.section .bss,"",@nobits
+.short 0
diff --git a/test/ELF/linkerscript-symbol-conflict.s b/test/ELF/linkerscript-symbol-conflict.s
new file mode 100644 (file)
index 0000000..30186ed
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.text : {*(.text.*)} end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 0000000000000121         *ABS*    00000000 end
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript-symbols.s b/test/ELF/linkerscript-symbols.s
new file mode 100644 (file)
index 0000000..1fcd4e8
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.text : {*(.text.*)} text_end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 0000000000000121         *ABS*    00000000 text_end
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript-va.s b/test/ELF/linkerscript-va.s
new file mode 100644 (file)
index 0000000..25d0bd2
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .foo          00000004 0000000000000120 DATA
+# CHECK-NEXT:   2 .boo          00000004 0000000000000124 DATA
+# CHECK-NEXT:   3 .text         00000001 0000000000000128 TEXT DATA
+
+.global _start
+_start:
+ nop
+
+.section .foo, "a"
+foo:
+ .long 0
+
+.section .boo, "a"
+boo:
+ .long 0
diff --git a/test/ELF/linkerscript.s b/test/ELF/linkerscript.s
new file mode 100644 (file)
index 0000000..4ee7416
--- /dev/null
@@ -0,0 +1,120 @@
+# There is some bad quoting interaction between lit's internal shell, which is
+# implemented in Python, and the Cygwin implementations of the Unix utilities.
+# Avoid running these tests on Windows for now by requiring a real shell.
+
+# REQUIRES: shell
+
+# REQUIRES: x86
+# RUN: mkdir -p %t.dir
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/libsearch-st.s -o %t2.o
+# RUN: rm -f %t.dir/libxyz.a
+# RUN: llvm-ar rcs %t.dir/libxyz.a %t2.o
+
+# RUN: echo "EXTERN( undef undef2 )" > %t.script
+# RUN: ld.lld %t -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "INPUT(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" =libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script
+# RUN: ld.lld -o %t2 %t.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" -lxyz )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.script
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.dir/xyz.script
+# RUN: not ld.lld -o %t2 %t.script
+# RUN: not ld.lld -o %t2 %t.script --sysroot=%t.dir
+# RUN: ld.lld -o %t2 %t.dir/xyz.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t.script2\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld -o %t2 %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "ENTRY(_wrong_label)" > %t.script
+# RUN: not ld.lld -o %t2 %t.script %t > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR-ENTRY %s < %t.log
+
+# ERR-ENTRY: undefined symbol: _wrong_label
+
+# -e has precedence over linker script's ENTRY.
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -e _start -o %t2 %t.script %t
+# RUN: llvm-readobj -file-headers -symbols %t2 | \
+# RUN:   FileCheck -check-prefix=ENTRY-OVERLOAD %s
+
+# ENTRY-OVERLOAD: Entry: [[ENTRY:0x[0-9A-F]+]]
+# ENTRY-OVERLOAD: Name: _start
+# ENTRY-OVERLOAD-NEXT: Value: [[ENTRY]]
+
+# RUN: echo "OUTPUT_FORMAT(elf64-x86-64) /*/*/ GROUP(\"%t\" )" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(AS_NEEDED(\"%t\"))" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: rm -f %t.out
+# RUN: echo "OUTPUT(\"%t.out\")" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "SEARCH_DIR(/lib/foo/blah)" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";SEARCH_DIR(x);SEARCH_DIR(y);" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "INCLUDE \"%t.script2\" OUTPUT(\"%t.out\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "FOO(BAR)" > %t.script
+# RUN: not ld.lld -o foo %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR1 %s < %t.log
+
+# ERR1: unknown directive: FOO
+
+.globl _start, _label
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+_label:
+  syscall
diff --git a/test/ELF/linkerscript2.s b/test/ELF/linkerscript2.s
new file mode 100644 (file)
index 0000000..6ecd9e7
--- /dev/null
@@ -0,0 +1,17 @@
+# There is some bad quoting interaction between lit's internal shell, which is
+# implemented in Python, and the Cygwin implementations of the Unix utilities.
+# Avoid running these tests on Windows for now by requiring a real shell.
+
+# REQUIRES: shell
+
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd \
+# RUN:   %p/Inputs/libsearch-dyn.s -o %tdyn.o
+# RUN: mkdir -p %t.dir
+# RUN: ld.lld -shared %tdyn.o -o %t.dir/libls.so
+# RUN: echo "SEARCH_DIR(\"%t.dir\")" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script -lls %t
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/lit.local.cfg b/test/ELF/lit.local.cfg
new file mode 100644 (file)
index 0000000..b93a36d
--- /dev/null
@@ -0,0 +1,2 @@
+config.suffixes = ['.test', '.s', '.ll']
+
diff --git a/test/ELF/llvm33-rela-outside-group.s b/test/ELF/llvm33-rela-outside-group.s
new file mode 100644 (file)
index 0000000..8e7e7c4
--- /dev/null
@@ -0,0 +1,11 @@
+// Input file generated with:
+// llvm33/llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %S/Inputs/llvm33-rela-outside-group.o
+//
+// RUN: ld.lld -shared %S/Inputs/llvm33-rela-outside-group.o %S/Inputs/llvm33-rela-outside-group.o
+
+       .global bar
+       .weak   _Z3fooIiEvv
+
+       .section        .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+_Z3fooIiEvv:
+       callq   bar@PLT
diff --git a/test/ELF/local-dynamic.s b/test/ELF/local-dynamic.s
new file mode 100644 (file)
index 0000000..436516a
--- /dev/null
@@ -0,0 +1,94 @@
+// Check that local symbols are not inserted into dynamic table.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -shared -o %t1.so
+// RUN: llvm-readobj -t -dyn-symbols %t1.so | FileCheck %s
+// REQUIRES: x86
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: blah
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: goo
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start@
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+
+blah:
+foo:
+goo:
+
+
diff --git a/test/ELF/local-got-pie.s b/test/ELF/local-got-pie.s
new file mode 100644 (file)
index 0000000..e846bd4
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -pie
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+.globl _start
+_start:
+ call foo@gotpcrel
+
+ .hidden foo
+ .global foo
+foo:
+ nop
+
+// 0x20A0 - 1001 - 5 = 4250
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:   1000: {{.*}} callq 4251
+// DISASM:      foo:
+// DISASM-NEXT:   1005: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20A0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x20A0 R_X86_64_RELATIVE - 0x1005
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/local-got-shared.s b/test/ELF/local-got-shared.s
new file mode 100644 (file)
index 0000000..08e6583
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+bar:
+       call foo@gotpcrel
+
+        .hidden foo
+        .global foo
+foo:
+        nop
+
+// 0x2090 - 0x1000 - 5 = 4235
+// DISASM:      bar:
+// DISASM-NEXT:   1000: {{.*}} callq 4235
+
+// DISASM:      foo:
+// DISASM-NEXT:   1005: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2090 R_X86_64_RELATIVE - 0x1005
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/local-got.s b/test/ELF/local-got.s
new file mode 100644 (file)
index 0000000..1a8fa0d
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r -section-data %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+        .globl _start
+_start:
+       call bar@gotpcrel
+       call foo@gotpcrel
+
+        .global foo
+foo:
+        nop
+
+// 0x120B0 - 0x11000 - 5 =  4251
+// 0x120B8 - 0x11005 - 5 =  4254
+// DISASM:      _start:
+// DISASM-NEXT:   11000: {{.*}} callq 4267
+// DISASM-NEXT:   11005: {{.*}} callq 4270
+
+// DISASM:      foo:
+// DISASM-NEXT:   1100a: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x120B0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// 0x1200a in little endian
+// CHECK-NEXT:   0000:  00000000 00000000 0A100100 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x120B0 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/local-undefined-symbol.s b/test/ELF/local-undefined-symbol.s
new file mode 100644 (file)
index 0000000..34ef847
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t1
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK:     Symbols [
+# CHECK-NOT:  Name: foo
+
+.global _start
+_start:
+ jmp foo
+
+.local foo
diff --git a/test/ELF/local.s b/test/ELF/local.s
new file mode 100644 (file)
index 0000000..cc879e1
--- /dev/null
@@ -0,0 +1,82 @@
+// Check that symbol table is correctly populated with local symbols.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t1
+// RUN: llvm-readobj -t -s %t1 | FileCheck %s
+// REQUIRES: x86
+
+// Check that Info is equal to the number of local symbols.
+// CHECK:   Section {
+// CHECK:     Name: .symtab
+// CHECK-NEXT:     Type: SHT_SYMTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info: 5
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: abs
+// CHECK-NEXT:     Value: 0x2A
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Absolute
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: blah
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: goo
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+
+blah:
+foo:
+goo:
+abs = 42
diff --git a/test/ELF/lto/Inputs/archive-2.ll b/test/ELF/lto/Inputs/archive-2.ll
new file mode 100644 (file)
index 0000000..8236cfe
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/archive-3.ll b/test/ELF/lto/Inputs/archive-3.ll
new file mode 100644 (file)
index 0000000..ad8fb1e
--- /dev/null
@@ -0,0 +1,5 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/archive.ll b/test/ELF/lto/Inputs/archive.ll
new file mode 100644 (file)
index 0000000..71c1e4f
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/available-externally.ll b/test/ELF/lto/Inputs/available-externally.ll
new file mode 100644 (file)
index 0000000..b8583ea
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @zed() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/comdat.s b/test/ELF/lto/Inputs/comdat.s
new file mode 100644 (file)
index 0000000..6f6e5ae
--- /dev/null
@@ -0,0 +1,5 @@
+    .section .text.f,"axG",@progbits,c,comdat
+    .globl foo
+
+foo:
+    retq
diff --git a/test/ELF/lto/Inputs/common.s b/test/ELF/lto/Inputs/common.s
new file mode 100644 (file)
index 0000000..e2cd9e6
--- /dev/null
@@ -0,0 +1 @@
+        .comm   a,8,4
diff --git a/test/ELF/lto/Inputs/drop-debug-info.bc b/test/ELF/lto/Inputs/drop-debug-info.bc
new file mode 100644 (file)
index 0000000..f9c471f
Binary files /dev/null and b/test/ELF/lto/Inputs/drop-debug-info.bc differ
diff --git a/test/ELF/lto/Inputs/drop-linkage.ll b/test/ELF/lto/Inputs/drop-linkage.ll
new file mode 100644 (file)
index 0000000..0e3dc7a
--- /dev/null
@@ -0,0 +1,12 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+define linkonce void @foo() comdat {
+  ret void
+}
+
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/dynsym.s b/test/ELF/lto/Inputs/dynsym.s
new file mode 100644 (file)
index 0000000..a69f870
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret
diff --git a/test/ELF/lto/Inputs/internalize-exportdyn.ll b/test/ELF/lto/Inputs/internalize-exportdyn.ll
new file mode 100644 (file)
index 0000000..21ac358
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define weak_odr void @bah() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/internalize-undef.ll b/test/ELF/lto/Inputs/internalize-undef.ll
new file mode 100644 (file)
index 0000000..71c1e4f
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/irmover-error.ll b/test/ELF/lto/Inputs/irmover-error.ll
new file mode 100644 (file)
index 0000000..86ed259
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{ i32 1, !"foo", i32 2 }
+
+!llvm.module.flags = !{ !0 }
diff --git a/test/ELF/lto/Inputs/linkonce-odr.ll b/test/ELF/lto/Inputs/linkonce-odr.ll
new file mode 100644 (file)
index 0000000..0b38288
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define linkonce_odr void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/linkonce.ll b/test/ELF/lto/Inputs/linkonce.ll
new file mode 100644 (file)
index 0000000..a6738b3
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define linkonce void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/resolution.s b/test/ELF/lto/Inputs/resolution.s
new file mode 100644 (file)
index 0000000..60b7870
--- /dev/null
@@ -0,0 +1,4 @@
+        .data
+        .global a
+a:
+        .long 9
diff --git a/test/ELF/lto/Inputs/save-temps.ll b/test/ELF/lto/Inputs/save-temps.ll
new file mode 100644 (file)
index 0000000..d6e6eb6
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @bar() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/shared.s b/test/ELF/lto/Inputs/shared.s
new file mode 100644 (file)
index 0000000..ab79ed1
--- /dev/null
@@ -0,0 +1,7 @@
+.globl  printf
+.type printf, @function
+printf:
+
+.globl  puts
+.type puts, @function
+puts:
diff --git a/test/ELF/lto/Inputs/start-lib1.ll b/test/ELF/lto/Inputs/start-lib1.ll
new file mode 100644 (file)
index 0000000..9f42e6a
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/start-lib2.ll b/test/ELF/lto/Inputs/start-lib2.ll
new file mode 100644 (file)
index 0000000..68b3c83
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @bar() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/tls-mixed.s b/test/ELF/lto/Inputs/tls-mixed.s
new file mode 100644 (file)
index 0000000..b31ae3d
--- /dev/null
@@ -0,0 +1,4 @@
+.globl foo
+.section .tbss,"awT",@nobits
+foo:
+.long 0
diff --git a/test/ELF/lto/Inputs/type-merge.ll b/test/ELF/lto/Inputs/type-merge.ll
new file mode 100644 (file)
index 0000000..c316421
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @zed() {
+  call void @bar()
+  ret void
+}
+declare void @bar()
diff --git a/test/ELF/lto/Inputs/type-merge2.ll b/test/ELF/lto/Inputs/type-merge2.ll
new file mode 100644 (file)
index 0000000..79fd1f8
--- /dev/null
@@ -0,0 +1,8 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%zed = type { i16 }
+define void @bar(%zed* %this)  {
+  store %zed* %this, %zed** null
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/undef-mixed.s b/test/ELF/lto/Inputs/undef-mixed.s
new file mode 100644 (file)
index 0000000..2e4b7e1
--- /dev/null
@@ -0,0 +1,3 @@
+        .globl  bar
+bar:
+        retq
diff --git a/test/ELF/lto/Inputs/unnamed-addr-lib.s b/test/ELF/lto/Inputs/unnamed-addr-lib.s
new file mode 100644 (file)
index 0000000..e6ebce0
--- /dev/null
@@ -0,0 +1,6 @@
+        .protected foo
+        .global foo
+foo:
+
+        .global bar
+bar:
diff --git a/test/ELF/lto/Inputs/visibility.s b/test/ELF/lto/Inputs/visibility.s
new file mode 100644 (file)
index 0000000..db1379c
--- /dev/null
@@ -0,0 +1,8 @@
+        .global g
+g:
+        ret
+
+        .data
+        .global a
+a:
+        .long 41
diff --git a/test/ELF/lto/archive-2.ll b/test/ELF/lto/archive-2.ll
new file mode 100644 (file)
index 0000000..6712d60
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive-2.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+
+; CHECK:      Name: _start (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @g() {
+  call void @_start()
+  ret void
+}
+
+declare void @_start()
+
diff --git a/test/ELF/lto/archive-3.ll b/test/ELF/lto/archive-3.ll
new file mode 100644 (file)
index 0000000..350c892
--- /dev/null
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive-3.ll -o %t1.o
+; RUN: llvm-as %s -o %t2.o
+
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o  -o %t3 -save-temps
+; RUN: llvm-dis %t3.lto.bc -o - | FileCheck %s
+
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: ld.lld -m elf_x86_64 %t.a %t1.o %t2.o  -o %t3 -save-temps
+; RUN: llvm-dis %t3.lto.bc -o - | FileCheck %s
+
+; CHECK: define internal void @foo() {
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/archive.ll b/test/ELF/lto/archive.ll
new file mode 100644 (file)
index 0000000..b3f69fb
--- /dev/null
@@ -0,0 +1,37 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+
+
+; CHECK:      Name: g (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+; CHECK:      Name: f (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+declare void @f()
+
diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll
new file mode 100644 (file)
index 0000000..d76e418
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps
+; RUN: llvm-dis %t.lto.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm ".weak patatino"
+module asm ".equ patatino, foo"
+
+declare void @patatino()
+
+define void @foo() {
+  ret void
+}
+
+define void @_start() {
+  call void @patatino()
+  ret void
+}
+
+; CHECK: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata"
+; CHECK: define internal void @foo
+
diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll
new file mode 100644 (file)
index 0000000..74aa860
--- /dev/null
@@ -0,0 +1,22 @@
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o
+; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps
+; RUN: llvm-dis < %t.so.lto.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo() {
+  call void @bar()
+  call void @zed()
+  ret void
+}
+define available_externally void @bar() {
+  ret void
+}
+define available_externally void @zed() {
+  ret void
+}
+
+; CHECK: define available_externally void @bar() {
+; CHECK: define void @zed() {
diff --git a/test/ELF/lto/combined-lto-object-name.ll b/test/ELF/lto/combined-lto-object-name.ll
new file mode 100644 (file)
index 0000000..f5b7e3a
--- /dev/null
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2 2>&1 | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @foo()
+define void @_start() {
+  call void @foo()
+  ret void
+}
+
+; CHECK: undefined symbol: foo in {{.*}}combined-lto-object-name.ll.tmp.o
diff --git a/test/ELF/lto/comdat.ll b/test/ELF/lto/comdat.ll
new file mode 100644 (file)
index 0000000..e1384d0
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: foo
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+define void @foo() comdat {
+  ret void
+}
+
diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll
new file mode 100644 (file)
index 0000000..1509585
--- /dev/null
@@ -0,0 +1,40 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.o -o %t2.so -shared
+; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$c = comdat any
+
+define protected void @foo() comdat($c) {
+  ret void
+}
+
+; CHECK: Symbol {
+; CHECK:   Name: foo
+; CHECK-NEXT:   Value: 0x1000
+; CHECK-NEXT:   Size: 1
+; CHECK-NEXT:   Binding: Global
+; CHECK-NEXT:   Type: Function
+; CHECK-NEXT:   Other [
+; CHECK-NEXT:     STV_PROTECTED
+; CHECK-NEXT:   ]
+; CHECK-NEXT:   Section: .text
+; CHECK-NEXT: }
+
+; OTHER: Symbol {
+; OTHER:   Name: foo
+; OTHER-NEXT:   Value: 0x1000
+; OTHER-NEXT:   Size: 0
+; OTHER-NEXT:   Binding: Global
+; OTHER-NEXT:   Type: None
+; OTHER-NEXT:   Other [
+; OTHER-NEXT:     STV_PROTECTED
+; OTHER-NEXT:   ]
+; OTHER-NEXT:   Section: .text
+; OTHER-NEXT: }
diff --git a/test/ELF/lto/common.ll b/test/ELF/lto/common.ll
new file mode 100644 (file)
index 0000000..b020024
--- /dev/null
@@ -0,0 +1,31 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -s -t %t.so | FileCheck %s
+
+; CHECK:      Name: .bss
+; CHECK-NEXT: Type: SHT_NOBITS
+; CHECK-NEXT: Flags [
+; CHECK-NEXT:   SHF_ALLOC
+; CHECK-NEXT:   SHF_WRITE
+; CHECK-NEXT: ]
+; CHECK-NEXT: Address:
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Size: 8
+; CHECK-NEXT: Link: 0
+; CHECK-NEXT: Info: 0
+; CHECK-NEXT: AddressAlignment: 8
+
+; CHECK:      Name: a
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 8
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Object
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .bss
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = common global i32 0, align 8
diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll
new file mode 100644 (file)
index 0000000..59a2676
--- /dev/null
@@ -0,0 +1,24 @@
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps
+; RUN: llvm-dis < %t.lto.bc | FileCheck %s
+; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = common global i8 0, align 8
+
+; Shared library case, we ensure that the bitcode generated file
+; has not the a symbol but is appears in the final shared library
+; produced.
+; CHECK-NOT: @a = common global i8 0, align 8
+
+; SHARED: Symbol {
+; SHARED:   Name: a
+; SHARED-NEXT:   Value: 0x2000
+; SHARED-NEXT:   Size: 1
+; SHARED-NEXT:   Binding: Global
+; SHARED-NEXT:   Type: Object
+; SHARED-NEXT:   Other: 0
+; SHARED-NEXT:   Section: .bss
+; SHARED-NEXT: }
diff --git a/test/ELF/lto/ctors.ll b/test/ELF/lto/ctors.ll
new file mode 100644 (file)
index 0000000..7fce645
--- /dev/null
@@ -0,0 +1,18 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-readobj -sections %t.so | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define void @ctor() {
+  call void asm "nop", ""()
+  ret void
+}
+
+; The llvm.global_ctors should end up producing constructors.
+; On x86-64 (linux) we should always emit .init_array and never .ctors.
+; CHECK: Name: .init_array
+; CHECK-NOT: Name: .ctors
diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll
new file mode 100644 (file)
index 0000000..c6cd94f
--- /dev/null
@@ -0,0 +1,23 @@
+; RUN: llvm-as %s -o %t.o
+
+; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o
+; RUN: llvm-dis < %t2.o.lto.bc | FileCheck %s
+
+; CHECK: @GlobalValueName
+; CHECK: @foo(i32 %in)
+; CHECK: somelabel:
+; CHECK:  %GV = load i32, i32* @GlobalValueName
+; CHECK:  %add = add i32 %in, %GV
+; CHECK:  ret i32 %add
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@GlobalValueName = global i32 0
+
+define i32 @foo(i32 %in) {
+somelabel:
+  %GV = load i32, i32* @GlobalValueName
+  %add = add i32 %in, %GV
+  ret i32 %add
+}
diff --git a/test/ELF/lto/drop-debug-info.ll b/test/ELF/lto/drop-debug-info.ll
new file mode 100644 (file)
index 0000000..7a7ed5e
--- /dev/null
@@ -0,0 +1,9 @@
+; REQUIRES: x86
+;
+; drop-debug-info.bc was created from "void f(void) {}" with clang 3.5 and
+; -gline-tables-only, so it contains old debug info.
+;
+; RUN: ld.lld -m elf_x86_64 -shared %p/Inputs/drop-debug-info.bc \
+; RUN: -disable-verify 2>&1 | FileCheck %s
+; CHECK: warning: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc
+
diff --git a/test/ELF/lto/drop-linkage.ll b/test/ELF/lto/drop-linkage.ll
new file mode 100644 (file)
index 0000000..fd111c1
--- /dev/null
@@ -0,0 +1,14 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; REQUIRES: x86
+; RUN: llc %s -o %t.o -filetype=obj
+; RUN: llvm-as %p/Inputs/drop-linkage.ll -o %t2.o
+; RUN: ld.lld %t.o %t2.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+
+define void @foo() {
+  ret void
+}
+
+; CHECK: declare void @foo()
diff --git a/test/ELF/lto/duplicated.ll b/test/ELF/lto/duplicated.ll
new file mode 100644 (file)
index 0000000..6ef6772
--- /dev/null
@@ -0,0 +1,10 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
+; CHECK: duplicate symbol: f in {{.*}}.o and {{.*}}.o
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll
new file mode 100644 (file)
index 0000000..0e950b3
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "{ foo; };" > %t.list
+; RUN: ld.lld -m elf_x86_64 -o %t --dynamic-list %t.list -pie %t.o
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+; CHECK:      Name:     foo@
+; CHECK-NEXT: Value:    0x1010
+; CHECK-NEXT: Size:     1
+; CHECK-NEXT: Binding:  Global (0x1)
+; CHECK-NEXT: Type:     Function
+; CHECK-NEXT: Other:    0
+; CHECK-NEXT: Section:  .text
+; CHECK-NEXT: }
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/dynsym.ll b/test/ELF/lto/dynsym.ll
new file mode 100644 (file)
index 0000000..5885960
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t.o %p/Inputs/dynsym.s
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.so -o %t
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  call void @foo()
+  ret void
+}
+
+; CHECK:      Name: foo
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding:
+; CHECK-NEXT: Type:
+; CHECK-NEXT: Other:
+; CHECK-NEXT: Section: .text
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/inline-asm.ll b/test/ELF/lto/inline-asm.ll
new file mode 100644 (file)
index 0000000..b6af6a5
--- /dev/null
@@ -0,0 +1,11 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo() {
+  call void asm "nop", ""()
+  ret void
+}
diff --git a/test/ELF/lto/internalize-basic.ll b/test/ELF/lto/internalize-basic.ll
new file mode 100644 (file)
index 0000000..396b9cb
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define hidden void @foo() {
+  ret void
+}
+
+; Check that _start is not internalized.
+; CHECK: define void @_start()
+
+; Check that foo function is correctly internalized.
+; CHECK: define internal void @foo()
diff --git a/test/ELF/lto/internalize-exportdyn.ll b/test/ELF/lto/internalize-exportdyn.ll
new file mode 100644 (file)
index 0000000..bee9a1e
--- /dev/null
@@ -0,0 +1,47 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps
+; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @foo() {
+  ret void
+}
+
+define hidden void @bar() {
+  ret void
+}
+
+define linkonce_odr void @zed() local_unnamed_addr {
+  ret void
+}
+
+define linkonce_odr void @zed2() unnamed_addr {
+  ret void
+}
+
+define linkonce_odr void @bah() {
+  ret void
+}
+
+define linkonce_odr void @baz() {
+  ret void
+}
+
+@use_baz = global void ()* @baz
+
+; Check what gets internalized.
+; CHECK: define void @_start()
+; CHECK: define void @foo()
+; CHECK: define internal void @bar()
+; CHECK: define internal void @zed()
+; CHECK: define internal void @zed2()
+; CHECK: define weak_odr void @bah()
+; CHECK: define weak_odr void @baz()
diff --git a/test/ELF/lto/internalize-llvmused.ll b/test/ELF/lto/internalize-llvmused.ll
new file mode 100644 (file)
index 0000000..46c90a6
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define hidden void @f() {
+  ret void
+}
+
+@llvm.used = appending global [1 x i8*] [ i8* bitcast (void ()* @f to i8*)]
+
+; Check that f is not internalized.
+; CHECK: define hidden void @f()
diff --git a/test/ELF/lto/internalize-undef.ll b/test/ELF/lto/internalize-undef.ll
new file mode 100644 (file)
index 0000000..5d74c31
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: llvm-dis < %t.lto.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+define void @_start() {
+  call void @f()
+  ret void
+}
+
+; CHECK: define internal void @f()
diff --git a/test/ELF/lto/internalize-version-script.ll b/test/ELF/lto/internalize-version-script.ll
new file mode 100644 (file)
index 0000000..c25328f
--- /dev/null
@@ -0,0 +1,22 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "{ global: foo; local: *; };" > %t.script
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+define void @bar() {
+  ret void
+}
+
+; Check that foo is not internalized.
+; CHECK: define void @foo()
+
+; Check that bar is correctly internalized.
+; CHECK: define internal void @bar()
diff --git a/test/ELF/lto/invalid-bitcode.ll b/test/ELF/lto/invalid-bitcode.ll
new file mode 100644 (file)
index 0000000..eceffb1
--- /dev/null
@@ -0,0 +1,12 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o 2>&1 | FileCheck %s
+
+; CHECK: invalid bitcode file:
+
+; This bitcode file has no datalayout.
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/irmover-error.ll b/test/ELF/lto/irmover-error.ll
new file mode 100644 (file)
index 0000000..aee4114
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llvm-as -o %t1.bc %s
+; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-error.ll
+; RUN: not ld.lld -m elf_x86_64 %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
+
+; CHECK: failed to link module {{.*}}2.bc: linking module flags 'foo': IDs have conflicting values
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{ i32 1, !"foo", i32 1 }
+
+!llvm.module.flags = !{ !0 }
diff --git a/test/ELF/lto/linkage.ll b/test/ELF/lto/linkage.ll
new file mode 100644 (file)
index 0000000..5af9b32
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+; RUN: llvm-nm %t.so | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Should not encounter a duplicate symbol error for @.str
+@.str = private unnamed_addr constant [4 x i8] c"Hey\00", align 1
+
+; Should not encounter a duplicate symbol error for @llvm.global_ctors
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define internal void @ctor() {
+  ret void
+}
+
+; Should not try to merge a declaration into the combined module.
+declare i32 @llvm.ctpop.i32(i32)
+; CHECK-NOT: llvm.ctpop.i32
diff --git a/test/ELF/lto/linkonce-odr.ll b/test/ELF/lto/linkonce-odr.ll
new file mode 100644 (file)
index 0000000..569e271
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %p/Inputs/linkonce-odr.ll -o %t1.o
+; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+declare void @f()
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+; Be sure that 'f' is kept and has weak_odr linkage.
+; CHECK: define weak_odr void @f()
diff --git a/test/ELF/lto/linkonce.ll b/test/ELF/lto/linkonce.ll
new file mode 100644 (file)
index 0000000..f980eff
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %p/Inputs/linkonce.ll -o %t1.o
+; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+declare void @f()
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+; Be sure that 'f' is kept and has weak linkage.
+; CHECK: define weak void @f()
diff --git a/test/ELF/lto/lto-start.ll b/test/ELF/lto/lto-start.ll
new file mode 100644 (file)
index 0000000..e93eecf
--- /dev/null
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2
+; RUN: llvm-readobj -t %t2 | FileCheck %s
+
+; CHECK:      Format: ELF64-x86-64
+; CHECK-NEXT: Arch: x86_64
+; CHECK-NEXT: AddressSize: 64bit
+
+; CHECK:      Name: _start
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other:
+; CHECK-NEXT: Section: .text
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/ltopasses-basic.ll b/test/ELF/lto/ltopasses-basic.ll
new file mode 100644 (file)
index 0000000..5bd5f41
--- /dev/null
@@ -0,0 +1,18 @@
+; REQUIRES: x86
+; RUN: rm -f %t.so.lto.bc %t.so.lto.opt.bc %t.so.lto.o
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define void @ctor() {
+  ret void
+}
+
+; `@ctor` doesn't do anything and so the optimizer should kill it, leaving no ctors
+; CHECK: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer
+
+; MLLVM: Pass Arguments:
diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll
new file mode 100644 (file)
index 0000000..3e982e0
--- /dev/null
@@ -0,0 +1,30 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \
+; RUN: --lto-newpm-passes=ipsccp -shared
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+; RUN: llvm-dis %t2.so.lto.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @barrier() {
+  fence seq_cst
+  ret void
+}
+
+; IPSCCP won't remove the fence.
+; CHECK: define void @barrier() {
+; CHECK-NEXT: fence seq_cst
+; CHECK-NEXT: ret void
+
+; LowerAtomic will remove the fence.
+; ATOMIC: define void @barrier() {
+; ATOMIC-NEXT: ret void
+
+; Check that invalid passes are rejected gracefully.
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \
+; RUN:   --lto-newpm-passes=iamnotapass -shared 2>&1 | \
+; RUN:   FileCheck %s --check-prefix=INVALID
+; INVALID: unable to parse pass pipeline description: iamnotapass
diff --git a/test/ELF/lto/metadata.ll b/test/ELF/lto/metadata.ll
new file mode 100644 (file)
index 0000000..3e73de5
--- /dev/null
@@ -0,0 +1,13 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define weak void @foo(i32* %p) {
+  store i32 5, i32* %p, align 4, !tbaa !0
+  ret void
+}
+
+!0 = !{!"Simple C/C++ TBAA"}
diff --git a/test/ELF/lto/mix-platforms.ll b/test/ELF/lto/mix-platforms.ll
new file mode 100644 (file)
index 0000000..3478caa
--- /dev/null
@@ -0,0 +1,10 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/shared.s -o %t386.o -filetype=obj -triple=i386-pc-linux
+; RUN: ld.lld %t386.o -o %ti386.so -shared
+; RUN: llvm-as %s -o %tx64.o
+; RUN: not ld.lld %ti386.so %tx64.o -o %t 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: {{.*}}x64.o is incompatible with {{.*}}i386.so
diff --git a/test/ELF/lto/module-asm.ll b/test/ELF/lto/module-asm.ll
new file mode 100644 (file)
index 0000000..1389b9f
--- /dev/null
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t
+; RUN: llvm-nm %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm ".text"
+module asm ".globl foo"
+; CHECK: T foo
+module asm "foo: ret"
+
+declare void @foo()
+
+define void @_start() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll
new file mode 100644 (file)
index 0000000..934bf01
--- /dev/null
@@ -0,0 +1,29 @@
+; RUN: llvm-as -o %t.o %s
+; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o
+; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --lto-O2 %t.o
+; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: ld.lld -o %t2a -m elf_x86_64 -e main %t.o
+; RUN: llvm-nm %t2a | FileCheck --check-prefix=CHECK-O2 %s
+
+; Reject invalid optimization levels.
+; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O6 %t.o 2>&1 | \
+; RUN:   FileCheck --check-prefix=INVALID %s
+; INVALID: invalid optimization level for LTO: 6
+; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \
+; RUN:   FileCheck --check-prefix=INVALIDNEGATIVE %s
+; INVALIDNEGATIVE: invalid optimization level for LTO: -1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-O0: foo
+; CHECK-O2-NOT: foo
+define internal void @foo() {
+  ret void
+}
+
+define void @main() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/parallel-internalize.ll b/test/ELF/lto/parallel-internalize.ll
new file mode 100644 (file)
index 0000000..58ed50e
--- /dev/null
@@ -0,0 +1,57 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.bc %s
+; RUN: ld.lld -m elf_x86_64 --lto-jobs=2 -save-temps -o %t %t.bc -e foo --lto-O0
+; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s
+; RUN: llvm-nm %t0.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+; CHECK:      Symbols [
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name:  (0)
+; CHECK-NEXT:     Value: 0x0
+; CHECK-NEXT:     Size: 0
+; CHECK-NEXT:     Binding: Local (0x0)
+; CHECK-NEXT:     Type: None (0x0)
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: Undefined (0x0)
+; CHECK-NEXT:   }
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name: bar (5)
+; CHECK-NEXT:     Value: 0x11010
+; CHECK-NEXT:     Size: 8
+; CHECK-NEXT:     Binding: Local (0x0)
+; CHECK-NEXT:     Type: Function (0x2)
+; CHECK-NEXT:     Other [ (0x2)
+; CHECK-NEXT:       STV_HIDDEN (0x2)
+; CHECK-NEXT:     ]
+; CHECK-NEXT:     Section: .text (0x2)
+; CHECK-NEXT:   }
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name: foo (1)
+; CHECK-NEXT:     Value: 0x11000
+; CHECK-NEXT:     Size: 8
+; CHECK-NEXT:     Binding: Global (0x1)
+; CHECK-NEXT:     Type: Function (0x2)
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: .text (0x2)
+; CHECK-NEXT:   }
+; CHECK-NEXT: ]
+; CHECK-NEXT: DynamicSymbols [
+; CHECK-NEXT: ]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK0: U bar
+; CHECK0: T foo
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK1: T bar
+; CHECK1: U foo
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/parallel.ll b/test/ELF/lto/parallel.ll
new file mode 100644 (file)
index 0000000..8ea62ef
--- /dev/null
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.bc %s
+; RUN: ld.lld -m elf_x86_64 --lto-jobs=2 -save-temps -o %t %t.bc -shared
+; RUN: llvm-nm %t0.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK0-NOT: bar
+; CHECK0: T foo
+; CHECK0-NOT: bar
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK1-NOT: foo
+; CHECK1: T bar
+; CHECK1-NOT: foo
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/pic.ll b/test/ELF/lto/pic.ll
new file mode 100644 (file)
index 0000000..abc514d
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t.so -shared
+; RUN: llvm-readobj -r %t.so | FileCheck %s
+
+; CHECK:      Relocations [
+; CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+; CHECK-NEXT:     R_X86_64_JUMP_SLOT bar 0x0
+; CHECK-NEXT:   }
+; CHECK-NEXT: ]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll
new file mode 100644 (file)
index 0000000..929e124
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so
+; RUN: llvm-readobj -r %t.so.lto.o | FileCheck %s
+
+; Test that we produce R_X86_64_REX_GOTPCRELX instead of R_X86_64_GOTPCREL
+; CHECK: R_X86_64_REX_GOTPCRELX foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = external global i32
+define i32 @bar() {
+  %t = load i32, i32* @foo
+  ret i32 %t
+}
diff --git a/test/ELF/lto/resolution.ll b/test/ELF/lto/resolution.ll
new file mode 100644 (file)
index 0000000..b3fcf1d
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -s --section-data %t.so | FileCheck %s
+
+; CHECK:      Name: .data
+; CHECK-NEXT: Type: SHT_PROGBITS
+; CHECK-NEXT: Flags [
+; CHECK-NEXT:   SHF_ALLOC
+; CHECK-NEXT:   SHF_WRITE
+; CHECK-NEXT: ]
+; CHECK-NEXT: Address:
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: Link: 0
+; CHECK-NEXT: Info: 0
+; CHECK-NEXT: AddressAlignment: 1
+; CHECK-NEXT: EntrySize: 0
+; CHECK-NEXT: SectionData (
+; CHECK-NEXT:   0000: 09000000 |{{.*}}|
+; CHECK-NEXT: )
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = weak global i32 8
diff --git a/test/ELF/lto/save-temps.ll b/test/ELF/lto/save-temps.ll
new file mode 100644 (file)
index 0000000..0b0f939
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: cd %T
+; RUN: rm -f a.out a.out.lto.bc a.out.lto.o
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o
+; RUN: ld.lld -shared -m elf_x86_64 %t.o %t2.o -save-temps
+; RUN: llvm-nm a.out | FileCheck %s
+; RUN: llvm-nm a.out.lto.bc | FileCheck %s
+; RUN: llvm-nm a.out.lto.o | FileCheck %s
+; RUN: llvm-dis a.out.lto.bc
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+; CHECK: T bar
+; CHECK: T foo
diff --git a/test/ELF/lto/shlib-undefined.ll b/test/ELF/lto/shlib-undefined.ll
new file mode 100644 (file)
index 0000000..db60de8
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo .global __progname > %t2.s
+; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
+; RUN: ld.lld -shared %t2.o -o %t2.so
+; RUN: ld.lld -o %t %t.o %t2.so
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+; CHECK:      Name:     __progname@
+; CHECK-NEXT: Value:    0x11010
+; CHECK-NEXT: Size:     1
+; CHECK-NEXT: Binding:  Global (0x1)
+; CHECK-NEXT: Type:     Function
+; CHECK-NEXT: Other:    0
+; CHECK-NEXT: Section:  .text
+; CHECK-NEXT: }
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @__progname() {
+  ret void
+}
diff --git a/test/ELF/lto/start-lib.ll b/test/ELF/lto/start-lib.ll
new file mode 100644 (file)
index 0000000..ec73954
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+;
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/start-lib1.ll -o %t2.o
+; RUN: llvm-as %p/Inputs/start-lib2.ll -o %t3.o
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s
+; TEST1: Name: bar
+; TEST1: Name: foo
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s
+; TEST2: Name: bar
+; TEST2-NOT: Name: foo
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s
+; TEST3-NOT: Name: bar
+; TEST3-NOT: Name: foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/tls-mixed.ll b/test/ELF/lto/tls-mixed.ll
new file mode 100644 (file)
index 0000000..524bb4f
--- /dev/null
@@ -0,0 +1,10 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc %p/Inputs/tls-mixed.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Should not encounter TLS-ness mismatch for @foo
+@foo = external thread_local global i32, align 4
diff --git a/test/ELF/lto/tls-preserve.ll b/test/ELF/lto/tls-preserve.ll
new file mode 100644 (file)
index 0000000..8aebcb7
--- /dev/null
@@ -0,0 +1,25 @@
+; TLS attribute needs to be preserved.
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -shared %t1.o -m elf_x86_64 -o %t1
+; RUN: llvm-readobj -t %t1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@tsp_int = thread_local global i32 1
+
+define void @_start() {
+  %val = load i32, i32* @tsp_int
+  ret void
+}
+
+; CHECK: Symbol {
+; CHECK:   Name: tsp_int
+; CHECK-NEXT:   Value: 0x0
+; CHECK-NEXT:   Size: 4
+; CHECK-NEXT:   Binding: Global
+; CHECK-NEXT:   Type: TLS
+; CHECK-NEXT:   Other: 0
+; CHECK-NEXT:   Section: .tdata
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/type-merge.ll b/test/ELF/lto/type-merge.ll
new file mode 100644 (file)
index 0000000..98db539
--- /dev/null
@@ -0,0 +1,26 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/type-merge.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -shared -save-temps
+; RUN: llvm-dis < %t.lto.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo()  {
+  call void @bar(i8* null)
+  ret void
+}
+declare void @bar(i8*)
+
+; CHECK:      define void @foo() {
+; CHECK-NEXT:   call void @bar(i8* null)
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+; CHECK: declare void @bar(i8*)
+
+; CHECK:      define void @zed() {
+; CHECK-NEXT:   call void bitcast (void (i8*)* @bar to void ()*)()
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll
new file mode 100644 (file)
index 0000000..f0931dd
--- /dev/null
@@ -0,0 +1,27 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%zed = type { i8 }
+define void @foo()  {
+  call void @bar(%zed* null)
+  ret void
+}
+declare void @bar(%zed*)
+
+; CHECK:      %zed = type { i8 }
+; CHECK-NEXT: %zed.0 = type { i16 }
+
+; CHECK:      define void @foo() {
+; CHECK-NEXT:   call void bitcast (void (%zed.0*)* @bar to void (%zed*)*)(%zed* null)
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+; CHECK:      define void @bar(%zed.0* %this) {
+; CHECK-NEXT:   store %zed.0* %this, %zed.0** null
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/undef-mixed.ll b/test/ELF/lto/undef-mixed.ll
new file mode 100644 (file)
index 0000000..0fff578
--- /dev/null
@@ -0,0 +1,22 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/undef-mixed.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld %t2.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: bar
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
diff --git a/test/ELF/lto/undef-weak.ll b/test/ELF/lto/undef-weak.ll
new file mode 100644 (file)
index 0000000..215978a
--- /dev/null
@@ -0,0 +1,29 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+
+
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o -o %t2.so %t.a -shared
+; RUN: llvm-readobj -t %t2.so | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare extern_weak void @f()
+define void @foo() {
+  call void @f()
+  ret void
+}
+
+; We should not fetch the archive member.
+
+; CHECK:      Name: f ({{.*}})
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Weak
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
+
diff --git a/test/ELF/lto/undef.ll b/test/ELF/lto/undef.ll
new file mode 100644 (file)
index 0000000..41da610
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK:      Name: bar
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/lto/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll
new file mode 100644 (file)
index 0000000..54fb32c
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/shared.s -o %t1.o -filetype=obj -triple=x86_64-unknown-linux
+; RUN: ld.lld %t1.o -o %t1.so -shared
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld %t1.so %t2.o -m elf_x86_64 -o %t
+; RUN: llvm-readobj -dyn-symbols -dyn-relocations %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@.str = private unnamed_addr constant [6 x i8] c"blah\0A\00", align 1
+
+define i32 @_start() {
+  %str = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0))
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...)
+
+; Check that puts symbol is present in the dynamic symbol table and
+; there's a relocation for it.
+; CHECK: Dynamic Relocations {
+; CHECK-NEXT:  0x13018 R_X86_64_JUMP_SLOT puts 0x0
+; CHECK-NEXT: }
+
+; CHECK: DynamicSymbols [
+; CHECK: Symbol {
+; CHECK:    Name: puts@
diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll
new file mode 100644 (file)
index 0000000..c8c36de
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+@foo = linkonce_odr unnamed_addr constant i32 42, comdat
+
+; CHECK: @foo = internal unnamed_addr constant i32 42, comdat
diff --git a/test/ELF/lto/unnamed-addr-lib.ll b/test/ELF/lto/unnamed-addr-lib.ll
new file mode 100644 (file)
index 0000000..c1c31f8
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-mc %p/Inputs/unnamed-addr-lib.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: ld.lld %t2.o -shared -o %t2.so
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.so -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
+
+; This documents a small limitation of lld's internalization logic. We decide
+; that bar should be in the symbol table because if it is it will preempt the
+; one in the shared library.
+; We could add one extra bit for ODR so that we know that preemption is not
+; necessary, but that is probably not worth it.
+
+; CHECK: @foo = internal unnamed_addr constant i8 42
+; CHECK: @bar = weak_odr unnamed_addr constant i8 42
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = linkonce_odr unnamed_addr constant i8 42
+@bar = linkonce_odr unnamed_addr constant i8 42
diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll
new file mode 100644 (file)
index 0000000..a2c0105
--- /dev/null
@@ -0,0 +1,14 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@a = internal unnamed_addr constant i8 42
+
+define i8* @f() {
+  ret i8* @a
+}
+
+; CHECK: @a = internal unnamed_addr constant i8 42
diff --git a/test/ELF/lto/verify-invalid.ll b/test/ELF/lto/verify-invalid.ll
new file mode 100644 (file)
index 0000000..16d6a3e
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN:   2>&1 | FileCheck -check-prefix=DEFAULT %s
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN:   -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+; -disable-verify should disable the verification of bitcode.
+; DEFAULT:     Pass Arguments: {{.*}} -verify {{.*}} -verify
+; DISABLE-NOT: Pass Arguments: {{.*}} -verify {{.*}} -verify
diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll
new file mode 100644 (file)
index 0000000..11a7f07
--- /dev/null
@@ -0,0 +1,50 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
+; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+define void @bar() {
+  ret void
+}
+
+; CHECK: define void @foo()
+; CHECK: define void @bar()
+
+; DSO: DynamicSymbols [
+; DSO:   Symbol {
+; DSO:     Name: @ (0)
+; DSO:     Value: 0x0
+; DSO:     Size: 0
+; DSO:     Binding: Local
+; DSO:     Type: None
+; DSO:     Other: 0
+; DSO:     Section: Undefined
+; DSO:   }
+; DSO:   Symbol {
+; DSO:     Name: foo@@VERSION_1.0
+; DSO:     Value: 0x1000
+; DSO:     Size: 1
+; DSO:     Binding: Global
+; DSO:     Type: Function
+; DSO:     Other: 0
+; DSO:     Section: .text
+; DSO:   }
+; DSO:   Symbol {
+; DSO:     Name: bar@@VERSION_2.0
+; DSO:     Value: 0x1010
+; DSO:     Size: 1
+; DSO:     Binding: Global
+; DSO:     Type: Function
+; DSO:     Other: 0
+; DSO:     Section: .text
+; DSO:   }
+; DSO: ]
diff --git a/test/ELF/lto/visibility.ll b/test/ELF/lto/visibility.ll
new file mode 100644 (file)
index 0000000..718cc5b
--- /dev/null
@@ -0,0 +1,35 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: g
+; CHECK-NEXT: Value: 0x1000
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other [ (0x2)
+; CHECK-NEXT:   STV_HIDDEN
+; CHECK-NEXT: ]
+; CHECK-NEXT: Section: .text
+
+; CHECK:      Name: a
+; CHECK-NEXT: Value: 0x3000
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other [ (0x2)
+; CHECK-NEXT:   STV_HIDDEN
+; CHECK-NEXT: ]
+; CHECK-NEXT: Section: .data
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare hidden void @g()
+define void @f() {
+  call void @g()
+  ret void
+}
+@a = weak hidden global i32 42
diff --git a/test/ELF/lto/weak.ll b/test/ELF/lto/weak.ll
new file mode 100644 (file)
index 0000000..381ef7a
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define weak void @f() {
+  ret void
+}
+
+; CHECK:      Name: f
+; CHECK-NEXT: Value: 0x1000
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Weak
diff --git a/test/ELF/many-sections.s b/test/ELF/many-sections.s
new file mode 100644 (file)
index 0000000..77e76c2
--- /dev/null
@@ -0,0 +1,116 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
+// RUN: llvm-readobj -t %t | FileCheck  %s
+
+// Verify that the symbol _start is in a section with an index >= SHN_LORESERVE.
+// CHECK:      Name: _start
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: dm (0xFF00)
+
+
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s
+
+// Test that _start is in the correct section.
+// LINKED:      Name: _start
+// LINKED-NEXT: Value: 0x0
+// LINKED-NEXT: Size: 0
+// LINKED-NEXT: Binding: Global
+// LINKED-NEXT: Type: None
+// LINKED-NEXT: Other: 0
+// LINKED-NEXT: Section: dm
+
+.macro gen_sections4 x
+        .section a\x
+        .section b\x
+        .section c\x
+        .section d\x
+.endm
+
+.macro gen_sections8 x
+        gen_sections4 a\x
+        gen_sections4 b\x
+.endm
+
+.macro gen_sections16 x
+        gen_sections8 a\x
+        gen_sections8 b\x
+.endm
+
+.macro gen_sections32 x
+        gen_sections16 a\x
+        gen_sections16 b\x
+.endm
+
+.macro gen_sections64 x
+        gen_sections32 a\x
+        gen_sections32 b\x
+.endm
+
+.macro gen_sections128 x
+        gen_sections64 a\x
+        gen_sections64 b\x
+.endm
+
+.macro gen_sections256 x
+        gen_sections128 a\x
+        gen_sections128 b\x
+.endm
+
+.macro gen_sections512 x
+        gen_sections256 a\x
+        gen_sections256 b\x
+.endm
+
+.macro gen_sections1024 x
+        gen_sections512 a\x
+        gen_sections512 b\x
+.endm
+
+.macro gen_sections2048 x
+        gen_sections1024 a\x
+        gen_sections1024 b\x
+.endm
+
+.macro gen_sections4096 x
+        gen_sections2048 a\x
+        gen_sections2048 b\x
+.endm
+
+.macro gen_sections8192 x
+        gen_sections4096 a\x
+        gen_sections4096 b\x
+.endm
+
+.macro gen_sections16384 x
+        gen_sections8192 a\x
+        gen_sections8192 b\x
+.endm
+
+.macro gen_sections32768 x
+        gen_sections16384 a\x
+        gen_sections16384 b\x
+.endm
+
+        .bss
+        .section bar
+
+gen_sections32768 a
+gen_sections16384 b
+gen_sections8192 c
+gen_sections4096 d
+gen_sections2048 e
+gen_sections1024 f
+gen_sections512 g
+gen_sections128 h
+gen_sections64 i
+gen_sections32 j
+gen_sections16 k
+gen_sections8 l
+gen_sections4 m
+
+.global _start
+_start:
diff --git a/test/ELF/merge-invalid-size.s b/test/ELF/merge-invalid-size.s
new file mode 100644 (file)
index 0000000..2a99e14
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: SHF_MERGE section size must be a multiple of sh_entsize
+
+        .section       .foo,"aM",@progbits,4
+        .short 42
diff --git a/test/ELF/merge-shared-str.s b/test/ELF/merge-shared-str.s
new file mode 100644 (file)
index 0000000..2ab03a4
--- /dev/null
@@ -0,0 +1,28 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared -O3
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+
+        .section        foo,"aMS",@progbits,1
+        .asciz "bar"
+        .asciz "ar"
+
+        .data
+        .quad foo + 4
+
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x1C9
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/merge-shared.s b/test/ELF/merge-shared.s
new file mode 100644 (file)
index 0000000..4c1d7c0
--- /dev/null
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+       .section        foo,"aM",@progbits,4
+        .long 42
+        .long 42
+
+        .data
+        .quad foo + 6
+
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x1CA
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/merge-string-align.s b/test/ELF/merge-string-align.s
new file mode 100644 (file)
index 0000000..0cb1afc
--- /dev/null
@@ -0,0 +1,56 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        .section        .rodata.foo,"aMS",@progbits,1
+        .align  16
+        .asciz "foo"
+
+        .section        .rodata.foo2,"aMS",@progbits,1
+        .align  16
+        .asciz "foo"
+
+        .section        .rodata.bar,"aMS",@progbits,1
+        .align  16
+        .asciz "bar"
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 20
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:  666F6F00 00000000 00000000 00000000  |foo.............|
+// CHECK-NEXT:   0010:  62617200                             |bar.|
+// CHECK-NEXT: )
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+        .asciz "foo"
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:  666F6F00 |foo.|
+// CHECK-NEXT: )
diff --git a/test/ELF/merge-string-error.s b/test/ELF/merge-string-error.s
new file mode 100644 (file)
index 0000000..c5088ac
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+        .section       .rodata.str1.1,"aMS",@progbits,1
+       .asciz  "abc"
+
+        .data
+        .long .rodata.str1.1 + 4
+
+// CHECK: entry is past the end of the section
diff --git a/test/ELF/merge-string-no-null.s b/test/ELF/merge-string-no-null.s
new file mode 100644 (file)
index 0000000..fd3f507
--- /dev/null
@@ -0,0 +1,8 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+       .ascii  "abc"
+
+// CHECK: string is not null terminated
diff --git a/test/ELF/merge-string.s b/test/ELF/merge-string.s
new file mode 100644 (file)
index 0000000..2ad8afa
--- /dev/null
@@ -0,0 +1,105 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -O2 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
+// RUN: ld.lld -O1 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOTAIL %s
+// RUN: ld.lld -O0 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOMERGE %s
+
+        .section       .rodata.str1.1,"aMS",@progbits,1
+       .asciz  "abc"
+foo:
+       .ascii  "a"
+bar:
+        .asciz  "bc"
+        .asciz  "bc"
+
+        .section        .rodata.str2.2,"aMS",@progbits,2
+        .align  2
+zed:
+        .short  20
+        .short  0
+
+// CHECK:      Name:    .rodata
+// CHECK-NEXT: Type:    SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:         0x1C8
+// CHECK-NEXT: Offset:  0x1C8
+// CHECK-NEXT: Size:    4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 1
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 61626300                             |abc.|
+// CHECK-NEXT: )
+
+// NOTAIL:      Name:    .rodata
+// NOTAIL-NEXT: Type:    SHT_PROGBITS
+// NOTAIL-NEXT: Flags [
+// NOTAIL-NEXT:   SHF_ALLOC
+// NOTAIL-NEXT:   SHF_MERGE
+// NOTAIL-NEXT:   SHF_STRINGS
+// NOTAIL-NEXT: ]
+// NOTAIL-NEXT: Address:         0x1C8
+// NOTAIL-NEXT: Offset:  0x1C8
+// NOTAIL-NEXT: Size:    7
+// NOTAIL-NEXT: Link: 0
+// NOTAIL-NEXT: Info: 0
+// NOTAIL-NEXT: AddressAlignment: 1
+// NOTAIL-NEXT: EntrySize: 1
+// NOTAIL-NEXT: SectionData (
+// NOTAIL-NEXT:   0000: 61626300 626300                     |abc.bc.|
+// NOTAIL-NEXT: )
+
+// NOMERGE:      Name:    .rodata
+// NOMERGE-NEXT: Type:    SHT_PROGBITS
+// NOMERGE-NEXT: Flags [
+// NOMERGE-NEXT:   SHF_ALLOC
+// NOMERGE-NEXT:   SHF_MERGE
+// NOMERGE-NEXT:   SHF_STRINGS
+// NOMERGE-NEXT: ]
+// NOMERGE-NEXT: Address:         0x1C8
+// NOMERGE-NEXT: Offset:  0x1C8
+// NOMERGE-NEXT: Size:    16
+// NOMERGE-NEXT: Link: 0
+// NOMERGE-NEXT: Info: 0
+// NOMERGE-NEXT: AddressAlignment: 2
+// NOMERGE-NEXT: EntrySize: 0
+// NOMERGE-NEXT: SectionData (
+// NOMERGE-NEXT:   0000: 61626300 61626300 62630000 14000000  |abc.abc.bc......|
+// NOMERGE-NEXT: )
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1CC
+// CHECK-NEXT: Offset: 0x1CC
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 2
+// CHECK-NEXT: EntrySize: 2
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 14000000                             |....|
+// CHECK-NEXT: )
+
+
+// CHECK:      Name:    bar
+// CHECK-NEXT: Value:   0x1C9
+
+// CHECK:      Name:    foo
+// CHECK-NEXT: Value:   0x1C8
+
+// CHECK:      Name: zed
+// CHECK-NEXT: Value: 0x1CC
+// CHECK-NEXT: Size: 0
diff --git a/test/ELF/merge-sym.s b/test/ELF/merge-sym.s
new file mode 100644 (file)
index 0000000..4a4e982
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -t -s %t.so | FileCheck %s
+
+        .section        .rodata.cst4,"aM",@progbits,4
+        .short 0
+foo:
+        .short 42
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x1CA
diff --git a/test/ELF/merge.s b/test/ELF/merge.s
new file mode 100644 (file)
index 0000000..5039ec2
--- /dev/null
@@ -0,0 +1,111 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/merge.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t
+// RUN: llvm-readobj -s -section-data -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .global foo
+        .hidden foo
+        .long   0x10
+foo:
+        .long   0x42
+bar:
+        .long   0x42
+zed:
+        .long   0x42
+
+// CHECK:      Name: .mysec
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_MERGE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x10120
+// CHECK-NEXT:    Offset: 0x120
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 0
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize: 4
+// CHECK-NEXT:    SectionData (
+// CHECK-NEXT:      0000: 10000000 42000000
+// CHECK-NEXT:    )
+
+
+// Address of the constant 0x10 = 0x10120 = 65824
+// Address of the constant 0x42 = 0x10124 = 65828
+
+// CHECK:      Symbols [
+
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x10124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Loca
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x10124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x10124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [ (0x2)
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .mysec
+
+ // CHECK: ]
+
+        .text
+        .globl  _start
+_start:
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+
+        movl .mysec, %eax
+// addr(0x10) = 65824
+// DISASM-NEXT:   movl    65824, %eax
+
+        movl .mysec+7, %eax
+// addr(0x42) + 3 = 65828 + 3 = 65831
+// DISASM-NEXT:   movl    65831, %eax
+
+        movl .mysec+8, %eax
+// addr(0x42) = 65828
+// DISASM-NEXT:   movl    65828, %eax
+
+        movl bar+7, %eax
+// addr(0x42) + 7 = 65828 + 7 = 65835
+// DISASM-NEXT:   movl    65835, %eax
+
+        movl bar+8, %eax
+// addr(0x42) + 8 = 65828 + 8 = 65836
+// DISASM-NEXT:   movl    65836, %eax
+
+        movl foo, %eax
+// addr(0x42) = 65828
+// DISASM-NEXT:   movl    65828, %eax
+
+        movl foo+7, %eax
+// addr(0x42) + 7 =  = 65828 + 7 = 65835
+// DISASM-NEXT:   movl    65835, %eax
+
+        movl foo+8, %eax
+// addr(0x42) + 8 =  = 65828 + 8 = 65836
+// DISASM-NEXT:   movl    65836, %eax
+
+//  From the other file:  movl .mysec, %eax
+// addr(0x42) = 65828
+// DISASM-NEXT:   movl    65828, %eax
diff --git a/test/ELF/mips-26.s b/test/ELF/mips-26.s
new file mode 100644 (file)
index 0000000..b463c1a
--- /dev/null
@@ -0,0 +1,95 @@
+# Check R_MIPS_26 relocation handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+# RUN: llvm-readobj -dynamic-table -s -r -mips-plt-got %t.exe \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: bar:
+# CHECK-NEXT:   20000:       0c 00 80 06     jal     131096 <loc>
+# CHECK-NEXT:   20004:       00 00 00 00     nop
+#
+# CHECK:      __start:
+# CHECK-NEXT:   20008:       0c 00 80 00     jal     131072 <bar>
+# CHECK-NEXT:   2000c:       00 00 00 00     nop
+# CHECK-NEXT:   20010:       0c 00 80 10     jal     131136
+#                                                    ^-- 0x20040 gotplt[foo0]
+# CHECK-NEXT:   20014:       00 00 00 00     nop
+#
+# CHECK:      loc:
+# CHECK-NEXT:   20018:       00 00 00 00     nop
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT:   20020:       3c 1c 00 04     lui     $gp, 4
+# CHECK-NEXT:   20024:       8f 99 00 04     lw      $25, 4($gp)
+# CHECK-NEXT:   20028:       27 9c 00 04     addiu   $gp, $gp, 4
+# CHECK-NEXT:   2002c:       03 1c c0 23     subu    $24, $24, $gp
+# CHECK-NEXT:   20030:       03 e0 78 25     move    $15, $ra
+# CHECK-NEXT:   20034:       00 18 c0 82     srl     $24, $24, 2
+# CHECK-NEXT:   20038:       03 20 f8 09     jalr    $25
+# CHECK-NEXT:   2003c:       27 18 ff fe     addiu   $24, $24, -2
+# CHECK-NEXT:   20040:       3c 0f 00 04     lui     $15, 4
+# CHECK-NEXT:   20044:       8d f9 00 0c     lw      $25, 12($15)
+# CHECK-NEXT:   20048:       03 20 00 08     jr      $25
+# CHECK-NEXT:   2004c:       25 f8 00 0c     addiu   $24, $15, 12
+
+# REL:      Name: .plt
+# REL-NEXT: Type: SHT_PROGBITS
+# REL-NEXT: Flags [ (0x6)
+# REL-NEXT:   SHF_ALLOC
+# REL-NEXT:   SHF_EXECINSTR
+# REL-NEXT: ]
+# REL-NEXT: Address: 0x[[PLTADDR:[0-9A-F]+]]
+
+# REL:      Name: .got.plt
+# REL-NEXT: Type: SHT_PROGBITS
+# REL-NEXT: Flags [ (0x3)
+# REL-NEXT:   SHF_ALLOC
+# REL-NEXT:   SHF_WRITE
+# REL-NEXT: ]
+# REL-NEXT: Address: 0x[[GOTPLTADDR:[0-9A-F]+]]
+
+# REL: Relocations [
+# REL-NEXT:   Section (7) .rel.plt {
+# REL-NEXT:     0x[[PLTSLOT:[0-9A-F]+]] R_MIPS_JUMP_SLOT foo0 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+# REL: 0x70000032  MIPS_PLTGOT  0x[[GOTPLTADDR]]
+
+# REL:      Primary GOT {
+# REL:        Local entries [
+# REL-NEXT:   ]
+# REL-NEXT:   Global entries [
+# REL-NEXT:   ]
+# REL:      PLT GOT {
+# REL:        Entries [
+# REL-NEXT:     Entry {
+# REL-NEXT:       Address: 0x[[PLTSLOT]]
+# REL-NEXT:       Initial: 0x[[PLTADDR]]
+# REL-NEXT:       Value: 0x0
+# REL-NEXT:       Type: Function
+# REL-NEXT:       Section: Undefined
+# REL-NEXT:       Name: foo0
+# REL-NEXT:     }
+# REL-NEXT:   ]
+
+  .text
+  .globl bar
+bar:
+  jal loc         # R_MIPS_26 against .text + offset
+
+  .globl __start
+__start:
+  jal bar         # R_MIPS_26 against global 'bar' from object file
+  jal foo0        # R_MIPS_26 against 'foo0' from DSO
+
+loc:
+  nop
diff --git a/test/ELF/mips-32.s b/test/ELF/mips-32.s
new file mode 100644 (file)
index 0000000..7875c48
--- /dev/null
@@ -0,0 +1,78 @@
+# Check R_MIPS_32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-objdump -t -s %t-be.so \
+# RUN:   | FileCheck -check-prefix=SYM -check-prefix=BE %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-be.so \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-objdump -t -s %t-el.so \
+# RUN:   | FileCheck -check-prefix=SYM -check-prefix=EL %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-el.so \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+  .globl  __start
+__start:
+  nop
+
+  .data
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .word 0
+
+  .globl v2
+  .type  v2,@object
+  .size  v2,8
+v2:
+  .word v2+4 # R_MIPS_32 target v2 addend 4
+  .word v1   # R_MIPS_32 target v1 addend 0
+
+# BE: Contents of section .data:
+# BE-NEXT: 30000 00000000 00000004 00030000
+#                         ^-- v2+4 ^-- v1
+
+# EL: Contents of section .data:
+# EL-NEXT: 30000 00000000 04000000 00000300
+#                         ^-- v2+4 ^-- v1
+
+# SYM: SYMBOL TABLE:
+# SYM: 00030000 l       .data           00000004 v1
+# SYM: 00030004 g       .data           00000008 v2
+
+# REL:      Relocations [
+# REL-NEXT:   Section (7) .rel.dyn {
+# REL-NEXT:     0x30008 R_MIPS_REL32 - 0x0
+# REL-NEXT:     0x30004 R_MIPS_REL32 v2 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+# REL: DynamicSection [
+# REL:   Tag        Type                 Name/Value
+# REL:   0x00000012 RELSZ                16 (bytes)
+# REL:   0x00000013 RELENT               8 (bytes)
+
+# REL:      Primary GOT {
+# REL-NEXT:   Canonical gp value:
+# REL-NEXT:   Reserved entries [
+# REL:        ]
+# REL-NEXT:   Local entries [
+# REL-NEXT:   ]
+# REL-NEXT:   Global entries [
+# REL-NEXT:     Entry {
+# REL-NEXT:       Address:
+# REL-NEXT:       Access:
+# REL-NEXT:       Initial: 0x30004
+# REL-NEXT:       Value: 0x30004
+# REL-NEXT:       Type: Object
+# REL-NEXT:       Section: .data
+# REL-NEXT:       Name: v2
+# REL-NEXT:     }
+# REL-NEXT:   ]
+# REL-NEXT:   Number of TLS and multi-GOT entries: 0
+# REL-NEXT: }
diff --git a/test/ELF/mips-64-disp.s b/test/ELF/mips-64-disp.s
new file mode 100644 (file)
index 0000000..1c66ba4
--- /dev/null
@@ -0,0 +1,89 @@
+# Check R_MIPS_GOT_DISP relocations against various kind of symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-pic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.exe.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+# CHECK-NEXT:    20000:   24 42 80 40   addiu   $2, $2, -32704
+# CHECK-NEXT:    20004:   24 42 80 20   addiu   $2, $2, -32736
+# CHECK-NEXT:    20008:   24 42 80 28   addiu   $2, $2, -32728
+# CHECK-NEXT:    2000c:   24 42 80 30   addiu   $2, $2, -32720
+# CHECK-NEXT:    20010:   24 42 80 38   addiu   $2, $2, -32712
+
+# CHECK: 0000000000020014     .text   00000000 foo
+# CHECK: 0000000000037ff0     .got    00000000 .hidden _gp
+# CHECK: 0000000000020000     .text   00000000 __start
+# CHECK: 0000000000000000 g F *UND*   00000000 foo1a
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+# GOT-NEXT: Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x37FF0
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30000
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30008
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x8000000000000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30010
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x20014
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30018
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x20004
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30020
+# GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20008
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30028
+# GOT-NEXT:       Access: -32712
+# GOT-NEXT:       Initial: 0x2000C
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30030
+# GOT-NEXT:       Access: -32704
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: Function
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo1a
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global  __start
+__start:
+  addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+4)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+8)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+12)         # R_MIPS_GOT_DISP
+
+foo:
+  nop
diff --git a/test/ELF/mips-64-got.s b/test/ELF/mips-64-got.s
new file mode 100644 (file)
index 0000000..52ce6fb
--- /dev/null
@@ -0,0 +1,87 @@
+# Check MIPS N64 ABI GOT relocations
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-pic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.exe.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+
+# CHECK-NEXT:    20000:   df 82 80 20   ld      $2, -32736($gp)
+# CHECK-NEXT:    20004:   64 42 00 18   daddiu  $2,  $2, 24
+# CHECK-NEXT:    20008:   24 42 80 38   addiu   $2,  $2, -32712
+# CHECK-NEXT:    2000c:   24 42 80 28   addiu   $2,  $2, -32728
+# CHECK-NEXT:    20010:   24 42 80 30   addiu   $2,  $2, -32720
+
+# CHECK: 0000000000020018   .text   00000000 foo
+# CHECK: 0000000000037ff0   .got    00000000 .hidden _gp
+# CHECK: 0000000000020000   .text   00000000 __start
+# CHECK: 0000000000020014   .text   00000000 bar
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+# GOT-NEXT: Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x37FF0
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30000
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30008
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x8000000000000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30010
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x20000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30018
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x20014
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30020
+# GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20018
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30028
+# GOT-NEXT:       Access: -32712
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: Function
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo1a
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global  __start, bar
+__start:
+  ld      $v0,%got_page(foo)($gp)             # R_MIPS_GOT_PAGE
+  daddiu  $v0,$v0,%got_ofst(foo)              # R_MIPS_GOT_OFST
+  addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(bar)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
+
+bar:
+  nop
+foo:
+  nop
diff --git a/test/ELF/mips-64-gprel-so.s b/test/ELF/mips-64-gprel-so.s
new file mode 100644 (file)
index 0000000..437238e
--- /dev/null
@@ -0,0 +1,23 @@
+# Check setup of GP relative offsets in a function's prologue.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: foo:
+# CHECK-NEXT:    10000:    3c 1c 00 01    lui     $gp, 1
+# CHECK-NEXT:    10004:    03 99 e0 2d    daddu   $gp, $gp, $25
+# CHECK-NEXT:    10008:    67 9c 7f f0    daddiu  $gp, $gp, 32752
+
+# CHECK: 0000000000027ff0   .got    00000000 .hidden _gp
+# CHECK: 0000000000010000   .text   00000000 foo
+
+  .text
+  .global foo
+foo:
+  lui     $gp,%hi(%neg(%gp_rel(foo)))
+  daddu   $gp,$gp,$t9
+  daddiu  $gp,$gp,%lo(%neg(%gp_rel(foo)))
diff --git a/test/ELF/mips-64-rels.s b/test/ELF/mips-64-rels.s
new file mode 100644 (file)
index 0000000..7126afc
--- /dev/null
@@ -0,0 +1,46 @@
+# Check handling multiple MIPS N64 ABI relocations packed
+# into the single relocation record.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+# CHECK-NEXT:    20000:   3c 1c 00 01   lui     $gp, 1
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %hi(0x17ff0)
+# CHECK:      loc:
+# CHECK-NEXT:    20004:   67 9c 7f f0   daddiu  $gp, $gp, 32752
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %lo(0x17ff0)
+
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT:  10190 ffffffff fffe8014
+#                    ^-- 0x20004 - 0x37ff0 = 0xfffffffffffe8014
+
+# CHECK: 0000000000020004   .text   00000000 loc
+# CHECK: 0000000000037ff0   .got    00000000 .hidden _gp
+# CHECK: 0000000000020000   .text   00000000 __start
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+  .text
+  .global  __start
+__start:
+  lui     $gp,%hi(%neg(%gp_rel(__start)))     # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_HI16
+loc:
+  daddiu  $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_LO16
+
+  .section  .rodata,"a",@progbits
+  .gpdword(loc)                               # R_MIPS_GPREL32
+                                              # R_MIPS_64
diff --git a/test/ELF/mips-64.s b/test/ELF/mips-64.s
new file mode 100644 (file)
index 0000000..689669e
--- /dev/null
@@ -0,0 +1,63 @@
+# Check R_MIPS_64 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-objdump -t %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .global  __start
+__start:
+  nop
+
+  .data
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .quad 0
+
+  .globl v2
+  .type  v2,@object
+  .size  v2,8
+v2:
+  .quad v2+8 # R_MIPS_64 target v2 addend 8
+  .quad v1   # R_MIPS_64 target v1 addend 0
+
+
+# SYM: SYMBOL TABLE:
+# SYM: 00030000 l       .data           00000004 v1
+# SYM: 00030008 g       .data           00000008 v2
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rela.dyn {
+# CHECK-NEXT:     0x30010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x30000
+#                                                             ^-- v1
+# CHECK-NEXT:     0x30008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x8
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSection [
+# CHECK:   Tag        Type     Name/Value
+# CHECK:   0x0000000000000008 RELASZ    48 (bytes)
+# CHECK:   0x0000000000000009 RELAENT   24 (bytes)
+
+# CHECK:      Primary GOT {
+# CHECK-NEXT:   Canonical gp value:
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access:
+# CHECK-NEXT:       Initial: 0x30008
+# CHECK-NEXT:       Value: 0x30008
+# CHECK-NEXT:       Type: Object
+# CHECK-NEXT:       Section: .data
+# CHECK-NEXT:       Name: v2
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-align-err.s b/test/ELF/mips-align-err.s
new file mode 100644 (file)
index 0000000..28b192a
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o \
+# RUN:         -mcpu=mips32r6
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %S/Inputs/mips-align-err.s -o %t2.o
+# RUN: not ld.lld %t.o %t2.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: improper alignment for relocation R_MIPS_PC16
+
+        .globl  __start
+__start:
+.zero 1
+        beqc      $5, $6, _foo            # R_MIPS_PC16
diff --git a/test/ELF/mips-call16.s b/test/ELF/mips-call16.s
new file mode 100644 (file)
index 0000000..4a5d0bf
--- /dev/null
@@ -0,0 +1,40 @@
+# Check R_MIPS_CALL16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+# RUN: llvm-readobj -mips-plt-got -symbols %t.exe \
+# RUN:   | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%call16(g1)($gp)
+
+  .globl g1
+  .type  g1,@function
+g1:
+  nop
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:      10000:   8f 88 80 18   lw   $8, -32744
+
+# GOT:      Name: g1
+# GOT-NEXT: Value: 0x[[ADDR:[0-9A-F]+]]
+
+# GOT:      Local entries [
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT:   Entry {
+# GOT-NEXT:     Address:
+# GOT-NEXT:     Access: -32744
+# GOT-NEXT:     Initial: 0x[[ADDR]]
+# GOT-NEXT:     Value: 0x[[ADDR]]
+# GOT-NEXT:     Type: Function
+# GOT-NEXT:     Section: .text
+# GOT-NEXT:     Name: g1
+# GOT-NEXT:   }
+# GOT-NEXT: ]
diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s
new file mode 100644 (file)
index 0000000..3cb5c63
--- /dev/null
@@ -0,0 +1,98 @@
+# Check MIPS specific .dynamic section entries.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %p/Inputs/mips-dynamic.s -o %td.o
+# RUN: ld.lld -shared %td.o -o %td.so
+
+# RUN: ld.lld %t.o %td.so -o %t.exe
+# RUN: llvm-readobj -sections -dynamic-table %t.exe \
+# RUN:   | FileCheck -check-prefix=EXE %s
+
+# RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe
+# RUN: llvm-readobj -sections -dynamic-table %t.exe \
+# RUN:   | FileCheck -check-prefix=IMAGE_BASE %s
+
+# RUN: ld.lld -shared %t.o %td.so -o %t.so
+# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \
+# RUN:   | FileCheck -check-prefix=DSO %s
+
+# REQUIRES: mips
+
+# EXE:      Sections [
+# EXE:          Name: .dynamic
+# EXE-NEXT:     Type: SHT_DYNAMIC
+# EXE-NEXT:     Flags [
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:     ]
+# EXE:          Name: .got
+# EXE-NEXT:     Type: SHT_PROGBITS
+# EXE-NEXT:     Flags [ (0x10000003)
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:       SHF_MIPS_GPREL
+# EXE-NEXT:       SHF_WRITE
+# EXE-NEXT:     ]
+# EXE-NEXT:     Address: [[GOTADDR:0x[0-9a-f]+]]
+# EXE-NEXT:     Offset:
+# EXE-NEXT:     Size: 8
+# EXE:          Name: .rld_map
+# EXE-NEXT:     Type: SHT_PROGBITS
+# EXE-NEXT:     Flags [
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:       SHF_WRITE
+# EXE-NEXT:     ]
+# EXE-NEXT:     Address: [[RLDMAPADDR:0x[0-9a-f]+]]
+# EXE-NEXT:     Offset:
+# EXE-NEXT:     Size: 4
+# EXE:      ]
+# EXE:      DynamicSection [
+# EXE-NEXT:   Tag        Type                 Name/Value
+# EXE-DAG:    0x00000003 PLTGOT               [[GOTADDR]]
+# EXE-DAG:    0x70000001 MIPS_RLD_VERSION     1
+# EXE-DAG:    0x70000005 MIPS_FLAGS           NOTPOT
+# EXE-DAG:    0x70000006 MIPS_BASE_ADDRESS    0x10000
+# EXE-DAG:    0x7000000A MIPS_LOCAL_GOTNO     2
+# EXE-DAG:    0x70000011 MIPS_SYMTABNO        2
+# EXE-DAG:    0x70000013 MIPS_GOTSYM          0x2
+# EXE-DAG:    0x70000016 MIPS_RLD_MAP         [[RLDMAPADDR]]
+# EXE:      ]
+
+# IMAGE_BASE: 0x70000006 MIPS_BASE_ADDRESS    0x123000
+
+# DSO:      Sections [
+# DSO:          Name: .dynamic
+# DSO-NEXT:     Type: SHT_DYNAMIC
+# DSO-NEXT:     Flags [
+# DSO-NEXT:       SHF_ALLOC
+# DSO-NEXT:     ]
+# DSO:          Name: .got
+# DSO-NEXT:     Type: SHT_PROGBITS
+# DSO-NEXT:     Flags [ (0x10000003)
+# DSO-NEXT:       SHF_ALLOC
+# DSO-NEXT:       SHF_MIPS_GPREL
+# DSO-NEXT:       SHF_WRITE
+# DSO-NEXT:     ]
+# DSO-NEXT:     Address: [[GOTADDR:0x[0-9a-f]+]]
+# DSO-NEXT:     Offset:
+# DSO-NEXT:     Size: 8
+# DSO:      ]
+# DSO:      DynamicSymbols [
+# DSO:          Name: @
+# DSO:          Name: __start@
+# DSO:          Name: _foo@
+# DSO:      ]
+# DSO:      DynamicSection [
+# DSO-NEXT:   Tag        Type                 Name/Value
+# DSO-DAG:    0x00000003 PLTGOT               [[GOTADDR]]
+# DSO-DAG:    0x70000001 MIPS_RLD_VERSION     1
+# DSO-DAG:    0x70000005 MIPS_FLAGS           NOTPOT
+# DSO-DAG:    0x70000006 MIPS_BASE_ADDRESS    0x0
+# DSO-DAG:    0x7000000A MIPS_LOCAL_GOTNO     2
+# DSO-DAG:    0x70000011 MIPS_SYMTABNO        3
+# DSO-DAG:    0x70000013 MIPS_GOTSYM          0x3
+# DSO:      ]
+
+  .text
+  .globl  __start,_foo
+  .type _foo,@function
+__start:
+  nop
diff --git a/test/ELF/mips-dynsym-sort.s b/test/ELF/mips-dynsym-sort.s
new file mode 100644 (file)
index 0000000..7d4559c
--- /dev/null
@@ -0,0 +1,43 @@
+# Check the order of dynamic symbols for the MIPS target.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-readobj -symbols -dyn-symbols %t-be.so | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-readobj -symbols -dyn-symbols %t-el.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .data
+  .globl v1,v2,v3
+v1:
+  .space 4
+v2:
+  .space 4
+v3:
+  .space 4
+
+  .text
+  .globl  __start
+__start:
+  lui $2, %got(v3) # v3 will precede v1 in the GOT
+  lui $2, %got(v1)
+
+# Since all these symbols have global binding,
+# the Symbols section contains them in the original order.
+# CHECK: Symbols [
+# CHECK:     Name: v1
+# CHECK:     Name: v2
+# CHECK:     Name: v3
+# CHECK: ]
+
+# The symbols in the DynamicSymbols section are sorted in compliance with
+# the MIPS rules. v2 comes first as it is not in the GOT.
+# v1 and v3 are sorted according to their order in the GOT.
+# CHECK: DynamicSymbols [
+# CHECK:     Name: v2@
+# CHECK:     Name: v3@
+# CHECK:     Name: v1@
+# CHECK: ]
diff --git a/test/ELF/mips-elf-flags.s b/test/ELF/mips-elf-flags.s
new file mode 100644 (file)
index 0000000..7817e58
--- /dev/null
@@ -0,0 +1,27 @@
+# Check generation of MIPS specific ELF header flags.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -h %t.so | FileCheck -check-prefix=SO %s
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=EXE %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  nop
+
+# SO:      Flags [
+# SO-NEXT:   EF_MIPS_ABI_O32
+# SO-NEXT:   EF_MIPS_ARCH_32R2
+# SO-NEXT:   EF_MIPS_CPIC
+# SO-NEXT:   EF_MIPS_PIC
+# SO-NEXT: ]
+
+# EXE:      Flags [
+# EXE-NEXT:   EF_MIPS_ABI_O32
+# EXE-NEXT:   EF_MIPS_ARCH_32R2
+# EXE-NEXT:   EF_MIPS_CPIC
+# EXE-NEXT: ]
diff --git a/test/ELF/mips-gnu-hash.s b/test/ELF/mips-gnu-hash.s
new file mode 100644 (file)
index 0000000..288d540
--- /dev/null
@@ -0,0 +1,15 @@
+# Shouldn't allow the GNU hash style to be selected with the MIPS target.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: not ld.lld -shared -hash-style=gnu %t-be.o -o %t-be.so 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: not ld.lld -shared -hash-style=gnu %t-el.o -o %t-el.so 2>&1 | FileCheck %s
+
+# CHECK: the .gnu.hash section is not compatible with the MIPS target.
+
+# REQUIRES: mips
+
+  .globl  __start
+__start:
+  nop
diff --git a/test/ELF/mips-got-and-copy.s b/test/ELF/mips-got-and-copy.s
new file mode 100644 (file)
index 0000000..453b8c9
--- /dev/null
@@ -0,0 +1,57 @@
+# REQUIRES: mips
+
+# If there are two relocations such that the first one requires
+# dynamic COPY relocation, the second one requires GOT entry
+# creation, linker should create both - dynamic relocation
+# and GOT entry.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data1
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x37FF0
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30008
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x40010
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x3000C
+# CHECK-NEXT:       Access: -32740
+# CHECK-NEXT:       Initial: 0x40014
+# CHECK-NEXT:       Value: 0x40014
+# CHECK-NEXT:       Type: Object (0x1)
+# CHECK-NEXT:       Section: .bss (0xD)
+# CHECK-NEXT:       Name: data1@ (7)
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
+
+  .text
+  .global __start
+__start:
+  # Case A: 'got' relocation goes before 'copy' relocation
+  lui    $t0,%hi(data0)         # R_MIPS_HI16 - requires R_MISP_COPY relocation
+  addi   $t0,$t0,%lo(data0)
+  lw     $t0,%got(data0)($gp)   # R_MIPS_GOT16 - requires GOT entry
+
+  # Case B: 'copy' relocation goes before 'got' relocation
+  lw     $t0,%got(data1)($gp)   # R_MIPS_GOT16 - requires GOT entry
+  lui    $t0,%hi(data1)         # R_MIPS_HI16 - requires R_MISP_COPY relocation
+  addi   $t0,$t0,%lo(data1)
diff --git a/test/ELF/mips-got-extsym.s b/test/ELF/mips-got-extsym.s
new file mode 100644 (file)
index 0000000..1cf99ae
--- /dev/null
@@ -0,0 +1,59 @@
+# Check creation of GOT entries for global symbols in case of executable
+# file linking. Symbols defined in DSO should get entries in the global part
+# of the GOT. Symbols defined in the executable itself should get local GOT
+# entries and does not need a row in .dynsym table.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dt -t -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbols [
+# CHECK:        Symbol {
+# CHECK:          Name: _foo
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+
+# CHECK:        Symbol {
+# CHECK:          Name: bar
+# CHECK-NEXT:     Value: 0x20008
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+
+# CHECK:     DynamicSymbols [
+# CHECK-NOT:      Name: bar
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address: 0x30008
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x20008
+#                          ^-- bar
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Global entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address: 0x3000C
+# CHECK-NEXT:     Access: -32740
+# CHECK-NEXT:     Initial: 0x0
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:     Name: _foo@
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%got(bar)($gp)
+  lw      $t0,%got(_foo)($gp)
+
+.global bar
+bar:
+  .word 0
diff --git a/test/ELF/mips-got-redundant.s b/test/ELF/mips-got-redundant.s
new file mode 100644 (file)
index 0000000..07c3c24
--- /dev/null
@@ -0,0 +1,58 @@
+# Check number of redundant entries in the local part of MIPS GOT.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address: 0x20008
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x30000
+#                          ^-- loc1
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address: 0x2000C
+# CHECK-NEXT:     Access: -32740
+# CHECK-NEXT:     Initial: 0x40000
+#                          ^-- loc2, loc3, loc4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address: 0x20010
+# CHECK-NEXT:     Access: -32736
+# CHECK-NEXT:     Initial: 0x40008
+#                          ^-- glb1
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .globl  foo
+foo:
+  lw      $t0, %got(loc1)($gp)
+  addi    $t0, $t0, %lo(loc1)
+  lw      $t0, %got(loc2)($gp)
+  addi    $t0, $t0, %lo(loc2)
+  lw      $t0, %got(loc3)($gp)
+  addi    $t0, $t0, %lo(loc3)
+  lw      $t0, %got(loc4)($gp)
+  addi    $t0, $t0, %lo(loc4)
+  lw      $t0, %got(glb1)($gp)
+  lw      $t0, %got(glb1)($gp)
+
+  .section .data.1,"aw",%progbits
+loc1:
+  .space 0x10000
+loc2:
+  .word 0
+loc3:
+  .word 0
+  .global glb1
+  .hidden glb1
+glb1:
+  .word 0
+
+  .section .data.2,"aw",%progbits
+loc4:
+  .word 0
diff --git a/test/ELF/mips-got-relocs.s b/test/ELF/mips-got-relocs.s
new file mode 100644 (file)
index 0000000..c44cf90
--- /dev/null
@@ -0,0 +1,100 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld %t-be.o -o %t-be.exe
+# RUN: llvm-objdump -section-headers -t %t-be.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.exe | FileCheck -check-prefix=EXE_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=EXE_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld %t-el.o -o %t-el.exe
+# RUN: llvm-objdump -section-headers -t %t-el.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.exe | FileCheck -check-prefix=EXE_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=EXE_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-objdump -section-headers -t %t-be.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.so | FileCheck -check-prefix=DSO_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.so | FileCheck -check-prefix=DSO_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.so | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-objdump -section-headers -t %t-el.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.so | FileCheck -check-prefix=DSO_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.so | FileCheck -check-prefix=DSO_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.so | FileCheck -check-prefix=SHFLAGS %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui $2, %got(v1)
+
+  .data
+  .globl v1
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .word 0
+
+# EXE_SYM: Sections:
+# EXE_SYM: .got 0000000c 0000000000030000 DATA
+# EXE_SYM: SYMBOL TABLE:
+# EXE_SYM: 00037ff0         .got                00000000 .hidden _gp
+#          ^-- .got + GP offset (0x7ff0)
+# EXE_SYM: 00040000 g       .data               00000004 v1
+
+
+# EXE_GOT_BE: Contents of section .got:
+# EXE_GOT_BE:  30000 00000000 80000000 00040000
+#                    ^        ^        ^-- v1 (0x40000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# EXE_GOT_EL: Contents of section .got:
+# EXE_GOT_EL:  30000 00000000 00000080 00000400
+#                    ^        ^        ^-- v1 (0x40000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x3000c) - _gp (0x37ff4) = -0x7fe8 => 0x8018 = 32792
+# EXE_DIS_BE:  20000:  3c 02 80 18  lui $2, 32792
+# EXE_DIS_EL:  20000:  18 80 02 3c  lui $2, 32792
+
+# DSO_SYM: Sections:
+# DSO_SYM: .got 0000000c 0000000000020000 DATA
+# DSO_SYM: SYMBOL TABLE:
+# DSO_SYM: 00027ff0         .got                00000000 .hidden _gp
+#          ^-- .got + GP offset (0x7ff0)
+# DSO_SYM: 00030000 g       .data               00000004 v1
+
+# DSO_GOT_BE: Contents of section .got:
+# DSO_GOT_BE:  20000 00000000 80000000 00030000
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# DSO_GOT_EL: Contents of section .got:
+# DSO_GOT_EL:  20000 00000000 00000080 00000300
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x2000c) - _gp (0x27ff4) = -0x7fe8 => 0x8018 = 32792
+# DSO_DIS_BE:  10000:  3c 02 80 18  lui $2, 32792
+# DSO_DIS_EL:  10000:  18 80 02 3c  lui $2, 32792
+
+# NORELOC:      Relocations [
+# NORELOC-NEXT: ]
+
+# SHFLAGS:      Name: .got
+# SHFLAGS-NEXT: Type: SHT_PROGBITS
+# SHFLAGS-NEXT: Flags [ (0x10000003)
+#                        ^-- SHF_MIPS_GPREL | SHF_ALLOC | SHF_WRITE
diff --git a/test/ELF/mips-got-weak.s b/test/ELF/mips-got-weak.s
new file mode 100644 (file)
index 0000000..a779246
--- /dev/null
@@ -0,0 +1,172 @@
+# Check R_MIPS_GOT16 relocation against weak symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t1.so
+# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \
+# RUN:   | FileCheck -check-prefix=NOSYM %s
+# RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so
+# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \
+# RUN:   | FileCheck -check-prefix=SYM %s
+
+# REQUIRES: mips
+
+# NOSYM:      Relocations [
+# NOSYM-NEXT: ]
+
+# NOSYM:        Symbol {
+# NOSYM:          Name: foo
+# NOSYM-NEXT:     Value: 0x30000
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Weak
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: .data
+# NOSYM-NEXT:   }
+# NOSYM-NEXT:   Symbol {
+# NOSYM-NEXT:     Name: bar
+# NOSYM-NEXT:     Value: 0x0
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Weak
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: Undefined
+# NOSYM-NEXT:   }
+# NOSYM-NEXT:   Symbol {
+# NOSYM-NEXT:     Name: sym
+# NOSYM-NEXT:     Value: 0x30004
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Global
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: .data
+# NOSYM-NEXT:   }
+# NOSYM-NEXT: ]
+
+# NOSYM:      0x70000011 MIPS_SYMTABNO        4
+# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     2
+# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM          0x1
+
+# NOSYM:      Primary GOT {
+# NOSYM-NEXT:   Canonical gp value: 0x27FF0
+# NOSYM-NEXT:   Reserved entries [
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address: 0x20000
+# NOSYM-NEXT:       Access: -32752
+# NOSYM-NEXT:       Initial: 0x0
+# NOSYM-NEXT:       Purpose: Lazy resolver
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address: 0x20004
+# NOSYM-NEXT:       Access: -32748
+# NOSYM-NEXT:       Initial: 0x80000000
+# NOSYM-NEXT:       Purpose: Module pointer (GNU extension)
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Local entries [
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Global entries [
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address: 0x20008
+# NOSYM-NEXT:       Access: -32744
+# NOSYM-NEXT:       Initial: 0x30000
+# NOSYM-NEXT:       Value: 0x30000
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: .data
+# NOSYM-NEXT:       Name: foo
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address: 0x2000C
+# NOSYM-NEXT:       Access: -32740
+# NOSYM-NEXT:       Initial: 0x0
+# NOSYM-NEXT:       Value: 0x0
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: Undefined
+# NOSYM-NEXT:       Name: bar
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address: 0x20010
+# NOSYM-NEXT:       Access: -32736
+# NOSYM-NEXT:       Initial: 0x30004
+# NOSYM-NEXT:       Value: 0x30004
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: .data
+# NOSYM-NEXT:       Name: sym
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Number of TLS and multi-GOT entries: 0
+# NOSYM-NEXT: }
+
+# SYM:      Relocations [
+# SYM-NEXT: ]
+
+# SYM:        Symbol {
+# SYM:          Name: bar
+# SYM-NEXT:     Value: 0x0
+# SYM-NEXT:     Size: 0
+# SYM-NEXT:     Binding: Weak
+# SYM-NEXT:     Type: None
+# SYM-NEXT:     Other: 0
+# SYM-NEXT:     Section: Undefined
+# SYM-NEXT:   }
+# SYM-NEXT: ]
+
+# SYM:      0x70000011 MIPS_SYMTABNO        4
+# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     4
+# SYM-NEXT: 0x70000013 MIPS_GOTSYM          0x3
+
+# SYM:      Primary GOT {
+# SYM-NEXT:   Canonical gp value: 0x27FF0
+# SYM-NEXT:   Reserved entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address: 0x20000
+# SYM-NEXT:       Access: -32752
+# SYM-NEXT:       Initial: 0x0
+# SYM-NEXT:       Purpose: Lazy resolver
+# SYM-NEXT:     }
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address: 0x20004
+# SYM-NEXT:       Access: -32748
+# SYM-NEXT:       Initial: 0x80000000
+# SYM-NEXT:       Purpose: Module pointer (GNU extension)
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Local entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address: 0x20008
+# SYM-NEXT:       Access: -32744
+# SYM-NEXT:       Initial: 0x30000
+# SYM-NEXT:     }
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address: 0x2000C
+# SYM-NEXT:       Access: -32740
+# SYM-NEXT:       Initial: 0x30004
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Global entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address: 0x20010
+# SYM-NEXT:       Access: -32736
+# SYM-NEXT:       Initial: 0x0
+# SYM-NEXT:       Value: 0x0
+# SYM-NEXT:       Type: None
+# SYM-NEXT:       Section: Undefined
+# SYM-NEXT:       Name: bar
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Number of TLS and multi-GOT entries: 0
+# SYM-NEXT: }
+
+  .text
+  .global  sym
+  .weak    foo,bar
+func:
+  lw      $t0,%got(foo)($gp)
+  lw      $t0,%got(bar)($gp)
+  lw      $t0,%got(sym)($gp)
+
+  .data
+  .weak foo
+foo:
+  .word 0
+sym:
+  .word 0
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
new file mode 100644 (file)
index 0000000..ef80418
--- /dev/null
@@ -0,0 +1,120 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    10000:       8f 88 80 18     lw      $8, -32744($gp)
+# CHECK-NEXT:    10004:       21 08 00 2c     addi    $8, $8, 44
+# CHECK-NEXT:    10008:       8f 88 80 1c     lw      $8, -32740($gp)
+# CHECK-NEXT:    1000c:       21 08 90 00     addi    $8, $8, -28672
+# CHECK-NEXT:    10010:       8f 88 80 20     lw      $8, -32736($gp)
+# CHECK-NEXT:    10014:       21 08 90 04     addi    $8, $8, -28668
+# CHECK-NEXT:    10018:       8f 88 80 20     lw      $8, -32736($gp)
+# CHECK-NEXT:    1001c:       21 08 10 04     addi    $8, $8, 4100
+# CHECK-NEXT:    10020:       8f 88 80 28     lw      $8, -32728($gp)
+# CHECK-NEXT:    10024:       21 08 10 08     addi    $8, $8, 4104
+# CHECK-NEXT:    10028:       8f 88 80 2c     lw      $8, -32724($gp)
+#
+# CHECK: SYMBOL TABLE:
+# CHECK: 00051008         .data           00000000 .hidden bar
+# CHECK: 00000000         *UND*           00000000 foo
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x27FF0
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20000
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20004
+# GOT-NEXT:       Access: -32748
+# GOT-NEXT:       Initial: 0x80000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20008
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x10000
+#                          ^-- (0x1002c + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x2000C
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x40000
+#                          ^-- (0x39000 + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20010
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x50000
+#                          ^-- (0x39000 + 0x10004 + 0x8000) & ~0xffff
+#                          ^-- (0x39000 + 0x18004 + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20014
+# GOT-NEXT:       Access: -32732
+# GOT-NEXT:       Initial: 0x0
+#                          ^-- redundant unused entry
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20018
+# GOT-NEXT:       Access: -327
+# GOT-NEXT:       Initial: 0x51008
+#                          ^-- 'bar' address
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x2001C
+# GOT-NEXT:       Access: -32724
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo@
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%got($LC0)($gp)
+  addi    $t0,$t0,%lo($LC0)
+  lw      $t0,%got($LC1)($gp)
+  addi    $t0,$t0,%lo($LC1)
+  lw      $t0,%got($LC1+0x10004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x10004)
+  lw      $t0,%got($LC1+0x18004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x18004)
+  lw      $t0,%got(bar)($gp)
+  addi    $t0,$t0,%lo(bar)
+  lw      $t0,%got(foo)($gp)
+$LC0:
+  nop
+
+  .data
+  .space 0x9000
+$LC1:
+  .word 0
+  .space 0x18000
+  .word 0
+.global bar
+.hidden bar
+bar:
+  .word 0
diff --git a/test/ELF/mips-gp-disp.s b/test/ELF/mips-gp-disp.s
new file mode 100644 (file)
index 0000000..7a0fd64
--- /dev/null
@@ -0,0 +1,37 @@
+# Check that even if _gp_disp symbol is defined in the shared library
+# we use our own value.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o %S/Inputs/mips-gp-disp.so
+# RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=INT-SO %s
+# RUN: llvm-readobj -symbols %S/Inputs/mips-gp-disp.so \
+# RUN:   | FileCheck -check-prefix=EXT-SO %s
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# INT-SO:      Name: _gp_disp
+# INT-SO-NEXT: Value:
+# INT-SO-NEXT: Size:
+# INT-SO-NEXT: Binding: Local
+
+# EXT-SO:      Name: _gp_disp
+# EXT-SO-NEXT: Value: 0x20000
+
+# DIS:      Disassembly of section .text:
+# DIS-NEXT: __start:
+# DIS-NEXT:    10000:  3c 08 00 01  lui   $8, 1
+# DIS-NEXT:    10004:  21 08 7f f0  addi  $8, $8, 32752
+#                                                 ^-- 0x37ff0 & 0xffff
+# DIS: 00027ff0  .got  00000000 .hidden _gp
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+  lw     $v0,%call16(_foo)($gp)
diff --git a/test/ELF/mips-gp-local.s b/test/ELF/mips-gp-local.s
new file mode 100644 (file)
index 0000000..8bb3c23
--- /dev/null
@@ -0,0 +1,20 @@
+# Check handling of relocations against __gnu_local_gp symbol.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -o %t.exe %t.o
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:  3c 08 00 03  lui   $8, 3
+# CHECK-NEXT:    20004:  21 08 7f f0  addi  $8, $8, 32752
+
+# CHECK: 00037ff0  .got  00000000 .hidden _gp
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__gnu_local_gp)
+  addi   $t0,$t0,%lo(__gnu_local_gp)
diff --git a/test/ELF/mips-gprel32-relocs-gp0.test b/test/ELF/mips-gprel32-relocs-gp0.test
new file mode 100644 (file)
index 0000000..6cc837e
--- /dev/null
@@ -0,0 +1,31 @@
+# Check R_MIPS_GPREL32 relocation calculation if input file conatins
+# non-zero GP0 value in the .reginfo section.
+# FIXME: The only way to get an object file with non-zero GP0 value
+# is to link multiple object files with GOT relocations using '-r'
+# option. LLD does not calculate and generate GP0 correctly so we
+# use a binary input in this test. The input object file is a result
+# of linking two object files with R_MIPS_GPREL32 relocations.
+
+# RUN: ld.lld -shared -o %t.so %S/Inputs/mips-gprel32-gp0.o
+# RUN: llvm-objdump -s %S/Inputs/mips-gprel32-gp0.o \
+# RUN:   | FileCheck -check-prefix=OBJ %s
+# RUN: llvm-objdump -s -t %t.so | FileCheck %s
+
+# OBJ:      Contents of section .reginfo:
+# OBJ-NEXT:  0000 00000001 00000000 00000000 00000000
+# OBJ-NEXT:  0010 00000000 00007fef
+#                              ^-- GP0 value
+# OBJ:      Contents of section .rodata:
+# OBJ-NEXT:  0000 ffff8011 ffff8011
+#                 ^-- foo addend
+#                          ^-- bar addend
+
+# CHECK: Contents of section .rodata:
+# CHECK:  012c fffe8010 fffe8020
+#              ^ 0x10000 + 0xffff8011 + 0x7fef - 0x27ff0
+#                       ^ 0x10010 + 0xffff8011 + 0x7fef - 0x27ff0
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00010000         .text          00000000 foo
+# CHECK: 00010010         .text          00000000 bar
+# CHECK: 00027ff0         .got           00000000 .hidden _gp
diff --git a/test/ELF/mips-gprel32-relocs.s b/test/ELF/mips-gprel32-relocs.s
new file mode 100644 (file)
index 0000000..fa1c5cf
--- /dev/null
@@ -0,0 +1,31 @@
+# Check R_MIPS_GPREL32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%call16(__start)($gp)
+foo:
+  nop
+bar:
+  nop
+
+  .section .rodata, "a"
+v1:
+  .gpword foo
+  .gpword bar
+
+# CHECK: Contents of section .rodata:
+# CHECK:  0114 fffe8014 fffe8018
+#              ^ 0x10004 - 0x27ff0
+#                       ^ 0x10008 - 0x27ff0
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00010008         .text           00000000 bar
+# CHECK: 00010004         .text           00000000 foo
+# CHECK: 00027ff0         .got           00000000 .hidden _gp
diff --git a/test/ELF/mips-hilo-gp-disp.s b/test/ELF/mips-hilo-gp-disp.s
new file mode 100644 (file)
index 0000000..37cf90d
--- /dev/null
@@ -0,0 +1,55 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation against _gp_disp.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+  lw     $v0,%call16(_foo)($gp)
+bar:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+
+# EXE:      Disassembly of section .text:
+# EXE-NEXT: __start:
+# EXE-NEXT:  20000:   3c 08 00 01   lui    $8, 1
+#                                              ^-- %hi(0x37ff0-0x20000)
+# EXE-NEXT:  20004:   21 08 7f f0   addi   $8, $8, 32752
+#                                                  ^-- %lo(0x37ff0-0x20004+4)
+# EXE:      bar:
+# EXE-NEXT:  2000c:   3c 08 00 01   lui    $8, 1
+#                                              ^-- %hi(0x37ff0-0x2000c)
+# EXE-NEXT:  20010:   21 08 7f e4   addi   $8, $8, 32740
+#                                                  ^-- %lo(0x37ff0-0x20010+4)
+
+# EXE: SYMBOL TABLE:
+# EXE: 0002000c     .text   00000000 bar
+# EXE: 00037ff0     .got    00000000 .hidden _gp
+# EXE: 00020000     .text   00000000 __start
+
+# SO:      Disassembly of section .text:
+# SO-NEXT: __start:
+# SO-NEXT:  10000:   3c 08 00 01   lui    $8, 1
+#                                             ^-- %hi(0x27ff0-0x10000)
+# SO-NEXT:  10004:   21 08 7f f0   addi   $8, $8, 32752
+#                                                 ^-- %lo(0x27ff0-0x10004+4)
+# SO:       bar:
+# SO-NEXT:   1000c:   3c 08 00 01   lui    $8, 1
+#                                              ^-- %hi(0x27ff0-0x1000c)
+# SO-NEXT:   10010:   21 08 7f e4   addi   $8, $8, 32740
+#                                                  ^-- %lo(0x27ff0-0x10010+4)
+
+# SO: SYMBOL TABLE:
+# SO: 0001000c     .text   00000000 bar
+# SO: 00027ff0     .got    00000000 .hidden _gp
+# SO: 00010000     .text   00000000 __start
diff --git a/test/ELF/mips-hilo-hi-only.s b/test/ELF/mips-hilo-hi-only.s
new file mode 100644 (file)
index 0000000..97808b5
--- /dev/null
@@ -0,0 +1,28 @@
+# Check warning on orphaned R_MIPS_HI16 relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start+0x10000)
+  addi   $t0,$t0,%lo(_label)
+_label:
+  nop
+
+# WARN: can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start) w/o addend
+# CHECK-NEXT   20004:   21 08 00 08   addi   $8, $8, 8
+#                                                    ^-- %lo(_label)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00020008    .text   00000000 _label
+# CHECK: 00020000    .text   00000000 __start
diff --git a/test/ELF/mips-hilo.s b/test/ELF/mips-hilo.s
new file mode 100644 (file)
index 0000000..4f14528
--- /dev/null
@@ -0,0 +1,53 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start)
+  lui    $t1,%hi(g1)
+  addi   $t0,$t0,%lo(__start+4)
+  addi   $t0,$t0,%lo(g1+8)
+
+  lui    $t0,%hi(l1+0x10000)
+  lui    $t1,%hi(l1+0x20000)
+  addi   $t0,$t0,%lo(l1+(-4))
+
+  .data
+  .type  l1,@object
+  .size  l1,4
+l1:
+  .word 0
+
+  .globl g1
+  .type  g1,@object
+  .size  g1,4
+g1:
+  .word 0
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start+4)
+# CHECK-NEXT:  20004:   3c 09 00 04   lui    $9, 4
+#                                                ^-- %hi(g1+8)
+# CHECK-NEXT:  20008:   21 08 00 04   addi   $8, $8, 4
+#                                                    ^-- %lo(__start+4)
+# CHECK-NEXT:  2000c:   21 08 00 0c   addi   $8, $8, 12
+#                                                    ^-- %lo(g1+8)
+# CHECK-NEXT:  20010:   3c 08 00 05   lui    $8, 5
+#                                                ^-- %hi(l1+0x10000-4)
+# CHECK-NEXT:  20014:   3c 09 00 06   lui    $9, 6
+#                                                ^-- %hi(l1+0x20000-4)
+# CHECK-NEXT:  20018:   21 08 ff fc   addi   $8, $8, -4
+#                                                    ^-- %lo(l1-4)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0040000 l   .data   00000004 l1
+# CHECK: 0020000     .text   00000000 __start
+# CHECK: 0040004 g   .data   00000004 g1
diff --git a/test/ELF/mips-jalr.test b/test/ELF/mips-jalr.test
new file mode 100644 (file)
index 0000000..c1b119c
--- /dev/null
@@ -0,0 +1,52 @@
+# Check that lld ignores R_MIPS_JALR relocation for now.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so -shared
+# RUN: llvm-objdump -d %t.so | FileCheck %s
+# RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK: 10000:   09 f8 20 03   jalr    $25
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+!ELF
+FileHeader:
+  Class:    ELFCLASS32
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_MIPS
+  Flags:    [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+  - Name:          .text
+    Type:          SHT_PROGBITS
+    Flags:         [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:  16
+    Content:       "09f82003"
+#                   ^-- jalr T1
+
+  - Name:          .rel.text
+    Type:          SHT_REL
+    Link:          .symtab
+    Info:          .text
+    Relocations:
+      - Offset:  0
+        Symbol:  T1
+        Type:    R_MIPS_JALR
+
+Symbols:
+  Local:
+    - Name:     T1
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0
+      Size:     4
+  Global:
+    - Name:     __start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0
+      Size:     4
diff --git a/test/ELF/mips-lo16-not-relative.s b/test/ELF/mips-lo16-not-relative.s
new file mode 100644 (file)
index 0000000..614e639
--- /dev/null
@@ -0,0 +1,23 @@
+# Check that R_MIPS_LO16 relocation is handled as non-relative,
+# and if a target symbol is a DSO data symbol, LLD create a copy
+# relocation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global __start
+__start:
+  addi   $t0, $t0, %lo(data0)
diff --git a/test/ELF/mips-nonalloc.s b/test/ELF/mips-nonalloc.s
new file mode 100644 (file)
index 0000000..7b0aa94
--- /dev/null
@@ -0,0 +1,21 @@
+# Check reading addends for relocations in non-allocatable sections.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-nonalloc.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .debug_info:
+# CHECK-NEXT:  0000 ffffffff 00020000 00020000
+#                            ^--------^-- __start
+
+  .global __start
+__start:
+  nop
+
+.section .debug_info
+  .word 0xffffffff
+  .word __start
diff --git a/test/ELF/mips-npic-call-pic.s b/test/ELF/mips-npic-call-pic.s
new file mode 100644 (file)
index 0000000..dbf0535
--- /dev/null
@@ -0,0 +1,144 @@
+# REQUIRES: mips
+# Check LA25 stubs creation. This stub code is necessary when
+# non-PIC code calls PIC function.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: ld.lld %t-npic.o %t-pic.o %p/Inputs/mips-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK:     Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       0c 00 80 0e     jal     131128 <foo1b+0x4>
+#                                                            ^-- .pic.foo1a
+# CHECK-NEXT:    20004:       00 00 00 00     nop
+# CHECK-NEXT:    20008:       0c 00 80 19     jal     131172 <foo2+0x4>
+#                                                            ^-- .pic.foo2
+# CHECK-NEXT:    2000c:       00 00 00 00     nop
+# CHECK-NEXT:    20010:       0c 00 80 12     jal     131144 <foo1b+0x14>
+#                                                            ^-- .pic.foo1b
+# CHECK-NEXT:    20014:       00 00 00 00     nop
+# CHECK-NEXT:    20018:       0c 00 80 19     jal     131172 <foo2+0x4>
+#                                                            ^-- .pic.foo2
+# CHECK-NEXT:    2001c:       00 00 00 00     nop
+# CHECK-NEXT:    20020:       0c 00 80 28     jal     131232 <fnpic+0x10>
+#                                                            ^-- .pic.fpic
+# CHECK-NEXT:    20024:       00 00 00 00     nop
+# CHECK-NEXT:    20028:       0c 00 80 24     jal     131216 <fnpic>
+# CHECK-NEXT:    2002c:       00 00 00 00     nop
+#
+# CHECK:      foo1a:
+# CHECK-NEXT:    20030:       00 00 00 00     nop
+#
+# CHECK:      foo1b:
+# CHECK-NEXT:    20034:       00 00 00 00     nop
+#
+# CHECK-NEXT:    20038:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    2003c:       08 00 80 0c     j       131120 <foo1a>
+# CHECK-NEXT:    20040:       27 39 00 30     addiu   $25, $25, 48
+# CHECK-NEXT:    20044:       00 00 00 00     nop
+# CHECK-NEXT:    20048:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    2004c:       08 00 80 0d     j       131124 <foo1b>
+# CHECK-NEXT:    20050:       27 39 00 34     addiu   $25, $25, 52
+# CHECK-NEXT:    20054:       00 00 00 00     nop
+# CHECK-NEXT:    20058:       00 00 00 00     nop
+# CHECK-NEXT:    2005c:       00 00 00 00     nop
+#
+# CHECK:      foo2:
+# CHECK-NEXT:    20060:       00 00 00 00     nop
+#
+# CHECK-NEXT:    20064:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20068:       08 00 80 18     j       131168 <foo2>
+# CHECK-NEXT:    2006c:       27 39 00 60     addiu   $25, $25, 96
+# CHECK-NEXT:    20070:       00 00 00 00     nop
+# CHECK-NEXT:    20074:       00 00 00 00     nop
+# CHECK-NEXT:    20078:       00 00 00 00     nop
+# CHECK-NEXT:    2007c:       00 00 00 00     nop
+#
+# CHECK:      fpic:
+# CHECK-NEXT:    20080:       00 00 00 00     nop
+# CHECK-NEXT:    20084:       00 00 00 00     nop
+# CHECK-NEXT:    20088:       00 00 00 00     nop
+# CHECK-NEXT:    2008c:       00 00 00 00     nop
+#
+# CHECK:      fnpic:
+# CHECK-NEXT:    20090:       00 00 00 00     nop
+# CHECK-NEXT:    20094:       00 00 00 00     nop
+# CHECK-NEXT:    20098:       00 00 00 00     nop
+# CHECK-NEXT:    2009c:       00 00 00 00     nop
+# CHECK-NEXT:    200a0:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    200a4:       08 00 80 20     j       131200 <fpic>
+# CHECK-NEXT:    200a8:       27 39 00 80     addiu   $25, $25, 128
+
+# Make sure tha thunks are created properly no matter how
+# objects are laid out.
+#
+# RUN: ld.lld %t-pic.o %t-npic.o %p/Inputs/mips-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
+
+# REVERSE:      foo1a:
+# REVERSE-NEXT:    20000:       00 00 00 00     nop
+#
+# REVERSE:      foo1b:
+# REVERSE-NEXT:    20004:       00 00 00 00     nop
+# REVERSE-NEXT:    20008:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    2000c:       08 00 80 00     j       131072 <foo1a>
+# REVERSE-NEXT:    20010:       27 39 00 00     addiu   $25, $25, 0
+# REVERSE-NEXT:    20014:       00 00 00 00     nop
+# REVERSE-NEXT:    20018:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    2001c:       08 00 80 01     j       131076 <foo1b>
+# REVERSE-NEXT:    20020:       27 39 00 04     addiu   $25, $25, 4
+# REVERSE-NEXT:    20024:       00 00 00 00     nop
+# REVERSE-NEXT:    20028:       00 00 00 00     nop
+# REVERSE-NEXT:    2002c:       00 00 00 00     nop
+#
+# REVERSE:      foo2:
+# REVERSE-NEXT:    20030:       00 00 00 00     nop
+# REVERSE-NEXT:    20034:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20038:       08 00 80 0c     j       131120 <foo2>
+# REVERSE-NEXT:    2003c:       27 39 00 30     addiu   $25, $25, 48
+# REVERSE-NEXT:    20040:       00 00 00 00     nop
+# REVERSE-NEXT:    20044:       00 00 00 00     nop
+# REVERSE-NEXT:    20048:       00 00 00 00     nop
+# REVERSE-NEXT:    2004c:       00 00 00 00     nop
+#
+# REVERSE:      __start:
+# REVERSE-NEXT:    20050:       0c 00 80 02     jal     131080 <foo1b+0x4>
+# REVERSE-NEXT:    20054:       00 00 00 00     nop
+# REVERSE-NEXT:    20058:       0c 00 80 0d     jal     131124 <foo2+0x4>
+# REVERSE-NEXT:    2005c:       00 00 00 00     nop
+# REVERSE-NEXT:    20060:       0c 00 80 06     jal     131096 <foo1b+0x14>
+# REVERSE-NEXT:    20064:       00 00 00 00     nop
+# REVERSE-NEXT:    20068:       0c 00 80 0d     jal     131124 <foo2+0x4>
+# REVERSE-NEXT:    2006c:       00 00 00 00     nop
+# REVERSE-NEXT:    20070:       0c 00 80 28     jal     131232 <fnpic+0x10>
+# REVERSE-NEXT:    20074:       00 00 00 00     nop
+# REVERSE-NEXT:    20078:       0c 00 80 24     jal     131216 <fnpic>
+# REVERSE-NEXT:    2007c:       00 00 00 00     nop
+#
+# REVERSE:      fpic:
+# REVERSE-NEXT:    20080:       00 00 00 00     nop
+# REVERSE-NEXT:    20084:       00 00 00 00     nop
+# REVERSE-NEXT:    20088:       00 00 00 00     nop
+# REVERSE-NEXT:    2008c:       00 00 00 00     nop
+#
+# REVERSE:      fnpic:
+# REVERSE-NEXT:    20090:       00 00 00 00     nop
+# REVERSE-NEXT:    20094:       00 00 00 00     nop
+# REVERSE-NEXT:    20098:       00 00 00 00     nop
+# REVERSE-NEXT:    2009c:       00 00 00 00     nop
+# REVERSE-NEXT:    200a0:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    200a4:       08 00 80 20     j       131200 <fpic>
+# REVERSE-NEXT:    200a8:       27 39 00 80     addiu   $25, $25, 128
+# REVERSE-NEXT:    200ac:       00 00 00 00     nop
+
+  .text
+  .globl __start
+__start:
+  jal foo1a
+  jal foo2
+  jal foo1b
+  jal foo2
+  jal fpic
+  jal fnpic
diff --git a/test/ELF/mips-options-r.test b/test/ELF/mips-options-r.test
new file mode 100644 (file)
index 0000000..c414405
--- /dev/null
@@ -0,0 +1,19 @@
+# Check that if input file contains .MIPS.options section and symbol
+# points to the section and the linker generates a relocatable output,
+# LLD does not crash and write section symbols point to the output
+# .MIPS.options section.
+#
+# PR 27878
+#
+# Input object file created using the following script:
+# % cat t.s
+#   .text
+#   nop
+# % as -mabi=64 -mips64r2 t.s
+
+# RUN: ld.lld -r %p/Inputs/mips-options.o -o %t.o
+# RUN: llvm-readobj -t %t.o | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK: Section: .MIPS.options
diff --git a/test/ELF/mips-options.s b/test/ELF/mips-options.s
new file mode 100644 (file)
index 0000000..30381ae
--- /dev/null
@@ -0,0 +1,28 @@
+# Check MIPS .MIPS.options section generation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+    lw   $t0,%call16(g1)($gp)
+
+# CHECK:      Name: _gp
+# CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]]
+
+# CHECK:      MIPS Options {
+# CHECK-NEXT:   ODK_REGINFO {
+# CHECK-NEXT:     GP: 0x[[GP]]
+# CHECK-NEXT:     General Mask: 0x10001001
+# CHECK-NEXT:     Co-Proc Mask0: 0x0
+# CHECK-NEXT:     Co-Proc Mask1: 0x0
+# CHECK-NEXT:     Co-Proc Mask2: 0x0
+# CHECK-NEXT:     Co-Proc Mask3: 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-pc-relocs.s b/test/ELF/mips-pc-relocs.s
new file mode 100644 (file)
index 0000000..209d7d2
--- /dev/null
@@ -0,0 +1,45 @@
+# Check R_MIPS_PCxxx relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -mcpu=mips32r6 -d -t -s %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lwpc      $6, _foo                # R_MIPS_PC19_S2
+  beqc      $5, $6, _foo            # R_MIPS_PC16
+  beqzc     $9, _foo                # R_MIPS_PC21_S2
+  bc        _foo                    # R_MIPS_PC26_S2
+  aluipc    $2, %pcrel_hi(_foo)     # R_MIPS_PCHI16
+  addiu     $2, $2, %pcrel_lo(_foo) # R_MIPS_PCLO16
+
+  .data
+  .word _foo+8-.                    # R_MIPS_PC32
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       ec c8 00 08     lwpc    $6, 32
+#                                      ^-- (0x20020-0x20000)>>2
+# CHECK-NEXT:    20004:       20 a6 00 06     beqc    $5, $6, 28
+#                                      ^-- (0x20020-4-0x20004)>>2
+# CHECK-NEXT:    20008:       d9 20 00 05     beqzc   $9, 24
+#                                      ^-- (0x20020-4-0x20008)>>2
+# CHECK-NEXT:    2000c:       c8 00 00 04     bc      20
+#                                      ^-- (0x20020-4-0x2000c)>>2
+# CHECK-NEXT:    20010:       ec 5f 00 00     aluipc  $2, 0
+#                                      ^-- %hi(0x20020-0x20010)
+# CHECK-NEXT:    20014:       24 42 00 0c     addiu   $2, $2, 12
+#                                      ^-- %lo(0x20020-0x20014)
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 40000 fffe0028 00000000 00000000 00000000
+#                   ^-- 0x20020 + 8 - 0x40000
+
+# CHECK: 00020000         .text           00000000 __start
+# CHECK: 00020020         .text           00000000 _foo
diff --git a/test/ELF/mips-plt-copy.s b/test/ELF/mips-plt-copy.s
new file mode 100644 (file)
index 0000000..58883d8
--- /dev/null
@@ -0,0 +1,85 @@
+# Check creating of R_MIPS_COPY and R_MIPS_JUMP_SLOT dynamic relocations
+# and corresponding PLT entries.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK:      Primary GOT {
+# CHECK:        Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
+
+# CHECK:      PLT GOT {
+# CHECK:        Entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Initial: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Value: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Initial: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Value: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo1
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT: }
+
+  .text
+  .globl __start
+__start:
+  lui    $t0,%hi(foo0)     # R_MIPS_HI16 requires JUMP_SLOT/PLT entry
+                           # for DSO defined func.
+  addi   $t0,$t0,%lo(foo0)
+  lui    $t0,%hi(bar)      # Does not require PLT for locally defined func.
+  addi   $t0,$t0,%lo(bar)
+  lui    $t0,%hi(loc)      # Does not require PLT for local func.
+  addi   $t0,$t0,%lo(loc)
+
+  lui    $t0,%hi(data0)    # R_MIPS_HI16 requires COPY rel for DSO defined data.
+  addi   $t0,$t0,%lo(data0)
+  lui    $t0,%hi(gd)       # Does not require COPY rel for locally defined data.
+  addi   $t0,$t0,%lo(gd)
+  lui    $t0,%hi(ld)       # Does not require COPY rel for local data.
+  addi   $t0,$t0,%lo(ld)
+
+  .globl bar
+  .type  bar, @function
+bar:
+  nop
+loc:
+  nop
+
+  .rodata
+  .globl gd
+gd:
+  .word 0
+ld:
+  .word data1+8            # R_MIPS_32 requires REL32 dnamic relocation
+                           # for DSO defined data. For now we generate COPY one.
+  .word foo1+8             # R_MIPS_32 requires PLT entry for DSO defined func.
diff --git a/test/ELF/mips-reginfo.s b/test/ELF/mips-reginfo.s
new file mode 100644 (file)
index 0000000..dd4771c
--- /dev/null
@@ -0,0 +1,26 @@
+# Check MIPS .reginfo section generation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-readobj -symbols -mips-reginfo %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+    lw   $t0,%call16(g1)($gp)
+
+# CHECK:      Name: _gp
+# CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]]
+
+# CHECK:      MIPS RegInfo {
+# CHECK-NEXT:   GP: 0x[[GP]]
+# CHECK-NEXT:   General Mask: 0x10000101
+# CHECK-NEXT:   Co-Proc Mask0: 0x0
+# CHECK-NEXT:   Co-Proc Mask1: 0x0
+# CHECK-NEXT:   Co-Proc Mask2: 0x0
+# CHECK-NEXT:   Co-Proc Mask3: 0x0
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-sto-plt.s b/test/ELF/mips-sto-plt.s
new file mode 100644 (file)
index 0000000..bd8de41
--- /dev/null
@@ -0,0 +1,66 @@
+# Check assigning STO_MIPS_PLT flag to symbol needs a pointer equality.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dt -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo0@
+# CHECK-NEXT:   Value: 0x0
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Undefined
+# CHECK-NEXT: }
+# CHECK:      Symbol {
+# CHECK:        Name: foo1@
+# CHECK-NEXT:   Value: 0x20050
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other [ (0x8)
+# CHECK-NEXT:     STO_MIPS_PLT
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: Undefined
+# CHECK-NEXT: }
+
+# CHECK:      Primary GOT {
+# CHECK:        Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK:      PLT GOT {
+# CHECK:        Entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Initial:
+# CHECK-NEXT:       Value: 0x0
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Initial:
+# CHECK-NEXT:       Value: 0x20050
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo1
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+
+  .text
+  .globl __start
+__start:
+  jal    foo0               # R_MIPS_26 against 'foo0' from DSO
+  lui    $t0,%hi(foo1)      # R_MIPS_HI16/LO16 against 'foo1' from DSO
+  addi   $t0,$t0,%lo(foo1)
+
+loc:
+  nop
diff --git a/test/ELF/mips-tls-64.s b/test/ELF/mips-tls-64.s
new file mode 100644 (file)
index 0000000..9c05e94
--- /dev/null
@@ -0,0 +1,86 @@
+# Check MIPS TLS 64-bit relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 28   addiu   $2, $3, -32728
+# DIS-NEXT:    20004:   24 62 80 38   addiu   $2, $3, -32712
+# DIS-NEXT:    20008:   8f 82 80 20   lw      $2, -32736($gp)
+# DIS-NEXT:    2000c:   24 62 80 48   addiu   $2, $3, -32696
+
+# DIS:      Contents of section .got:
+# DIS_NEXT:  30008 00000000 00000000 80000000 00000000
+# DIS_NEXT:  30018 00000000 00020000 00000000 00000000
+# DIS_NEXT:  30028 00000000 00000004 00000000 00000000
+# DIS_NEXT:  30038 00000000 00000000 00000000 00000004
+
+# DIS: 0000000000030000 l       .tdata          00000000 .tdata
+# DIS: 0000000000030000 l       .tdata          00000000 loc
+# DIS: 0000000000000004 g       .tdata          00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rela.dyn {
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30040 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE - 0x4
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x37FF8
+# CHECK-NEXT:   Reserved entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30008
+# CHECK-NEXT:       Access: -32752
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Purpose: Lazy resolver
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30010
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x80000000
+# CHECK-NEXT:       Purpose: Module pointer (GNU extension)
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30018
+# CHECK-NEXT:       Access: -32736
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Value: 0x0
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 5
+#               ^-- 0x30020 / -32728 - R_MIPS_TLS_GD  - R_MIPS_TLS_DTPMOD32 foo
+#               ^-- 0x30028 / -32720                  - R_MIPS_TLS_DTPREL32 foo
+#               ^-- 0x30030 / -32712 - R_MIPS_TLS_LDM - R_MIPS_TLS_DTPMOD32 loc
+#               ^-- 0x30038 / -32704
+#               ^-- 0x30040 / -32696 - R_MIPS_TLS_GOTTPREL - R_MIPS_TLS_TPREL32
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  lw    $2, %got(foo0)($gp)
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+ .global foo
+loc:
+ .word 0
+foo:
+ .word 0
diff --git a/test/ELF/mips-tls-hilo.s b/test/ELF/mips-tls-hilo.s
new file mode 100644 (file)
index 0000000..7628cb3
--- /dev/null
@@ -0,0 +1,52 @@
+# Check MIPS R_MIPS_TLS_DTPREL_HI16/LO16 and R_MIPS_TLS_TPREL_HI16/LO16
+# relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 00 00   addiu   $2, $3, 0
+#                       %hi(loc0 - .tdata - 0x8000) --^
+# DIS-NEXT:    20004:   24 62 80 00   addiu   $2, $3, -32768
+#                       %lo(loc0 - .tdata - 0x8000) --^
+# DIS-NEXT:    20008:   24 62 00 00   addiu   $2, $3, 0
+#                       %hi(loc0 - .tdata - 0x7000) --^
+# DIS-NEXT:    2000c:   24 62 90 00   addiu   $2, $3, -28672
+#                       %lo(loc0 - .tdata - 0x7000) --^
+
+# DIS: 00030000 l       .tdata          00000000 .tdata
+# DIS: 00030000 l       .tdata          00000000 loc0
+
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+# CHECK-NOT:  Primary GOT
+
+# SO:      Relocations [
+# SO-NEXT: ]
+# SO:      Primary GOT {
+# SO:        Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 0
+# SO-NEXT: }
+
+  .text
+  .globl  __start
+  .type __start,@function
+__start:
+  addiu $2, $3, %dtprel_hi(loc0)  # R_MIPS_TLS_DTPREL_HI16
+  addiu $2, $3, %dtprel_lo(loc0)  # R_MIPS_TLS_DTPREL_LO16
+  addiu $2, $3, %tprel_hi(loc0)   # R_MIPS_TLS_TPREL_HI16
+  addiu $2, $3, %tprel_lo(loc0)   # R_MIPS_TLS_TPREL_LO16
+
+ .section .tdata,"awT",%progbits
+loc0:
+ .word 0
diff --git a/test/ELF/mips-tls.s b/test/ELF/mips-tls.s
new file mode 100644 (file)
index 0000000..9635558
--- /dev/null
@@ -0,0 +1,77 @@
+# Check MIPS TLS relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %p/Inputs/mips-tls.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 1c   addiu   $2, $3, -32740
+# DIS-NEXT:    20004:   24 62 80 24   addiu   $2, $3, -32732
+# DIS-NEXT:    20008:   8f 82 80 18   lw      $2, -32744($gp)
+# DIS-NEXT:    2000c:   24 62 80 2c   addiu   $2, $3, -32724
+
+# DIS:      Contents of section .got:
+# DIS_NEXT:  30004 00000000 80000000 00020000 00000000
+# DIS_NEXT:  30014 00000000 00000000 00000000 00000000
+
+# DIS: 00030000 l       .tdata          00000000 .tdata
+# DIS: 00030000 l       .tdata          00000000 loc
+# DIS: 00000000 g       *UND*           00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x30018 R_MIPS_TLS_DTPMOD32 - 0x0
+# CHECK-NEXT:     0x30010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT:     0x30014 R_MIPS_TLS_DTPREL32 foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x37FF4
+# CHECK-NEXT:   Reserved entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30004
+# CHECK-NEXT:       Access: -32752
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Purpose: Lazy resolver
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30008
+# CHECK-NEXT:       Access: -32748
+# CHECK-NEXT:       Initial: 0x80000000
+# CHECK-NEXT:       Purpose: Module pointer (GNU extension)
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x3000C
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x20000
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 5
+#               ^-- 0x30010 / -32740 - R_MIPS_TLS_GD  - R_MIPS_TLS_DTPMOD32 foo
+#               ^-- 0x30018 / -32736                  - R_MIPS_TLS_DTPREL32 foo
+#               ^-- 0x3001C / -32732 - R_MIPS_TLS_LDM - R_MIPS_TLS_DTPMOD32 loc
+#               ^-- 0x30020 / -32728
+#               ^-- 0x30024 / -32724 - R_MIPS_TLS_GOTTPREL - R_MIPS_TLS_TPREL32
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  lw    $2, %got(__start)($gp)
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+loc:
+ .word 0
diff --git a/test/ELF/new-dtags.test b/test/ELF/new-dtags.test
new file mode 100644 (file)
index 0000000..334d477
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags -o %t
+// RUN: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2
+// RUN: llvm-readobj --dynamic-table %t | FileCheck --check-prefix=DISABLE %s
+// RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s
+
+// DISABLE: DynamicSection [
+// DISABLE:   0x000000000000000F RPATH                /somepath
+// DISABLE-NOT: RUNPATH
+// DISABLE: ]
+
+// ENABLE: DynamicSection [
+// ENABLE:   0x000000000000001D RUNPATH              /somepath
+// ENABLE-NOT: RPATH
+// ENABLE: ]
diff --git a/test/ELF/no-augmentation.s b/test/ELF/no-augmentation.s
new file mode 100644 (file)
index 0000000..31cd92e
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t | FileCheck -allow-empty %s
+
+// REQUIRES: mips
+
+// CHECK-NOT: corrupted or unsupported CIE information
+// CHECK-NOT: corrupted CIE
+
+.global __start
+__start:
+
+.section        .eh_frame,"aw",@progbits
+        .4byte  9
+        .4byte  0x0
+        .byte   0x1
+        .string ""
+        .uleb128 0x1
+        .sleb128 -4
+        .byte   0x1f
diff --git a/test/ELF/no-inhibit-exec.s b/test/ELF/no-inhibit-exec.s
new file mode 100644 (file)
index 0000000..31638fd
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t -o %t2
+# RUN: ld.lld %t --noinhibit-exec -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: x86
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: _start
+# CHECK-NEXT: 11000:   e8 fb ef fe ff callq -69637
+
+# next code will not link without noinhibit-exec flag
+# because of undefined symbol _bar
+.globl _start
+_start:
+  call _bar
diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s
new file mode 100644 (file)
index 0000000..68e9979
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-ar rcs %t.a %t.o
+// RUN: not ld.lld -o %t2 -u _start %t.a 2>&1 | FileCheck %s
+
+// CHECK: -m or at least a .o file required
+
+.global _start
+_start:
diff --git a/test/ELF/no-plt-shared.s b/test/ELF/no-plt-shared.s
new file mode 100644 (file)
index 0000000..ac45ed5
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t2.so -shared
+// RUN: llvm-readobj -r %t2.so | FileCheck %s
+
+        .data
+fp:
+        .quad bar
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_64 bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/no-symtab.s b/test/ELF/no-symtab.s
new file mode 100644 (file)
index 0000000..158bd72
--- /dev/null
@@ -0,0 +1,4 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o %t
+.global _start
+_start:
diff --git a/test/ELF/no-undefined.s b/test/ELF/no-undefined.s
new file mode 100644 (file)
index 0000000..fa4d5e9
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld --no-undefined -shared %t -o %t.so
+# RUN: ld.lld -shared %t -o %t1.so
+
+.globl _shared
+_shared:
+  callq _unresolved@PLT
diff --git a/test/ELF/noplt-pie.s b/test/ELF/noplt-pie.s
new file mode 100644 (file)
index 0000000..1eb8493
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: ld.lld %t1.o %t2.so -o %t.out
+# RUN: llvm-readobj -s -r %t.out | FileCheck %s
+
+# CHECK: Section {
+# CHECK-NOT: Name: .plt
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x120B0 R_X86_64_GLOB_DAT bar 0x0
+# CHECK-NEXT:     0x120B8 R_X86_64_GLOB_DAT zed 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ movq bar@GOTPCREL(%rip), %rcx
+ movq zed@GOTPCREL(%rip), %rcx
diff --git a/test/ELF/note.s b/test/ELF/note.s
new file mode 100644 (file)
index 0000000..a383b95
--- /dev/null
@@ -0,0 +1,18 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress:
+// CHECK-NEXT: PhysicalAddress:
+// CHECK-NEXT: FileSize:        8
+// CHECK-NEXT: MemSize:         8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment:       1
+
+        .section        .note.test,"a",@note
+        .quad 42
diff --git a/test/ELF/output-section.s b/test/ELF/output-section.s
new file mode 100644 (file)
index 0000000..6850525
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Symbol {
+// CHECK:        Name: bar_sym
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding:
+// CHECK-NEXT:   Type:
+// CHECK-NEXT:   Other:
+// CHECK-NEXT:   Section: bar
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: foo_sym
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding:
+// CHECK-NEXT:   Type:
+// CHECK-NEXT:   Other:
+// CHECK-NEXT:   Section: foo
+// CHECK-NEXT: }
+
+.section foo
+.global foo_sym
+foo_sym:
+
+.section bar, "a"
+.global bar_sym
+bar_sym:
+
+.global _start
+_start:
diff --git a/test/ELF/phdr-align.s b/test/ELF/phdr-align.s
new file mode 100644 (file)
index 0000000..58d537b
--- /dev/null
@@ -0,0 +1,82 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN:  .bss : { *(.bss) } \
+# RUN:  .data : { *(.data) } \
+# RUN:  .text : { *(.text) } }" > %t.script
+# RUN: ld.lld %t.o --script %t.script -o %t
+# RUN: llvm-readobj -sections -symbols %t | FileCheck %s
+
+# CHECK:      Sections [
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 0
+# CHECK-NEXT:    Name:  (0)
+# CHECK-NEXT:    Type: SHT_NULL
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x0
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 0
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 1
+# CHECK-NEXT:    Name: .bss
+# CHECK-NEXT:    Type: SHT_NOBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x158
+# CHECK-NEXT:    Offset: 0x158
+# CHECK-NEXT:    Size: 6
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 2
+# CHECK-NEXT:    Name: .data
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x15E
+# CHECK-NEXT:    Offset: 0x15E
+# CHECK-NEXT:    Size: 2
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 3
+# CHECK-NEXT:    Name: .text
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_EXECINSTR
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x160
+# CHECK-NEXT:    Offset: 0x160
+# CHECK-NEXT:    Size: 1
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 4
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+
+.global _start
+.text
+_start:
+ nop
+.data
+ .word 1
+.bss
+ .space 6
diff --git a/test/ELF/pie-weak.s b/test/ELF/pie-weak.s
new file mode 100644 (file)
index 0000000..e74bcdf
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -filetype=obj -relax-relocations=false -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOCS %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+# RELOCS:      Relocations [
+# RELOCS-NEXT: ]
+
+.weak foo
+
+.globl _start
+_start:
+# DISASM: _start:
+# DISASM-NEXT: 1000: 48 8b 05 69 10 00 00 movq 4201(%rip), %rax
+#                                              ^ .got - (.text + 7)
+mov foo@gotpcrel(%rip), %rax
diff --git a/test/ELF/pie.s b/test/ELF/pie.s
new file mode 100644 (file)
index 0000000..4cf1743
--- /dev/null
@@ -0,0 +1,102 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+## Test --pic-executable alias
+# RUN: ld.lld --pic-executable %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: SharedObject
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version: 1
+# CHECK-NEXT:  Entry: 0x1000
+# CHECK-NEXT:  ProgramHeaderOffset: 0x40
+# CHECK-NEXT:  SectionHeaderOffset: 0x1110
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize: 64
+# CHECK-NEXT:  ProgramHeaderEntrySize: 56
+# CHECK-NEXT:  ProgramHeaderCount: 7
+# CHECK-NEXT:  SectionHeaderEntrySize: 64
+# CHECK-NEXT:  SectionHeaderCount: 9
+# CHECK-NEXT:  StringTableSectionIndex: 7
+# CHECK-NEXT: }
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_PHDR
+# CHECK-NEXT:    Offset: 0x40
+# CHECK-NEXT:    VirtualAddress: 0x40
+# CHECK-NEXT:    PhysicalAddress: 0x40
+# CHECK-NEXT:    FileSize: 392
+# CHECK-NEXT:    MemSize: 392
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 8
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 497
+# CHECK-NEXT:    MemSize: 497
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_X
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 112
+# CHECK-NEXT:    MemSize: 112
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_DYNAMIC
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 112
+# CHECK-NEXT:    MemSize: 112
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 8
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
diff --git a/test/ELF/plt-aarch64.s b/test/ELF/plt-aarch64.s
new file mode 100644 (file)
index 0000000..3f124b0
--- /dev/null
@@ -0,0 +1,205 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/plt-aarch64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t.o %t2.so -o %t.so
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s -r %t.so | FileCheck --check-prefix=CHECKDSO %s
+// RUN: llvm-objdump -s -section=.got.plt %t.so | FileCheck --check-prefix=DUMPDSO %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASMDSO %s
+// RUN: llvm-readobj -s -r %t.exe | FileCheck --check-prefix=CHECKEXE %s
+// RUN: llvm-objdump -s -section=.got.plt %t.exe | FileCheck --check-prefix=DUMPEXE %s
+// RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASMEXE %s
+
+// REQUIRES: aarch64
+
+// CHECKDSO:     Name: .plt
+// CHECKDSO-NEXT:     Type: SHT_PROGBITS
+// CHECKDSO-NEXT:     Flags [
+// CHECKDSO-NEXT:       SHF_ALLOC
+// CHECKDSO-NEXT:       SHF_EXECINSTR
+// CHECKDSO-NEXT:     ]
+// CHECKDSO-NEXT:     Address: 0x1010
+// CHECKDSO-NEXT:     Offset:
+// CHECKDSO-NEXT:     Size: 80
+// CHECKDSO-NEXT:     Link:
+// CHECKDSO-NEXT:     Info:
+// CHECKDSO-NEXT:     AddressAlignment: 16
+
+// CHECKDSO:     Name: .got.plt
+// CHECKDSO-NEXT:     Type: SHT_PROGBITS
+// CHECKDSO-NEXT:     Flags [
+// CHECKDSO-NEXT:       SHF_ALLOC
+// CHECKDSO-NEXT:       SHF_WRITE
+// CHECKDSO-NEXT:     ]
+// CHECKDSO-NEXT:     Address: 0x3000
+// CHECKDSO-NEXT:     Offset:
+// CHECKDSO-NEXT:     Size: 48
+// CHECKDSO-NEXT:     Link:
+// CHECKDSO-NEXT:     Info:
+// CHECKDSO-NEXT:     AddressAlignment: 8
+
+// CHECKDSO: Relocations [
+// CHECKDSO-NEXT:   Section ({{.*}}) .rela.plt {
+
+// &(.got.plt[3]) = 0x3000 + 3 * 8 = 0x3018
+// CHECKDSO-NEXT:     0x3018 R_AARCH64_JUMP_SLOT foo
+
+// &(.got.plt[4]) = 0x3000 + 4 * 8 = 0x3020
+// CHECKDSO-NEXT:     0x3020 R_AARCH64_JUMP_SLOT bar
+
+// &(.got.plt[5]) = 0x3000 + 5 * 8 = 0x3028
+// CHECKDSO-NEXT:     0x3028 R_AARCH64_JUMP_SLOT weak
+// CHECKDSO-NEXT:   }
+// CHECKDSO-NEXT: ]
+
+// DUMPDSO: Contents of section .got.plt:
+// .got.plt[0..2] = 0 (reserved)
+// .got.plt[3..5] = .plt = 0x1010
+// DUMPDSO-NEXT:  3000 00000000 00000000 00000000 00000000  ................
+// DUMPDSO-NEXT:  3010 00000000 00000000 10100000 00000000  ................
+// DUMPDSO-NEXT:  3020 10100000 00000000 10100000 00000000  ................
+
+// DISASMDSO: _start:
+// 0x1030 - 0x1000 = 0x30 = 48
+// DISASMDSO-NEXT:     1000:   0c 00 00 14     b       #48
+// 0x1040 - 0x1004 = 0x3c = 60
+// DISASMDSO-NEXT:     1004:   0f 00 00 14     b       #60
+// 0x1050 - 0x1008 = 0x48 = 72
+// DISASMDSO-NEXT:     1008:   12 00 00 14     b       #72
+
+// DISASMDSO: foo:
+// DISASMDSO-NEXT:     100c:   1f 20 03 d5     nop
+
+// DISASMDSO: Disassembly of section .plt:
+// DISASMDSO-NEXT: .plt:
+// DISASMDSO-NEXT:     1010:   f0 7b bf a9     stp     x16, x30, [sp, #-16]!
+// &(.got.plt[2]) = 0x3000 + 2 * 8 = 0x3010
+// Page(0x3010) - Page(0x1014) = 0x3000 - 0x1000 = 0x2000 = 8192
+// DISASMDSO-NEXT:     1014:   10 00 00 d0     adrp    x16, #8192
+// 0x3010 & 0xFFF = 0x10 = 16
+// DISASMDSO-NEXT:     1018:   11 0a 40 f9 ldr x17, [x16, #16]
+// DISASMDSO-NEXT:     101c:   10 42 00 91     add     x16, x16, #16
+// DISASMDSO-NEXT:     1020:   20 02 1f d6     br      x17
+// DISASMDSO-NEXT:     1024:   1f 20 03 d5     nop
+// DISASMDSO-NEXT:     1028:   1f 20 03 d5     nop
+// DISASMDSO-NEXT:     102c:   1f 20 03 d5     nop
+
+// foo@plt
+// Page(0x3018) - Page(0x1030) = 0x3000 - 0x1000 = 0x2000 = 8192
+// DISASMDSO-NEXT:     1030:   10 00 00 d0     adrp    x16, #8192
+// 0x3018 & 0xFFF = 0x18 = 24
+// DISASMDSO-NEXT:     1034:   11 0e 40 f9     ldr     x17, [x16, #24]
+// DISASMDSO-NEXT:     1038:   10 62 00 91     add     x16, x16, #24
+// DISASMDSO-NEXT:     103c:   20 02 1f d6     br      x17
+
+// bar@plt
+// Page(0x3020) - Page(0x1040) = 0x3000 - 0x1000 = 0x2000 = 8192
+// DISASMDSO-NEXT:     1040:   10 00 00 d0     adrp    x16, #8192
+// 0x3020 & 0xFFF = 0x20 = 32
+// DISASMDSO-NEXT:     1044:   11 12 40 f9     ldr     x17, [x16, #32]
+// DISASMDSO-NEXT:     1048:   10 82 00 91     add     x16, x16, #32
+// DISASMDSO-NEXT:     104c:   20 02 1f d6     br      x17
+
+// weak@plt
+// Page(0x3028) - Page(0x1050) = 0x3000 - 0x1000 = 0x2000 = 8192
+// DISASMDSO-NEXT:     1050:   10 00 00 d0     adrp    x16, #8192
+// 0x3028 & 0xFFF = 0x28 = 40
+// DISASMDSO-NEXT:     1054:   11 16 40 f9     ldr     x17, [x16, #40]
+// DISASMDSO-NEXT:     1058:   10 a2 00 91     add     x16, x16, #40
+// DISASMDSO-NEXT:     105c:   20 02 1f d6     br      x17
+
+// CHECKEXE:     Name: .plt
+// CHECKEXE-NEXT:     Type: SHT_PROGBITS
+// CHECKEXE-NEXT:     Flags [
+// CHECKEXE-NEXT:       SHF_ALLOC
+// CHECKEXE-NEXT:       SHF_EXECINSTR
+// CHECKEXE-NEXT:     ]
+// CHECKEXE-NEXT:     Address: 0x11010
+// CHECKEXE-NEXT:     Offset:
+// CHECKEXE-NEXT:     Size: 64
+// CHECKEXE-NEXT:     Link:
+// CHECKEXE-NEXT:     Info:
+// CHECKEXE-NEXT:     AddressAlignment: 16
+
+// CHECKEXE:     Name: .got.plt
+// CHECKEXE-NEXT:     Type: SHT_PROGBITS
+// CHECKEXE-NEXT:     Flags [
+// CHECKEXE-NEXT:       SHF_ALLOC
+// CHECKEXE-NEXT:       SHF_WRITE
+// CHECKEXE-NEXT:     ]
+// CHECKEXE-NEXT:     Address: 0x13000
+// CHECKEXE-NEXT:     Offset:
+// CHECKEXE-NEXT:     Size: 40
+// CHECKEXE-NEXT:     Link:
+// CHECKEXE-NEXT:     Info:
+// CHECKEXE-NEXT:     AddressAlignment: 8
+
+// CHECKEXE: Relocations [
+// CHECKEXE-NEXT:   Section ({{.*}}) .rela.plt {
+
+// &(.got.plt[3]) = 0x13000 + 3 * 8 = 0x13018
+// CHECKEXE-NEXT:     0x13018 R_AARCH64_JUMP_SLOT bar 0x0
+
+// &(.got.plt[4]) = 0x13000 + 4 * 8 = 0x13020
+// CHECKEXE-NEXT:     0x13020 R_AARCH64_JUMP_SLOT weak 0x0
+// CHECKEXE-NEXT:   }
+// CHECKEXE-NEXT: ]
+
+// DUMPEXE: Contents of section .got.plt:
+// .got.plt[0..2] = 0 (reserved)
+// .got.plt[3..4] = .plt = 0x11010
+// DUMPEXE-NEXT:  13000 00000000 00000000 00000000 00000000  ................
+// DUMPEXE-NEXT:  13010 00000000 00000000 10100100 00000000  ................
+// DUMPEXE-NEXT:  13020 10100100 00000000                    ........
+
+// DISASMEXE: _start:
+// 0x1100c - 0x11000 = 0xc = 12
+// DISASMEXE-NEXT:    11000:   03 00 00 14     b       #12
+// 0x11030 - 0x11004 = 0x2c = 44
+// DISASMEXE-NEXT:    11004:   0b 00 00 14     b       #44
+// 0x11040 - 0x11008 = 0x38 = 56
+// DISASMEXE-NEXT:    11008:   0e 00 00 14     b       #56
+
+// DISASMEXE: foo:
+// DISASMEXE-NEXT:    1100c:   1f 20 03 d5     nop
+
+// DISASMEXE: Disassembly of section .plt:
+// DISASMEXE-NEXT: .plt:
+// DISASMEXE-NEXT:    11010:   f0 7b bf a9     stp     x16, x30, [sp, #-16]!
+// &(.got.plt[2]) = 0x120B0 + 2 * 8 = 0x120C0
+// Page(0x13010) - Page(0x11014) = 0x13000 - 0x11000 = 0x1000 = 8192
+// DISASMEXE-NEXT:    11014:   10 00 00 d0     adrp    x16, #8192
+// 0x120c0 & 0xFFF = 0xC0 = 192
+// DISASMEXE-NEXT:    11018:   11 0a 40 f9     ldr     x17, [x16, #16]
+// DISASMEXE-NEXT:    1101c:   10 42 00 91     add     x16, x16, #16
+// DISASMEXE-NEXT:    11020:   20 02 1f d6     br      x17
+// DISASMEXE-NEXT:    11024:   1f 20 03 d5     nop
+// DISASMEXE-NEXT:    11028:   1f 20 03 d5     nop
+// DISASMEXE-NEXT:    1102c:   1f 20 03 d5     nop
+
+// bar@plt
+// Page(0x13018) - Page(0x11030) = 0x12000 - 0x11000 = 0x1000 = 8192
+// DISASMEXE-NEXT:    11030:   10 00 00 d0     adrp    x16, #8192
+// 0x120C8 & 0xFFF = 0xC8 = 200
+// DISASMEXE-NEXT:    11034:   11 0e 40 f9     ldr     x17, [x16, #24]
+// DISASMEXE-NEXT:    11038:   10 62 00 91     add     x16, x16, #24
+// DISASMEXE-NEXT:    1103c:   20 02 1f d6     br      x17
+
+// weak@plt
+// Page(0x13020) - Page(0x11040) = 0x12000 - 0x11000 = 0x1000 = 8192
+// DISASMEXE-NEXT:    11040:   10 00 00 d0     adrp    x16, #8192
+// 0x120D0 & 0xFFF = 0xD0 = 208
+// DISASMEXE-NEXT:    11044:   11 12 40 f9     ldr     x17, [x16, #32]
+// DISASMEXE-NEXT:    11048:   10 82 00 91     add     x16, x16, #32
+// DISASMEXE-NEXT:    1104c:   20 02 1f d6     br      x17
+
+.global _start,foo,bar
+.weak weak
+_start:
+  b foo
+  b bar
+  b weak
+
+.section .text2,"ax",@progbits
+foo:
+  nop
diff --git a/test/ELF/plt-i686.s b/test/ELF/plt-i686.s
new file mode 100644 (file)
index 0000000..bf07fed
--- /dev/null
@@ -0,0 +1,174 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// RUN: ld.lld -shared %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck --check-prefix=CHECKSHARED %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMSHARED %s
+// RUN: ld.lld -pie %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMPIE %s
+// REQUIRES: x86
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11020
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Name: .got.plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x13000
+// CHECK-NEXT: Offset: 0x3000
+// CHECK-NEXT: Size: 20
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+
+// 0x13000 + got.plt.reserved(12) = 0x1300C
+// 0x13000 + got.plt.reserved(12) + 4 = 0x13010
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+// CHECK-NEXT:     0x1300C R_386_JUMP_SLOT bar 0x0
+// CHECK-NEXT:     0x13010 R_386_JUMP_SLOT zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+
+// 16 is the size of PLT[0]
+// (0x11010 + 16) - (0x11000 + 1) - 4 = 27
+// (0x11010 + 16) - (0x11005 + 1) - 4 = 22
+// (0x11020 + 16) - (0x1100a + 1) - 4 = 33
+
+// DISASM:       local:
+// DISASM-NEXT:  11000: {{.*}}
+// DISASM-NEXT:  11002: {{.*}}
+// DISASM:       _start:
+// 0x11013 + 5 - 24 = 0x11000
+// DISASM-NEXT: 11004: e9 27 00 00 00 jmp 39
+// DISASM-NEXT: 11009: e9 22 00 00 00 jmp 34
+// DISASM-NEXT: 1100e: e9 2d 00 00 00 jmp 45
+// DISASM-NEXT: 11013: e9 e8 ff ff ff jmp -24
+
+// 0x11010 - 0x1102b - 5 = -32
+// 0x11010 - 0x1103b - 5 = -48
+// 77828 = 0x13004 = .got.plt (0x13000) + 4
+// 77832 = 0x13008 = .got.plt (0x13000) + 8
+// 77836 = 0x1300C = .got.plt (0x13000) + got.plt.reserved(12)
+// 77840 = 0x13010 = .got.plt (0x13000) + got.plt.reserved(12) + 4
+// DISASM:      Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020: ff 35 04 30 01 00 pushl 77828
+// DISASM-NEXT:    11026: ff 25 08 30 01 00 jmpl *77832
+// DISASM-NEXT:    1102c: 90 nop
+// DISASM-NEXT:    1102d: 90 nop
+// DISASM-NEXT:    1102e: 90 nop
+// DISASM-NEXT:    1102f: 90 nop
+// DISASM-NEXT:    11030: ff 25 0c 30 01 00 jmpl *77836
+// DISASM-NEXT:    11036: 68 00 00 00 00 pushl $0
+// DISASM-NEXT:    1103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-NEXT:    11040: ff 25 10 30 01 00 jmpl *77840
+// DISASM-NEXT:    11046: 68 08 00 00 00 pushl $8
+// DISASM-NEXT:    1104b: e9 d0 ff ff ff jmp -48 <.plt>
+
+// CHECKSHARED:        Name: .plt
+// CHECKSHARED-NEXT:   Type: SHT_PROGBITS
+// CHECKSHARED-NEXT:   Flags [
+// CHECKSHARED-NEXT:     SHF_ALLOC
+// CHECKSHARED-NEXT:     SHF_EXECINSTR
+// CHECKSHARED-NEXT:   ]
+// CHECKSHARED-NEXT:   Address: 0x1020
+// CHECKSHARED-NEXT:   Offset: 0x1020
+// CHECKSHARED-NEXT:   Size: 48
+// CHECKSHARED-NEXT:   Link: 0
+// CHECKSHARED-NEXT:   Info: 0
+// CHECKSHARED-NEXT:   AddressAlignment: 16
+// CHECKSHARED-NEXT:   EntrySize: 0
+// CHECKSHARED-NEXT:   }
+// CHECKSHARED:        Name: .got.plt
+// CHECKSHARED-NEXT:   Type: SHT_PROGBITS
+// CHECKSHARED-NEXT:   Flags [
+// CHECKSHARED-NEXT:     SHF_ALLOC
+// CHECKSHARED-NEXT:     SHF_WRITE
+// CHECKSHARED-NEXT:   ]
+// CHECKSHARED-NEXT:   Address: 0x3000
+// CHECKSHARED-NEXT:   Offset: 0x3000
+// CHECKSHARED-NEXT:   Size: 20
+// CHECKSHARED-NEXT:   Link: 0
+// CHECKSHARED-NEXT:   Info: 0
+// CHECKSHARED-NEXT:   AddressAlignment: 4
+// CHECKSHARED-NEXT:   EntrySize: 0
+// CHECKSHARED-NEXT:   }
+
+// 0x3000 + got.plt.reserved(12) = 0x300C
+// 0x3000 + got.plt.reserved(12) + 4 = 0x3010
+// CHECKSHARED:        Relocations [
+// CHECKSHARED-NEXT:     Section ({{.*}}) .rel.plt {
+// CHECKSHARED-NEXT:       0x300C R_386_JUMP_SLOT bar 0x0
+// CHECKSHARED-NEXT:       0x3010 R_386_JUMP_SLOT zed 0x0
+// CHECKSHARED-NEXT:     }
+// CHECKSHARED-NEXT:   ]
+
+// DISASMSHARED:       local:
+// DISASMSHARED-NEXT:  1000: {{.*}}
+// DISASMSHARED-NEXT:  1002: {{.*}}
+// DISASMSHARED:       _start:
+// 0x1013 + 5 - 24 = 0x1000
+// DISASMSHARED-NEXT:  1004: e9 27 00 00 00 jmp 39
+// DISASMSHARED-NEXT:  1009: e9 22 00 00 00 jmp 34
+// DISASMSHARED-NEXT:  100e: e9 2d 00 00 00 jmp 45
+// DISASMSHARED-NEXT:  1013: e9 e8 ff ff ff jmp -24
+// DISASMSHARED-NEXT:  Disassembly of section .plt:
+// DISASMSHARED-NEXT:  .plt:
+// DISASMSHARED-NEXT:  1020: ff b3 04 00 00 00  pushl 4(%ebx)
+// DISASMSHARED-NEXT:  1026: ff a3 08 00 00 00  jmpl *8(%ebx)
+// DISASMSHARED-NEXT:  102c: 90 nop
+// DISASMSHARED-NEXT:  102d: 90 nop
+// DISASMSHARED-NEXT:  102e: 90 nop
+// DISASMSHARED-NEXT:  102f: 90 nop
+// DISASMSHARED-NEXT:  1030: ff a3 0c 00 00 00  jmpl *12(%ebx)
+// DISASMSHARED-NEXT:  1036: 68 00 00 00 00     pushl $0
+// DISASMSHARED-NEXT:  103b: e9 e0 ff ff ff     jmp -32 <.plt>
+// DISASMSHARED-NEXT:  1040: ff a3 10 00 00 00  jmpl *16(%ebx)
+// DISASMSHARED-NEXT:  1046: 68 08 00 00 00     pushl $8
+// DISASMSHARED-NEXT:  104b: e9 d0 ff ff ff     jmp -48 <.plt>
+
+// DISASMPIE:      Disassembly of section .plt:
+// DISASMPIE-NEXT: .plt:
+// DISASMPIE-NEXT:   1020:     ff b3 04 00 00 00 pushl 4(%ebx)
+// DISASMPIE-NEXT:   1026:     ff a3 08 00 00 00 jmpl *8(%ebx)
+// DISASMPIE-NEXT:   102c:     90 nop
+// DISASMPIE-NEXT:   102d:     90 nop
+// DISASMPIE-NEXT:   102e:     90 nop
+// DISASMPIE-NEXT:   102f:     90 nop
+// DISASMPIE-NEXT:   1030:     ff a3 0c 30 00 00 jmpl *12300(%ebx)
+// DISASMPIE-NEXT:   1036:     68 00 00 00 00 pushl $0
+// DISASMPIE-NEXT:   103b:     e9 e0 ff ff ff jmp -32 <.plt>
+// DISASMPIE-NEXT:   1040:     ff a3 10 30 00 00 jmpl *12304(%ebx)
+// DISASMPIE-NEXT:   1046:     68 08 00 00 00 pushl $8
+// DISASMPIE-NEXT:   104b:     e9 d0 ff ff ff jmp -48 <.plt>
+
+local:
+.long 0
+
+.global _start
+_start:
+  jmp bar@PLT
+  jmp bar@PLT
+  jmp zed@PLT
+  jmp local@plt
diff --git a/test/ELF/plt.s b/test/ELF/plt.s
new file mode 100644 (file)
index 0000000..60268a6
--- /dev/null
@@ -0,0 +1,119 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t.o %t2.so -o %t
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck --check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM2 %s
+
+// REQUIRES: x86
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1020
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 64
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x3018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:     0x3020 R_X86_64_JUMP_SLOT zed 0x0
+// CHECK-NEXT:     0x3028 R_X86_64_JUMP_SLOT _start 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK2:      Name: .plt
+// CHECK2-NEXT: Type: SHT_PROGBITS
+// CHECK2-NEXT: Flags [
+// CHECK2-NEXT:   SHF_ALLOC
+// CHECK2-NEXT:   SHF_EXECINSTR
+// CHECK2-NEXT: ]
+// CHECK2-NEXT: Address: 0x11020
+// CHECK2-NEXT: Offset:
+// CHECK2-NEXT: Size: 48
+// CHECK2-NEXT: Link: 0
+// CHECK2-NEXT: Info: 0
+// CHECK2-NEXT: AddressAlignment: 16
+
+// CHECK2:      Relocations [
+// CHECK2-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK2-NEXT:     0x13018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK2-NEXT:     0x13020 R_X86_64_JUMP_SLOT zed 0x0
+// CHECK2-NEXT:   }
+// CHECK2-NEXT: ]
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+
+// 0x1030 - (0x1000 + 5) = 43
+// 0x1030 - (0x1005 + 5) = 38
+// 0x1040 - (0x100a + 5) = 49
+// 0x1048 - (0x100a + 5) = 60
+
+// DISASM:      _start:
+// DISASM-NEXT:   1000:  e9 {{.*}}       jmp  43
+// DISASM-NEXT:   1005:  e9 {{.*}}       jmp  38
+// DISASM-NEXT:   100a:  e9 {{.*}}       jmp  49
+// DISASM-NEXT:   100f:  e9 {{.*}}       jmp  60
+
+// 0x3018 - 0x1036  = 8162
+// 0x3020 - 0x1046  = 4234
+// 0x3028 - 0x1056  = 4226
+
+// DISASM:      Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   1020:  ff 35 e2 1f 00 00  pushq 8162(%rip)
+// DISASM-NEXT:   1026:  ff 25 e4 1f 00 00  jmpq *8164(%rip)
+// DISASM-NEXT:   102c:  0f 1f 40 00        nopl (%rax)
+// DISASM-NEXT:   1030:  ff 25 e2 1f 00 00  jmpq *8162(%rip)
+// DISASM-NEXT:   1036:  68 00 00 00 00     pushq $0
+// DISASM-NEXT:   103b:  e9 e0 ff ff ff     jmp -32 <.plt>
+// DISASM-NEXT:   1040:  ff 25 da 1f 00 00  jmpq *8154(%rip)
+// DISASM-NEXT:   1046:  68 01 00 00 00     pushq $1
+// DISASM-NEXT:   104b:  e9 d0 ff ff ff     jmp -48 <.plt>
+// DISASM-NEXT:   1050:  ff 25 d2 1f 00 00  jmpq *8146(%rip)
+// DISASM-NEXT:   1056:  68 02 00 00 00     pushq $2
+// DISASM-NEXT:   105b:  e9 c0 ff ff ff     jmp -64 <.plt>
+
+// 0x11030 - (0x11000 + 1) - 4 = 43
+// 0x11030 - (0x11005 + 1) - 4 = 38
+// 0x11040 - (0x1100a + 1) - 4 = 49
+// 0x11000 - (0x1100f + 1) - 4 = -20
+
+// DISASM2:      _start:
+// DISASM2-NEXT:   11000:  e9 {{.*}}     jmp  43
+// DISASM2-NEXT:   11005:  e9 {{.*}}     jmp  38
+// DISASM2-NEXT:   1100a:  e9 {{.*}}     jmp  49
+// DISASM2-NEXT:   1100f:  e9 {{.*}}     jmp  -20
+
+// 0x13018 - 0x11036  = 4242
+// 0x13020 - 0x11046  = 4234
+
+// DISASM2:      Disassembly of section .plt:
+// DISASM2-NEXT: .plt:
+// DISASM2-NEXT:  11020:  ff 35 e2 1f 00 00   pushq 8162(%rip)
+// DISASM2-NEXT:  11026:  ff 25 e4 1f 00 00   jmpq *8164(%rip)
+// DISASM2-NEXT:  1102c:  0f 1f 40 00         nopl  (%rax)
+// DISASM2-NEXT:  11030:  ff 25 e2 1f 00 00   jmpq *8162(%rip)
+// DISASM2-NEXT:  11036:  68 00 00 00 00      pushq $0
+// DISASM2-NEXT:  1103b:  e9 e0 ff ff ff      jmp -32 <.plt>
+// DISASM2-NEXT:  11040:  ff 25 da 1f 00 00   jmpq *8154(%rip)
+// DISASM2-NEXT:  11046:  68 01 00 00 00      pushq $1
+// DISASM2-NEXT:  1104b:  e9 d0 ff ff ff      jmp -48 <.plt>
+// DISASM2-NOT:   110C0
+
+.global _start
+_start:
+  jmp bar@PLT
+  jmp bar@PLT
+  jmp zed@PLT
+  jmp _start@plt
diff --git a/test/ELF/ppc-relocs.s b/test/ELF/ppc-relocs.s
new file mode 100644 (file)
index 0000000..a70cac1
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+.section .R_PPC_ADDR16_HA,"ax",@progbits
+.globl _start
+_start:
+  lis 4, msg@ha
+msg:
+  .string "foo"
+  len = . - msg
+
+# CHECK: Disassembly of section .R_PPC_ADDR16_HA:
+# CHECK: _start:
+# CHECK:    11000:       3c 80 00 01     lis 4, 1
+# CHECK: msg:
+# CHECK:    11004:       66 6f 6f 00     oris 15, 19, 28416
+
+.section .R_PPC_ADDR16_LO,"ax",@progbits
+  addi 4, 4, msg@l
+mystr:
+  .asciz "blah"
+  len = . - mystr
+
+# CHECK: Disassembly of section .R_PPC_ADDR16_LO:
+# CHECK: .R_PPC_ADDR16_LO:
+# CHECK:    11008:       38 84 10 04     addi 4, 4, 4100
+# CHECK: mystr:
+# CHECK:    1100c:       62 6c 61 68     ori 12, 19, 24936
diff --git a/test/ELF/ppc64-addr16-error.s b/test/ELF/ppc64-addr16-error.s
new file mode 100644 (file)
index 0000000..2bc8ef2
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2
+// RUN: not ld.lld -shared %t %t2 -o %t3 2>&1 | FileCheck %s
+// REQUIRES: ppc
+
+.short sym+65539
+
+// CHECK: relocation R_PPC64_ADDR16 out of range
diff --git a/test/ELF/ppc64-rel-calls.s b/test/ELF/ppc64-rel-calls.s
new file mode 100644 (file)
index 0000000..f3b309f
--- /dev/null
@@ -0,0 +1,42 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# CHECK: Disassembly of section .text:
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+  li      0,1
+  li      3,42
+  sc
+
+# CHECK: 10010000:       38 00 00 01     li 0, 1
+# CHECK: 10010004:       38 60 00 2a     li 3, 42
+# CHECK: 10010008:       44 00 00 02     sc
+
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC.@tocbase,0
+
+.text
+.Lbar:
+  bl _start
+  nop
+  bl .Lfoo
+  nop
+  blr
+
+# FIXME: The printing here is misleading, the branch offset here is negative.
+# CHECK: 1001000c:       4b ff ff f5     bl .+67108852
+# CHECK: 10010010:       60 00 00 00     nop
+# CHECK: 10010014:       4b ff ff ed     bl .+67108844
+# CHECK: 10010018:       60 00 00 00     nop
+# CHECK: 1001001c:       4e 80 00 20     blr
+
diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s
new file mode 100644 (file)
index 0000000..28902ae
--- /dev/null
@@ -0,0 +1,130 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+       li      0,1
+       li      3,42
+       sc
+
+.section        ".toc","aw"
+.L1:
+.quad           22, 37, 89, 47
+
+.section .R_PPC64_TOC16_LO_DS,"ax",@progbits
+.globl .FR_PPC64_TOC16_LO_DS
+.FR_PPC64_TOC16_LO_DS:
+  ld 1, .L1@toc@l(2)
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_LO_DS:
+# CHECK: .FR_PPC64_TOC16_LO_DS:
+# CHECK: 1001000c:       e8 22 80 00     ld 1, -32768(2)
+
+.section .R_PPC64_TOC16_LO,"ax",@progbits
+.globl .FR_PPC64_TOC16_LO
+.FR_PPC64_TOC16_LO:
+  addi  1, 2, .L1@toc@l
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_LO:
+# CHECK: .FR_PPC64_TOC16_LO:
+# CHECK: 10010010: 38 22 80 00 addi 1, 2, -32768
+
+.section .R_PPC64_TOC16_HI,"ax",@progbits
+.globl .FR_PPC64_TOC16_HI
+.FR_PPC64_TOC16_HI:
+  addis 1, 2, .L1@toc@h
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_HI:
+# CHECK: .FR_PPC64_TOC16_HI:
+# CHECK: 10010014: 3c 22 ff ff addis 1, 2, -1
+
+.section .R_PPC64_TOC16_HA,"ax",@progbits
+.globl .FR_PPC64_TOC16_HA
+.FR_PPC64_TOC16_HA:
+  addis 1, 2, .L1@toc@ha
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_HA:
+# CHECK: .FR_PPC64_TOC16_HA:
+# CHECK: 10010018: 3c 22 00 00 addis 1, 2, 0
+
+.section .R_PPC64_REL24,"ax",@progbits
+.globl .FR_PPC64_REL24
+.FR_PPC64_REL24:
+  b .Lfoox
+.section .R_PPC64_REL24_2,"ax",@progbits
+.Lfoox:
+
+# CHECK: Disassembly of section .R_PPC64_REL24:
+# CHECK: .FR_PPC64_REL24:
+# CHECK: 1001001c: 48 00 00 04 b .+4
+
+.section .R_PPC64_ADDR16_LO,"ax",@progbits
+.globl .FR_PPC64_ADDR16_LO
+.FR_PPC64_ADDR16_LO:
+  li 1, .Lfoo@l
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_LO:
+# CHECK: .FR_PPC64_ADDR16_LO:
+# CHECK: 10010020: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HI,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HI
+.FR_PPC64_ADDR16_HI:
+  li 1, .Lfoo@h
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HI:
+# CHECK: .FR_PPC64_ADDR16_HI:
+# CHECK: 10010024: 38 20 10 01 li 1, 4097
+
+.section .R_PPC64_ADDR16_HA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HA
+.FR_PPC64_ADDR16_HA:
+  li 1, .Lfoo@ha
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HA:
+# CHECK: .FR_PPC64_ADDR16_HA:
+# CHECK: 10010028: 38 20 10 01 li 1, 4097
+
+.section .R_PPC64_ADDR16_HIGHER,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHER
+.FR_PPC64_ADDR16_HIGHER:
+  li 1, .Lfoo@higher
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER:
+# CHECK: .FR_PPC64_ADDR16_HIGHER:
+# CHECK: 1001002c: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHERA
+.FR_PPC64_ADDR16_HIGHERA:
+  li 1, .Lfoo@highera
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA:
+# CHECK: .FR_PPC64_ADDR16_HIGHERA:
+# CHECK: 10010030: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHEST
+.FR_PPC64_ADDR16_HIGHEST:
+  li 1, .Lfoo@highest
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST:
+# CHECK: .FR_PPC64_ADDR16_HIGHEST:
+# CHECK: 10010034: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHESTA
+.FR_PPC64_ADDR16_HIGHESTA:
+  li 1, .Lfoo@highesta
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA:
+# CHECK: .FR_PPC64_ADDR16_HIGHESTA:
+# CHECK: 10010038: 38 20 00 00 li 1, 0
+
diff --git a/test/ELF/ppc64-shared-rel-toc.s b/test/ELF/ppc64-shared-rel-toc.s
new file mode 100644 (file)
index 0000000..f5cd459
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+// REQUIRES: ppc
+
+// When we create the TOC reference in the shared library, make sure that the
+// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset.
+
+        .globl  foo
+        .align  2
+        .type   foo,@function
+        .section        .opd,"aw",@progbits
+foo:                                    # @foo
+        .align  3
+        .quad   .Lfunc_begin0
+        .quad   .TOC.@tocbase
+        .quad   0
+        .text
+.Lfunc_begin0:
+        blr
+
+// CHECK: 0x30000 R_PPC64_RELATIVE - 0x10000
+// CHECK: 0x30008 R_PPC64_RELATIVE - 0x8000
+
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x30000
+
diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s
new file mode 100644 (file)
index 0000000..dbfeaec
--- /dev/null
@@ -0,0 +1,62 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK: Disassembly of section .text:
+
+.global _start
+_start:
+  bl bar
+  nop
+
+// CHECK: _start:
+// CHECK: 10010000:       48 00 00 21     bl .+32
+// CHECK-NOT: 10010004:       60 00 00 00     nop
+// CHECK: 10010004:       e8 41 00 28     ld 2, 40(1)
+
+.global noret
+noret:
+  bl bar
+  li 5, 7
+
+// CHECK: noret:
+// CHECK: 10010008: 48 00 00 19 bl .+24
+// CHECK: 1001000c: 38 a0 00 07 li 5, 7
+
+.global noretend
+noretend:
+  bl bar
+
+// CHECK: noretend:
+// CHECK: 10010010: 48 00 00 11 bl .+16
+
+.global noretb
+noretb:
+  b bar
+
+// CHECK: noretb:
+// CHECK: 10010014: 48 00 00 0c b .+12
+
+// This should come last to check the end-of-buffer condition.
+.global last
+last:
+  bl bar
+  nop
+
+// CHECK: last:
+// CHECK: 10010018: 48 00 00 09 bl .+8
+// CHECK: 1001001c: e8 41 00 28 ld 2, 40(1)
+
+// CHECK: Disassembly of section .plt:
+// CHECK: .plt:
+// CHECK: 10010020:       f8 41 00 28     std 2, 40(1)
+// CHECK: 10010024:       3d 62 10 03     addis 11, 2, 4099
+// CHECK: 10010028:       e9 8b 80 18     ld 12, -32744(11)
+// CHECK: 1001002c:       e9 6c 00 00     ld 11, 0(12)
+// CHECK: 10010030:       7d 69 03 a6     mtctr 11
+// CHECK: 10010034:       e8 4c 00 08     ld 2, 8(12)
+// CHECK: 10010038:       e9 6c 00 10     ld 11, 16(12)
+// CHECK: 1001003c:       4e 80 04 20     bctr
diff --git a/test/ELF/ppc64-weak-undef-call-shared.s b/test/ELF/ppc64-weak-undef-call-shared.s
new file mode 100644 (file)
index 0000000..2c27a27
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+# REQUIRES: ppc
+
+.section        ".toc","aw"
+.quad weakfunc
+// CHECK-NOT: R_PPC64_RELATIVE
+
+.text
+.Lfoo:
+  bl weakfunc
+// CHECK-NOT: R_PPC64_REL24
+
+.weak weakfunc
+
diff --git a/test/ELF/ppc64-weak-undef-call.s b/test/ELF/ppc64-weak-undef-call.s
new file mode 100644 (file)
index 0000000..55443cb
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# CHECK: Disassembly of section .text:
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+  bl weakfunc
+  nop
+  blr
+
+.weak weakfunc
+
+# It does not really matter how we fixup the bl, if at all, because it needs to
+# be unreachable. But, we should link successfully. We should not, however,
+# generate a .plt entry (this would be wasted space). For now, we do nothing
+# (leaving the zero relative offset present in the input).
+# CHECK: 10010000:       48 00 00 01     bl .+0
+# CHECK: 10010004:       60 00 00 00     nop
+# CHECK: 10010008:       4e 80 00 20     blr
diff --git a/test/ELF/pre_init_fini_array.s b/test/ELF/pre_init_fini_array.s
new file mode 100644 (file)
index 0000000..4ddcb69
--- /dev/null
@@ -0,0 +1,152 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2
+// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t %t2.so -o %t2
+// RUN: llvm-readobj -r -symbols -sections -dynamic-table %t2 | FileCheck %s
+// RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  call __preinit_array_start
+  call __preinit_array_end
+  call __init_array_start
+  call __init_array_end
+  call __fini_array_start
+  call __fini_array_end
+
+
+.section .init_array,"aw",@init_array
+  .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+        .quad 0
+        .byte 0
+
+.section .fini_array,"aw",@fini_array
+        .quad 0
+        .short 0
+
+// CHECK:      Name: .init_array
+// CHECK-NEXT: Type: SHT_INIT_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[INIT_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[INIT_SIZE:.*]]
+
+
+// CHECK:     Name: .preinit_array
+// CHECK-NEXT: Type: SHT_PREINIT_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT: Address: [[PREINIT_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[PREINIT_SIZE:.*]]
+
+
+// CHECK:      Name: .fini_array
+// CHECK-NEXT: Type: SHT_FINI_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[FINI_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[FINI_SIZE:.*]]
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
+
+// CHECK:        Name: __fini_array_end
+// CHECK-NEXT:   Value: 0x1201B
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .fini_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __fini_array_start
+// CHECK-NEXT:   Value: [[FINI_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .fini_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __init_array_end
+// CHECK-NEXT:   Value: 0x12008
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .init_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __init_array_start
+// CHECK-NEXT:   Value: [[INIT_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .init_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __preinit_array_end
+// CHECK-NEXT:   Value: 0x12011
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .preinit_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __preinit_array_start
+// CHECK-NEXT:   Value: [[PREINIT_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .preinit_array
+// CHECK-NEXT: }
+
+// CHECK: DynamicSection
+// CHECK: PREINIT_ARRAY        [[PREINIT_ADDR]]
+// CHECK: PREINIT_ARRAYSZ      [[PREINIT_SIZE]] (bytes)
+// CHECK: INIT_ARRAY           [[INIT_ADDR]]
+// CHECK: INIT_ARRAYSZ         [[INIT_SIZE]] (bytes)
+// CHECK: FINI_ARRAY           [[FINI_ADDR]]
+// CHECK: FINI_ARRAYSZ         [[FINI_SIZE]] (bytes)
+
+
+// 0x12008 - (0x11000 + 5) = 4099
+// 0x12011 - (0x11005 + 5) = 4103
+// 0x12000 - (0x1100a + 5) = 4081
+// 0x12008 - (0x1100f + 5) = 4084
+// 0x12011 - (0x11014 + 5) = 4088
+// 0x1201B - (0x11019 + 5) = 4093
+// DISASM:      _start:
+// DISASM-NEXT:   11000:  e8 {{.*}}  callq  4099
+// DISASM-NEXT:   11005:  e8 {{.*}}  callq  4103
+// DISASM-NEXT:   1100a:  e8 {{.*}}  callq  4081
+// DISASM-NEXT:   1100f:  e8 {{.*}}  callq  4084
+// DISASM-NEXT:   11014:  e8 {{.*}}  callq  4088
+// DISASM-NEXT:   11019:  e8 {{.*}}  callq  4093
diff --git a/test/ELF/pre_init_fini_array_missing.s b/test/ELF/pre_init_fini_array_missing.s
new file mode 100644 (file)
index 0000000..02b8324
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  call __preinit_array_start
+  call __preinit_array_end
+  call __init_array_start
+  call __init_array_end
+  call __fini_array_start
+  call __fini_array_end
+
+// With no .init_array section the symbols resolve to 0
+// 0 - (0x11000 + 5) = -69637
+// 0 - (0x11005 + 5) = -69642
+// 0 - (0x1100a + 5) = -69647
+// 0 - (0x1100f + 5) = -69652
+// 0 - (0x11014 + 5) = -69657
+// 0 - (0x11019 + 5) = -69662
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT:  _start:
+// CHECK-NEXT:   11000:    e8 fb ef fe ff     callq    -69637
+// CHECK-NEXT:   11005:    e8 f6 ef fe ff     callq    -69642
+// CHECK-NEXT:   1100a:    e8 f1 ef fe ff     callq    -69647
+// CHECK-NEXT:   1100f:    e8 ec ef fe ff     callq    -69652
+// CHECK-NEXT:   11014:    e8 e7 ef fe ff     callq    -69657
+// CHECK-NEXT:   11019:    e8 e2 ef fe ff     callq    -69662
diff --git a/test/ELF/progname.s b/test/ELF/progname.s
new file mode 100644 (file)
index 0000000..10cbf17
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: echo .global __progname > %t2.s
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %t2.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -o %t %t.o %t2.so
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+
+// Inputs/progname-ver.so consists of the assembly file
+//
+// .global bar
+// bar:
+// .quad __progname
+//
+// linked into a library  with the version script
+//
+// VER_1 {
+//  global:
+//  bar;
+// };
+//
+// We should create it with lld itself once we it supports that.
+
+// RUN: ld.lld -o %t %t.o %p/Inputs/progname-ver.so
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// CHECK:      Name:     __progname@
+// CHECK-NEXT: Value:    0x11000
+// CHECK-NEXT: Size:     0
+// CHECK-NEXT: Binding:  Global (0x1)
+// CHECK-NEXT: Type:     None (0x0)
+// CHECK-NEXT: Other:    0
+// CHECK-NEXT: Section:  .text
+// CHECK-NEXT: }
+
+.global _start, __progname
+_start:
+__progname:
+  nop
diff --git a/test/ELF/program-header-layout.s b/test/ELF/program-header-layout.s
new file mode 100644 (file)
index 0000000..8e32227
--- /dev/null
@@ -0,0 +1,98 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# Check that different output sections with the same flags are merged into a
+# single Read/Write PT_LOAD.
+
+.section .r,"a"
+.globl _start
+_start:
+.quad 0
+
+.section .a,"aw"
+.quad 1
+
+.section .b,"aw"
+.quad 2
+
+# CHECK:        Name: .r
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset: 0x158
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10040
+# CHECK-NEXT:     PhysicalAddress: 0x10040
+# CHECK-NEXT:     FileSize: 280
+# CHECK-NEXT:     MemSize: 280
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 352
+# CHECK-NEXT:     MemSize: 352
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/protected-shared.s b/test/ELF/protected-shared.s
new file mode 100644 (file)
index 0000000..e69b108
--- /dev/null
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -t --dyn-symbols %t | FileCheck %s
+
+        .global  _start
+_start:
+
+        .global bar
+bar:
+
+        .data
+        .quad foo
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/rel-offset.s b/test/ELF/rel-offset.s
new file mode 100644 (file)
index 0000000..6f35bce
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -r  %t | FileCheck %s
+
+        .section        .data.foo,"aw",@progbits
+        .quad   foo
+
+        .section        .data.zed,"aw",@progbits
+        .quad   foo
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x2000 R_X86_64_64 foo 0x0
+// CHECK-NEXT:   0x2008 R_X86_64_64 foo 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/relative-dynamic-reloc-pie.s b/test/ELF/relative-dynamic-reloc-pie.s
new file mode 100644 (file)
index 0000000..d9967af
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t.pie
+# RUN: llvm-readobj -r -dyn-symbols %t.pie | FileCheck %s
+
+## Test that we create R_X86_64_RELATIVE relocations with -pie.
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x3000 R_X86_64_RELATIVE - 0x3000
+# CHECK-NEXT:     0x3008 R_X86_64_RELATIVE - 0x3008
+# CHECK-NEXT:     0x3010 R_X86_64_RELATIVE - 0x3009
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.globl _start
+_start:
+nop
+
+ .data
+foo:
+ .quad foo
+
+.hidden bar
+.global bar
+bar:
+ .quad bar
+ .quad bar + 1
diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s
new file mode 100644 (file)
index 0000000..81a7a70
--- /dev/null
@@ -0,0 +1,67 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+// REQUIRES: ppc
+
+// Test that we create R_PPC64_RELATIVE relocations but don't put any
+// symbols in the dynamic symbol table.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x[[FOO_ADDR:.*]] R_PPC64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x[[BAR_ADDR:.*]] R_PPC64_RELATIVE - 0x[[BAR_ADDR]]
+// CHECK-NEXT:     0x20010 R_PPC64_RELATIVE - 0x20009
+// CHECK-NEXT:     0x{{.*}} R_PPC64_RELATIVE - 0x[[ZED_ADDR:.*]]
+// CHECK-NEXT:     0x{{.*}} R_PPC64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x20028 R_PPC64_ADDR64 external 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x[[FOO_ADDR]]
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x[[BAR_ADDR]]
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x[[ZED_ADDR]]
+// CHECK:      ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @ (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: external@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .quad foo
+
+        .hidden bar
+        .global bar
+bar:
+        .quad bar
+        .quad bar + 1
+
+        .hidden zed
+        .comm zed,1
+        .quad zed
+
+        .section abc,"aw"
+        .quad foo
+
+        .quad external
diff --git a/test/ELF/relative-dynamic-reloc.s b/test/ELF/relative-dynamic-reloc.s
new file mode 100644 (file)
index 0000000..aac5566
--- /dev/null
@@ -0,0 +1,70 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+
+// Test that we create R_X86_64_RELATIVE relocations but don't put any
+// symbols in the dynamic symbol table.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x[[FOO_ADDR:.*]] R_X86_64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x[[BAR_ADDR:.*]] R_X86_64_RELATIVE - 0x[[BAR_ADDR]]
+// CHECK-NEXT:     0x2010 R_X86_64_RELATIVE - 0x2009
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x[[ZED_ADDR:.*]]
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x2028 R_X86_64_64 external 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x[[FOO_ADDR]]
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x[[BAR_ADDR]]
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x[[ZED_ADDR]]
+// CHECK:      ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @ (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: external@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .quad foo
+
+        .hidden bar
+        .global bar
+bar:
+        .quad bar
+        .quad bar + 1
+
+        .hidden zed
+        .comm zed,1
+        .quad zed
+
+        .section abc,"aw"
+        .quad foo
+
+        .quad external
+
+// This doesn't need a relocation.
+        callq localfunc@PLT
+localfunc:
diff --git a/test/ELF/relocatable-bss.s b/test/ELF/relocatable-bss.s
new file mode 100644 (file)
index 0000000..0411bf3
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+## We check here that .bss does not occupy the space in file.
+## If it would, the SectionHeaderOffset would have offset about 5 megabytes.
+# CHECK:       ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: Relocatable
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version:
+# CHECK-NEXT:  Entry:
+# CHECK-NEXT:   ProgramHeaderOffset:
+# CHECK-NEXT:   SectionHeaderOffset: 0xA8
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize:
+# CHECK-NEXT:  ProgramHeaderEntrySize:
+# CHECK-NEXT:  ProgramHeaderCount:
+# CHECK-NEXT:  SectionHeaderEntrySize:
+# CHECK-NEXT:  SectionHeaderCount:
+# CHECK-NEXT:  StringTableSectionIndex:
+# CHECK-NEXT:  }
+
+.text
+.globl _start
+_start:
+ nop
+
+.bss
+ .space 5242880
diff --git a/test/ELF/relocatable-ehframe.s b/test/ELF/relocatable-ehframe.s
new file mode 100644 (file)
index 0000000..d484020
--- /dev/null
@@ -0,0 +1,51 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable-ehframe.s -o %t2.o
+# RUN: ld.lld -r %t1.o %t2.o -o %t
+# RUN: llvm-readobj -r -s -section-data %t | FileCheck %s
+
+# CHECK:      Name: .strtab
+# CHECK-NEXT: Type: SHT_STRTAB
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset
+# CHECK-NEXT: Size: 9
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT:   0000: 00005F73 74617274 00                 |.._start.|
+# CHECK-NEXT: )
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section {{.*}} .rela.eh_frame {
+# CHECK-NEXT:     0x20 R_X86_64_PC32 foo 0x0
+# CHECK-NEXT:     0x34 R_X86_64_PC32 bar 0x0
+# CHECK-NEXT:     0x48 R_X86_64_PC32 dah 0x0
+# CHECK-NEXT:     0x78 R_X86_64_PC32 foo1 0x0
+# CHECK-NEXT:     0x8C R_X86_64_PC32 bar1 0x0
+# CHECK-NEXT:     0xA0 R_X86_64_PC32 dah1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section foo,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.text
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/relocatable-reloc.s b/test/ELF/relocatable-reloc.s
new file mode 100644 (file)
index 0000000..c576073
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj %s -o %t.o -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o %t.o -r -o %t2.o
+// RUN: llvm-readobj -r %t2.o | FileCheck %s
+
+.weak foo
+foo:
+.quad foo
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.text {
+// CHECK-NEXT:     0x0 R_X86_64_64 foo 0x0
+// CHECK-NEXT:     0x8 R_X86_64_64 foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/relocatable-symbols.s b/test/ELF/relocatable-symbols.s
new file mode 100644 (file)
index 0000000..75ed17e
--- /dev/null
@@ -0,0 +1,183 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -r %t -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+# RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s
+
+# DISASM:      _start:
+# DISASM-NEXT:   0: {{.*}} callq 0
+# DISASM-NEXT:   5: {{.*}} callq 0
+# DISASM-NEXT:   a: {{.*}} callq 0
+# DISASM-NEXT:   f: {{.*}} callq 0
+# DISASM-NEXT:  14: {{.*}} callq 0
+# DISASM-NEXT:  19: {{.*}} callq 0
+# DISASM-NEXT:  1e: {{.*}} callq 0
+# DISASM-NEXT:  23: {{.*}} callq 0
+# DISASM-NEXT:  28: {{.*}} callq 0
+# DISASM-NEXT:  2d: {{.*}} callq 0
+# DISASM-NEXT:  32: {{.*}} callq 0
+# DISASM-NEXT:  37: {{.*}} callq 0
+# DISASM-NEXT: Disassembly of section foo:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:  0: 90 nop
+# DISASM-NEXT:  1: 90 nop
+# DISASM-NEXT:  2: 90 nop
+# DISASM-NEXT: Disassembly of section bar:
+# DISASM-NEXT: bar:
+# DISASM-NEXT:  0: 90 nop
+# DISASM-NEXT:  1: 90 nop
+# DISASM-NEXT:  2: 90 nop
+
+# SYMBOL:      Relocations [
+# SYMBOL-NEXT:  Section ({{.*}}) .rela.text {
+# SYMBOL-NEXT:     0x1 R_X86_64_PC32 __start_foo 0x0
+# SYMBOL-NEXT:     0x6 R_X86_64_PC32 __stop_foo 0x0
+# SYMBOL-NEXT:     0xB R_X86_64_PC32 __start_bar 0x0
+# SYMBOL-NEXT:     0x10 R_X86_64_PC32 __stop_bar 0x0
+# SYMBOL-NEXT:     0x15 R_X86_64_PC32 __start_doo 0x0
+# SYMBOL-NEXT:     0x1A R_X86_64_PC32 __stop_doo 0x0
+# SYMBOL-NEXT:     0x1F R_X86_64_PC32 __preinit_array_start 0x0
+# SYMBOL-NEXT:     0x24 R_X86_64_PC32 __preinit_array_end 0x0
+# SYMBOL-NEXT:     0x29 R_X86_64_PC32 __init_array_start 0x0
+# SYMBOL-NEXT:     0x2E R_X86_64_PC32 __init_array_end 0x0
+# SYMBOL-NEXT:     0x33 R_X86_64_PC32 __fini_array_start 0x0
+# SYMBOL-NEXT:     0x38 R_X86_64_PC32 __fini_array_end 0x0
+# SYMBOL-NEXT:   }
+# SYMBOL-NEXT: ]
+# SYMBOL:      Symbol {
+# SYMBOL:        Name: __fini_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __fini_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __init_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __init_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __preinit_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __preinit_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_bar
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_doo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_foo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_bar
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_doo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_foo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+
+.global _start
+.text
+_start:
+ call __start_foo
+ call __stop_foo
+
+ call __start_bar
+ call __stop_bar
+
+ call __start_doo
+ call __stop_doo
+
+ call __preinit_array_start
+ call __preinit_array_end
+ call __init_array_start
+ call __init_array_end
+ call __fini_array_start
+ call __fini_array_end
+
+.section foo,"ax"
+ nop
+ nop
+ nop
+
+.section bar,"ax"
+ nop
+ nop
+ nop
diff --git a/test/ELF/relocatable.s b/test/ELF/relocatable.s
new file mode 100644 (file)
index 0000000..032cb63
--- /dev/null
@@ -0,0 +1,120 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o
+# RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
+
+## Test --relocatable alias
+# RUN: ld.lld --relocatable %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
+
+## Verify that we can use our relocation output as input to produce executable
+# RUN: ld.lld -e main %t -o %texec
+# RUN: llvm-readobj -file-headers %texec | FileCheck -check-prefix=CHECKEXE %s
+
+# CHECK:       ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: Relocatable
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version: 1
+# CHECK-NEXT:  Entry: 0x0
+# CHECK-NEXT:  ProgramHeaderOffset: 0x0
+# CHECK-NEXT:  SectionHeaderOffset: 0x2C0
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize: 64
+# CHECK-NEXT:  ProgramHeaderEntrySize: 0
+# CHECK-NEXT:  ProgramHeaderCount: 0
+# CHECK-NEXT:  SectionHeaderEntrySize: 64
+# CHECK-NEXT:  SectionHeaderCount: 7
+# CHECK-NEXT:  StringTableSectionIndex: 5
+# CHECK-NEXT:  }
+
+# CHECK:       Relocations [
+# CHECK-NEXT:  Section (3) .rela.text {
+# CHECK-NEXT:    0x3 R_X86_64_32S x 0x0
+# CHECK-NEXT:    0xE R_X86_64_32S y 0x0
+# CHECK-NEXT:    0x23 R_X86_64_32S xx 0x0
+# CHECK-NEXT:    0x2E R_X86_64_32S yy 0x0
+# CHECK-NEXT:    0x43 R_X86_64_32S xxx 0x0
+# CHECK-NEXT:    0x4E R_X86_64_32S yyy 0x0
+# CHECK-NEXT:  }
+
+# CHECKTEXT:      Disassembly of section .text:
+# CHECKTEXT-NEXT: main:
+# CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0
+# CHECKTEXT-NEXT: b: c7 04 25 00 00 00 00 07 00 00 00 movl $7, 0
+# CHECKTEXT:      foo:
+# CHECKTEXT-NEXT: 20: c7 04 25 00 00 00 00 01 00 00 00 movl $1, 0
+# CHECKTEXT-NEXT: 2b: c7 04 25 00 00 00 00 02 00 00 00 movl $2, 0
+# CHECKTEXT:      bar:
+# CHECKTEXT-NEXT: 40: c7 04 25 00 00 00 00 08 00 00 00 movl $8, 0
+# CHECKTEXT-NEXT: 4b: c7 04 25 00 00 00 00 09 00 00 00 movl $9, 0
+
+# CHECKEXE:       Format: ELF64-x86-64
+# CHECKEXE-NEXT:  Arch: x86_64
+# CHECKEXE-NEXT:  AddressSize: 64bit
+# CHECKEXE-NEXT:  LoadName:
+# CHECKEXE-NEXT:  ElfHeader {
+# CHECKEXE-NEXT:    Ident {
+# CHECKEXE-NEXT:      Magic: (7F 45 4C 46)
+# CHECKEXE-NEXT:      Class: 64-bit
+# CHECKEXE-NEXT:      DataEncoding: LittleEndian
+# CHECKEXE-NEXT:      FileVersion: 1
+# CHECKEXE-NEXT:      OS/ABI: SystemV (0x0)
+# CHECKEXE-NEXT:      ABIVersion: 0
+# CHECKEXE-NEXT:      Unused: (00 00 00 00 00 00 00)
+# CHECKEXE-NEXT:    }
+# CHECKEXE-NEXT:    Type: Executable
+# CHECKEXE-NEXT:    Machine: EM_X86_64
+# CHECKEXE-NEXT:    Version: 1
+# CHECKEXE-NEXT:    Entry: 0x11000
+# CHECKEXE-NEXT:    ProgramHeaderOffset: 0x40
+# CHECKEXE-NEXT:    SectionHeaderOffset: 0x11E8
+# CHECKEXE-NEXT:    Flags [
+# CHECKEXE-NEXT:    ]
+# CHECKEXE-NEXT:    HeaderSize: 64
+# CHECKEXE-NEXT:    ProgramHeaderEntrySize: 56
+# CHECKEXE-NEXT:    ProgramHeaderCount: 5
+# CHECKEXE-NEXT:    SectionHeaderEntrySize: 64
+# CHECKEXE-NEXT:    SectionHeaderCount: 6
+# CHECKEXE-NEXT:    StringTableSectionIndex: 4
+# CHECKEXE-NEXT:  }
+
+.text
+.type x,@object
+.bss
+.globl x
+.align 4
+x:
+.long 0
+.size x, 4
+.type y,@object
+.globl y
+.align 4
+y:
+.long 0
+.size y, 4
+
+.text
+.globl main
+.align 16, 0x90
+.type main,@function
+main:
+movl $5, x
+movl $7, y
+
+blah:
+goo:
+abs = 42
diff --git a/test/ELF/relocation-absolute.s b/test/ELF/relocation-absolute.s
new file mode 100644 (file)
index 0000000..20d54ec
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %tabs %t -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  movl $abs, %edx
+
+//CHECK:      start:
+//CHECK-NEXT: movl     $66, %edx
diff --git a/test/ELF/relocation-common.s b/test/ELF/relocation-common.s
new file mode 100644 (file)
index 0000000..d5d379a
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-objdump -t -d %tout | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  movl $1, sym1(%rip)
+
+.global sym1
+.comm sym1,4,4
+
+// CHECK: 11000: {{.*}} movl    $1, 4086(%rip)
+// CHECK: 0000000000012000 g       .bss            00000004 sym1
diff --git a/test/ELF/relocation-copy-alias.s b/test/ELF/relocation-copy-alias.s
new file mode 100644 (file)
index 0000000..15712e3
--- /dev/null
@@ -0,0 +1,67 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-alias.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj --dyn-symbols -r --expand-relocs %t3 | FileCheck %s
+
+.global _start
+_start:
+movl $5, a1
+movl $5, b1
+movl $5, b2
+
+// CHECK:      .rela.dyn {
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Type: R_X86_64_COPY
+// CHECK-NEXT:     Symbol: a1
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Type: R_X86_64_COPY
+// CHECK-NEXT:     Symbol: b1
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+// CHECK:      Name: a1
+// CHECK-NEXT: Value: [[A:.*]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global (0x1)
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss (0x7)
+
+// CHECK:      Name: b1
+// CHECK-NEXT: Value: [[B:.*]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: b2
+// CHECK-NEXT: Value: [[B]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: a2
+// CHECK-NEXT: Value: [[A]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: b3
+// CHECK-NEXT: Value: [[B]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
diff --git a/test/ELF/relocation-copy-align.s b/test/ELF/relocation-copy-align.s
new file mode 100644 (file)
index 0000000..07ae663
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-align.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+
+.global _start
+_start:
+movl $5, x
+
+// CHECK:    Name: .bss
+// CHECK-NEXT:    Type: SHT_NOBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address:
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize:
+
+// CHECK:      Relocation {
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Type: R_X86_64_COPY
+// CHECK-NEXT:   Symbol: x
+// CHECK-NEXT:   Addend: 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/relocation-copy-flags.s b/test/ELF/relocation-copy-flags.s
new file mode 100644 (file)
index 0000000..50b4b15
--- /dev/null
@@ -0,0 +1,73 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s -section-data -r %t.exe | FileCheck %s
+
+        .global _start
+_start:
+        .quad x
+
+        .section foo
+        .quad y
+
+        .section bar, "aw"
+        .quad z
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11000
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 10300100
+// CHECK-NEXT: )
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x13000
+// CHECK-NEXT: Offset: 0x3000
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x3008
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x13010 R_X86_64_COPY x 0x0
+// CHECK-NEXT:     0x13000 R_X86_64_64 z 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/relocation-copy-i686.s b/test/ELF/relocation-copy-i686.s
new file mode 100644 (file)
index 0000000..f9ee32e
--- /dev/null
@@ -0,0 +1,63 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld -e main %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+
+.text
+.globl main
+.align 16, 0x90
+.type main,@function
+main:
+movl $5, x
+movl $7, y
+movl $9, z
+
+// CHECK:      Name: .bss
+// CHECK-NEXT:  Type: SHT_NOBITS
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x13000
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:  Size: 24
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 16
+// CHECK-NEXT:  EntrySize: 0
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 77824 = 0x13000
+// 16 is alignment here
+// 77840 = 0x13000 + 16
+// 77844 = 0x13000 + 16 + 4
+// CODE: Disassembly of section .text:
+// CODE-NEXT: main:
+// CODE-NEXT: 11000: c7 05 00 30 01 00 05 00 00 00 movl $5, 77824
+// CODE-NEXT: 1100a: c7 05 10 30 01 00 07 00 00 00 movl $7, 77840
+// CODE-NEXT: 11014: c7 05 14 30 01 00 09 00 00 00 movl $9, 77844
diff --git a/test/ELF/relocation-copy.s b/test/ELF/relocation-copy.s
new file mode 100644 (file)
index 0000000..9d13241
--- /dev/null
@@ -0,0 +1,67 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+
+.text
+.global _start
+_start:
+movl $5, x
+movl $7, y
+movl $9, z
+movl $x, %edx
+movl $y, %edx
+movl $z, %edx
+
+// CHECK:      Name: .bss
+// CHECK-NEXT:  Type: SHT_NOBITS (0x8)
+// CHECK-NEXT:  Flags [ (0x3)
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x13000
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:  Size: 24
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 16
+// CHECK-NEXT:  EntrySize: 0
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 77824 = 0x13000
+// 16 is alignment here
+// 77840 = 0x13000 + 16
+// 77844 = 0x13000 + 16 + 4
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT: 11000: c7 04 25 00 30 01 00 05 00 00 00 movl $5, 77824
+// CODE-NEXT: 1100b: c7 04 25 10 30 01 00 07 00 00 00 movl $7, 77840
+// CODE-NEXT: 11016: c7 04 25 14 30 01 00 09 00 00 00 movl $9, 77844
+// CODE-NEXT: 11021: ba 00 30 01 00                   movl $77824, %edx
+// CODE-NEXT: 11026: ba 10 30 01 00                   movl $77840, %edx
+// CODE-NEXT: 1102b: ba 14 30 01 00                   movl $77844, %edx
diff --git a/test/ELF/relocation-i686.s b/test/ELF/relocation-i686.s
new file mode 100644 (file)
index 0000000..96d7606
--- /dev/null
@@ -0,0 +1,94 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t %t2.so -o %t2
+// RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=ADDR %s
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.section       .R_386_32,"ax",@progbits
+.global R_386_32
+R_386_32:
+  movl $R_386_32 + 1, %edx
+
+
+.section       .R_386_PC32,"ax",@progbits,unique,1
+.global R_386_PC32
+R_386_PC32:
+  call R_386_PC32_2
+
+.section       .R_386_PC32,"ax",@progbits,unique,2
+.zero 4
+R_386_PC32_2:
+  nop
+
+// CHECK: Disassembly of section .R_386_32:
+// CHECK-NEXT: R_386_32:
+// CHECK-NEXT:  11000: {{.*}} movl $69633, %edx
+
+// CHECK: Disassembly of section .R_386_PC32:
+// CHECK-NEXT: R_386_PC32:
+// CHECK-NEXT:   11005:  e8 04 00 00 00  calll 4
+
+// CHECK:      R_386_PC32_2:
+// CHECK-NEXT:   1100e:  90  nop
+
+// Create a .got
+movl bar@GOT, %eax
+
+// ADDR:      Name: .plt
+// ADDR-NEXT: Type: SHT_PROGBITS
+// ADDR-NEXT: Flags [
+// ADDR-NEXT:   SHF_ALLOC
+// ADDR-NEXT:   SHF_EXECINSTR
+// ADDR-NEXT: ]
+// ADDR-NEXT: Address: 0x11040
+// ADDR-NEXT: Offset: 0x1040
+// ADDR-NEXT: Size: 32
+
+// ADDR:      Name: .got
+// ADDR-NEXT: Type: SHT_PROGBITS
+// ADDR-NEXT: Flags [
+// ADDR-NEXT:   SHF_ALLOC
+// ADDR-NEXT:   SHF_WRITE
+// ADDR-NEXT: ]
+// ADDR-NEXT: Address: 0x12078
+
+.section .R_386_GOTPC,"ax",@progbits
+R_386_GOTPC:
+ movl $_GLOBAL_OFFSET_TABLE_, %eax
+
+// 0x12050 - 0x11014 = 4156
+
+// CHECK:      Disassembly of section .R_386_GOTPC:
+// CHECK-NEXT: R_386_GOTPC:
+// CHECK-NEXT:   11014:  {{.*}} movl  $4196, %eax
+
+.section .dynamic_reloc, "ax",@progbits
+ call bar
+// addr(.plt) + 16 - (0x11019 + 5) = 50
+// CHECK:      Disassembly of section .dynamic_reloc:
+// CHECK-NEXT: .dynamic_reloc:
+// CHECK-NEXT:   11019:  e8 32 00 00 00 calll 50
+
+.section .R_386_GOT32,"ax",@progbits
+.global R_386_GOT32
+R_386_GOT32:
+ movl bar@GOT, %eax
+ movl zed@GOT, %eax
+ movl bar+8@GOT, %eax
+ movl zed+4@GOT, %eax
+
+// 4294967288 = 0xFFFFFFF8 = got[0](0x12070) - .got(0x12070) - sizeof(.got)(8)
+// 4294967292 = 0xFFFFFFFC = got[1](0x12074) - .got(0x12070) - sizeof(.got)(8)
+// 0xFFFFFFF8 + 8 = 0
+// 0xFFFFFFFC + 4 = 0
+// CHECK:      Disassembly of section .R_386_GOT32:
+// CHECK-NEXT: R_386_GOT32:
+// CHECK-NEXT: 1101e: a1 f8 ff ff ff movl 4294967288, %eax
+// CHECK-NEXT: 11023: a1 fc ff ff ff movl 4294967292, %eax
+// CHECK-NEXT: 11028: a1 00 00 00 00 movl 0, %eax
+// CHECK-NEXT: 1102d: a1 00 00 00 00 movl 0, %eax
diff --git a/test/ELF/relocation-in-merge.s b/test/ELF/relocation-in-merge.s
new file mode 100644 (file)
index 0000000..9ce2e4f
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: relocations pointing to SHF_MERGE are not supported
+
+        .section       .foo,"aM",@progbits,4
+        .long bar
diff --git a/test/ELF/relocation-local.s b/test/ELF/relocation-local.s
new file mode 100644 (file)
index 0000000..26e89fc
--- /dev/null
@@ -0,0 +1,38 @@
+// Test that relocation of local symbols is working.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -s -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+
+.global _start
+_start:
+  call lulz
+
+.zero 4
+lulz:
+
+.section       .text2,"ax",@progbits
+R_X86_64_32:
+  movl $R_X86_64_32, %edx
+
+// FIXME: this would be far more self evident if llvm-objdump printed
+// constants in hex.
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: R_X86_64_32:
+// CHECK-NEXT:  11009: {{.*}} movl $69641, %edx
+
+.section .R_X86_64_32S,"ax",@progbits
+R_X86_64_32S:
+  movq lulz - 0x100000, %rdx
+
+// CHECK: Disassembly of section .R_X86_64_32S:
+// CHECK-NEXT: R_X86_64_32S:
+// CHECK-NEXT:  {{.*}}: {{.*}} movq -978935, %rdx
+
+.section .R_X86_64_64,"a",@progbits
+R_X86_64_64:
+ .quad R_X86_64_64
+
+// CHECK:      Contents of section .R_X86_64_64:
+// CHECK-NEXT:   10120 20010100 00000000
diff --git a/test/ELF/relocation-non-alloc.s b/test/ELF/relocation-non-alloc.s
new file mode 100644 (file)
index 0000000..43f6f5f
--- /dev/null
@@ -0,0 +1,60 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared
+// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck %s
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000 00000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00200000 00000000 00200000 00000000
+// CHECK-NEXT:   0010: 00200000 00000000 00200000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.}}) .rela.dyn {
+// CHECK-NEXT:     0x2000 R_X86_64_RELATIVE - 0x2000
+// CHECK-NEXT:     0x2008 R_X86_64_64 zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.data
+        .global zed
+zed:
+bar:
+        .quad bar
+        .quad zed
+
+        .section foo
+        .quad bar
+        .quad zed
+
+        .section foo
+        .quad bar
+        .quad zed
diff --git a/test/ELF/relocation-past-merge-end.s b/test/ELF/relocation-past-merge-end.s
new file mode 100644 (file)
index 0000000..993b071
--- /dev/null
@@ -0,0 +1,8 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+// CHECK: entry is past the end of the section
+
+        .data
+        .long .foo + 1
+        .section       .foo,"aM",@progbits,4
diff --git a/test/ELF/relocation-relative-absolute.s b/test/ELF/relocation-relative-absolute.s
new file mode 100644 (file)
index 0000000..5253191
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s
+
+.globl _start
+_start:
+
+# CHECK: relocation R_X86_64_PLT32 cannot refer to absolute symbol answer
+call answer@PLT
+
+.globl answer
+answer = 42
diff --git a/test/ELF/relocation-relative-synthetic.s b/test/ELF/relocation-relative-synthetic.s
new file mode 100644 (file)
index 0000000..f4d449b
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+call __init_array_start@PLT
diff --git a/test/ELF/relocation-relative-weak.s b/test/ELF/relocation-relative-weak.s
new file mode 100644 (file)
index 0000000..c525012
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+
+.globl w
+.weak w
+call w@PLT
diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s
new file mode 100644 (file)
index 0000000..e185094
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -o %t.so
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 380E0000 00000000
+//                     0x1000 - 0x1C8 = 0xE38
+// CHECK-NEXT: )
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
+
+bar:
+        .section foo,"a",@progbits
+        .quad bar - .
diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s
new file mode 100644 (file)
index 0000000..d6274e9
--- /dev/null
@@ -0,0 +1,78 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocation-size-shared.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOCSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// RELOCSHARED:       Relocations [
+// RELOCSHARED-NEXT:  Section ({{.*}}) .rela.dyn {
+// RELOCSHARED-NEXT:    0x13018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x13020 R_X86_64_SIZE64 fooshared 0x0
+// RELOCSHARED-NEXT:    0x13028 R_X86_64_SIZE64 fooshared 0x1
+// RELOCSHARED-NEXT:    0x13048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x1304F R_X86_64_SIZE32 fooshared 0x0
+// RELOCSHARED-NEXT:    0x13056 R_X86_64_SIZE32 fooshared 0x1
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT:]
+
+// DISASM:      Disassembly of section test
+// DISASM:      _data:
+// DISASM-NEXT: 13000: 19 00
+// DISASM-NEXT: 13002: 00 00
+// DISASM-NEXT: 13004: 00 00
+// DISASM-NEXT: 13006: 00 00
+// DISASM-NEXT: 13008: 1a 00
+// DISASM-NEXT: 1300a: 00 00
+// DISASM-NEXT: 1300c: 00 00
+// DISASM-NEXT: 1300e: 00 00
+// DISASM-NEXT: 13010: 1b 00
+// DISASM-NEXT: 13012: 00 00
+// DISASM-NEXT: 13014: 00 00
+// DISASM-NEXT: 13016: 00 00
+// DISASM-NEXT: 13018: 00 00
+// DISASM-NEXT: 1301a: 00 00
+// DISASM-NEXT: 1301c: 00 00
+// DISASM-NEXT: 1301e: 00 00
+// DISASM-NEXT: 13020: 00 00
+// DISASM-NEXT: 13022: 00 00
+// DISASM-NEXT: 13024: 00 00
+// DISASM-NEXT: 13026: 00 00
+// DISASM-NEXT: 13028: 00 00
+// DISASM-NEXT: 1302a: 00 00
+// DISASM-NEXT: 1302c: 00 00
+// DISASM-NEXT: 1302e: 00 00
+// DISASM:      _start:
+// DISASM-NEXT: 13030: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 13037: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 1303e: 8b 04 25 1b 00 00 00 movl 27, %eax
+// DISASM-NEXT: 13045: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASM-NEXT: 1304c: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASM-NEXT: 13053: 8b 04 25 00 00 00 00 movl 0, %eax
+
+.data
+.global foo
+.type foo,%object
+.size foo,26
+foo:
+.zero 26
+
+.section test, "awx"
+_data:
+  // R_X86_64_SIZE64:
+  .quad foo@SIZE-1
+  .quad foo@SIZE
+  .quad foo@SIZE+1
+  .quad fooshared@SIZE-1
+  .quad fooshared@SIZE
+  .quad fooshared@SIZE+1
+
+.globl _start
+_start:
+  // R_X86_64_SIZE32:
+  movl foo@SIZE-1,%eax
+  movl foo@SIZE,%eax
+  movl foo@SIZE+1,%eax
+  movl fooshared@SIZE-1,%eax
+  movl fooshared@SIZE,%eax
+  movl fooshared@SIZE+1,%eax
diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s
new file mode 100644 (file)
index 0000000..58604db
--- /dev/null
@@ -0,0 +1,123 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+// RUN: ld.lld -shared %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOCSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASMSHARED %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section test:
+// DISASM-NEXT: _data:
+// DISASM-NEXT: 12000: 19 00
+// DISASM-NEXT: 12002: 00 00
+// DISASM-NEXT: 12004: 00 00
+// DISASM-NEXT: 12006: 00 00
+// DISASM-NEXT: 12008: 1a 00
+// DISASM-NEXT: 1200a: 00 00
+// DISASM-NEXT: 1200c: 00 00
+// DISASM-NEXT: 1200e: 00 00
+// DISASM-NEXT: 12010: 1b 00
+// DISASM-NEXT: 12012: 00 00
+// DISASM-NEXT: 12014: 00 00
+// DISASM-NEXT: 12016: 00 00
+// DISASM-NEXT: 12018: 19 00
+// DISASM-NEXT: 1201a: 00 00
+// DISASM-NEXT: 1201c: 00 00
+// DISASM-NEXT: 1201e: 00 00
+// DISASM-NEXT: 12020: 1a 00
+// DISASM-NEXT: 12022: 00 00
+// DISASM-NEXT: 12024: 00 00
+// DISASM-NEXT: 12026: 00 00
+// DISASM-NEXT: 12028: 1b 00
+// DISASM-NEXT: 1202a: 00 00
+// DISASM-NEXT: 1202c: 00 00
+// DISASM-NEXT: 1202e: 00 00
+// DISASM:      _start:
+// DISASM-NEXT: 12030: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 12037: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 1203e: 8b 04 25 1b 00 00 00 movl 27, %eax
+// DISASM-NEXT: 12045: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 1204c: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 12053: 8b 04 25 1b 00 00 00 movl 27, %eax
+
+// RELOCSHARED:      Relocations [
+// RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn {
+// RELOCSHARED-NEXT:    0x3000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x3008 R_X86_64_SIZE64 foo 0x0
+// RELOCSHARED-NEXT:    0x3010 R_X86_64_SIZE64 foo 0x1
+// RELOCSHARED-NEXT:    0x3033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x303A R_X86_64_SIZE32 foo 0x0
+// RELOCSHARED-NEXT:    0x3041 R_X86_64_SIZE32 foo 0x1
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT: ]
+
+// DISASMSHARED:      Disassembly of section test:
+// DISASMSHARED-NEXT: _data:
+// DISASMSHARED-NEXT: 3000: 00 00
+// DISASMSHARED-NEXT: 3002: 00 00
+// DISASMSHARED-NEXT: 3004: 00 00
+// DISASMSHARED-NEXT: 3006: 00 00
+// DISASMSHARED-NEXT: 3008: 00 00
+// DISASMSHARED-NEXT: 300a: 00 00
+// DISASMSHARED-NEXT: 300c: 00 00
+// DISASMSHARED-NEXT: 300e: 00 00
+// DISASMSHARED-NEXT: 3010: 00 00
+// DISASMSHARED-NEXT: 3012: 00 00
+// DISASMSHARED-NEXT: 3014: 00 00
+// DISASMSHARED-NEXT: 3016: 00 00
+// DISASMSHARED-NEXT: 3018: 19 00
+// DISASMSHARED-NEXT: 301a: 00 00
+// DISASMSHARED-NEXT: 301c: 00 00
+// DISASMSHARED-NEXT: 301e: 00 00
+// DISASMSHARED-NEXT: 3020: 1a 00
+// DISASMSHARED-NEXT: 3022: 00 00
+// DISASMSHARED-NEXT: 3024: 00 00
+// DISASMSHARED-NEXT: 3026: 00 00
+// DISASMSHARED-NEXT: 3028: 1b 00
+// DISASMSHARED-NEXT: 302a: 00 00
+// DISASMSHARED-NEXT: 302c: 00 00
+// DISASMSHARED-NEXT: 302e: 00 00
+// DISASMSHARED:      _start:
+// DISASMSHARED-NEXT: 3030: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 3037: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 303e: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 3045: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASMSHARED-NEXT: 304c: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASMSHARED-NEXT: 3053: 8b 04 25 1b 00 00 00 movl 27, %eax
+
+.data
+.global foo
+.type foo,%object
+.size foo,26
+foo:
+.zero 26
+
+.data
+.global foohidden
+.hidden foohidden
+.type foohidden,%object
+.size foohidden,26
+foohidden:
+.zero 26
+
+.section test,"axw"
+_data:
+  // R_X86_64_SIZE64:
+  .quad foo@SIZE-1
+  .quad foo@SIZE
+  .quad foo@SIZE+1
+  .quad foohidden@SIZE-1
+  .quad foohidden@SIZE
+  .quad foohidden@SIZE+1
+.globl _start
+_start:
+  // R_X86_64_SIZE32:
+  movl foo@SIZE-1,%eax
+  movl foo@SIZE,%eax
+  movl foo@SIZE+1,%eax
+  movl foohidden@SIZE-1,%eax
+  movl foohidden@SIZE,%eax
+  movl foohidden@SIZE+1,%eax
diff --git a/test/ELF/relocation-undefined-weak.s b/test/ELF/relocation-undefined-weak.s
new file mode 100644 (file)
index 0000000..f1cb706
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -sections %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix DISASM
+// REQUIRES: x86
+
+// Check that undefined weak symbols are treated as having a VA of 0.
+
+.global _start
+_start:
+  movl $1, sym1(%rip)
+
+.weak sym1
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11000
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+// R_86_64_PC32 = 0 + (-8 - (0x11000 + 2)) = -69642
+
+// DISASM: movl    $1, -69642(%rip)
diff --git a/test/ELF/relocation.s b/test/ELF/relocation.s
new file mode 100644 (file)
index 0000000..1183268
--- /dev/null
@@ -0,0 +1,134 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2
+// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t %t2.so -o %t3
+// RUN: llvm-readobj -s  %t3 | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -s -d %t3 | FileCheck %s
+// REQUIRES: x86
+
+// SEC:      Name: .plt
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_EXECINSTR
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x11030
+// SEC-NEXT: Offset: 0x1030
+// SEC-NEXT: Size: 48
+
+// SEC:         Name: .got
+// SEC-NEXT:   Type: SHT_PROGBITS
+// SEC-NEXT:   Flags [
+// SEC-NEXT:     SHF_ALLOC
+// SEC-NEXT:     SHF_WRITE
+// SEC-NEXT:   ]
+// SEC-NEXT:   Address: 0x120F0
+// SEC-NEXT:   Offset:
+// SEC-NEXT:   Size: 8
+// SEC-NEXT:   Link: 0
+// SEC-NEXT:   Info: 0
+// SEC-NEXT:   AddressAlignment: 8
+// SEC-NEXT:   EntrySize: 0
+// SEC-NEXT: }
+
+// SEC:        Name: .got.plt
+// SEC-NEXT:   Type: SHT_PROGBITS
+// SEC-NEXT:   Flags [
+// SEC-NEXT:     SHF_ALLOC
+// SEC-NEXT:     SHF_WRITE
+// SEC-NEXT:   ]
+// SEC-NEXT:   Address: 0x13000
+// SEC-NEXT:   Offset: 0x3000
+// SEC-NEXT:   Size: 40
+// SEC-NEXT:   Link: 0
+// SEC-NEXT:   Info: 0
+// SEC-NEXT:   AddressAlignment: 8
+// SEC-NEXT:   EntrySize: 0
+// SEC-NEXT:   }
+
+.section       .text,"ax",@progbits,unique,1
+.global _start
+_start:
+  call lulz
+
+.section       .text,"ax",@progbits,unique,2
+.zero 4
+.global lulz
+lulz:
+  nop
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   11000:  e8 04 00 00 00   callq 4
+// CHECK-NEXT:   11005:
+
+// CHECK:      lulz:
+// CHECK-NEXT:   11009:  90  nop
+
+
+.section       .text2,"ax",@progbits
+.global R_X86_64_32
+R_X86_64_32:
+  movl $R_X86_64_32, %edx
+
+// FIXME: this would be far more self evident if llvm-objdump printed
+// constants in hex.
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: R_X86_64_32:
+// CHECK-NEXT:  1100a: {{.*}} movl $69642, %edx
+
+.section .R_X86_64_32S,"ax",@progbits
+.global R_X86_64_32S
+R_X86_64_32S:
+  movq lulz - 0x100000, %rdx
+
+// CHECK: Disassembly of section .R_X86_64_32S:
+// CHECK-NEXT: R_X86_64_32S:
+// CHECK-NEXT:  {{.*}}: {{.*}} movq -978935, %rdx
+
+.section .R_X86_64_PC32,"ax",@progbits
+.global R_X86_64_PC32
+R_X86_64_PC32:
+ call bar
+ movl $bar, %eax
+//16 is a size of PLT[0]
+// 0x11030 + 16 - (0x11017 + 5) = 20
+// CHECK:      Disassembly of section .R_X86_64_PC32:
+// CHECK-NEXT: R_X86_64_PC32:
+// CHECK-NEXT:  11017:   {{.*}}  callq  36
+// CHECK-NEXT:  1101c:   {{.*}}  movl $69696, %eax
+
+.section .R_X86_64_32S_2,"ax",@progbits
+.global R_X86_64_32S_2
+R_X86_64_32S_2:
+  mov bar2, %eax
+// plt is  at 0x11030. The second plt entry is at 0x11050 == 69712
+// CHECK:      Disassembly of section .R_X86_64_32S_2:
+// CHECK-NEXT: R_X86_64_32S_2:
+// CHECK-NEXT: 11021: {{.*}}  movl    69712, %eax
+
+.section .R_X86_64_64,"a",@progbits
+.global R_X86_64_64
+R_X86_64_64:
+ .quad R_X86_64_64
+
+// CHECK:      Contents of section .R_X86_64_64:
+// CHECK-NEXT:   101c8 c8010100 00000000
+
+.section .R_X86_64_GOTPCREL,"a",@progbits
+.global R_X86_64_GOTPCREL
+R_X86_64_GOTPCREL:
+ .long zed@gotpcrel
+
+// 0x120F8 - 0x101D8 = 7952
+// 7952 = 0x101f0000 in little endian
+// CHECK:      Contents of section .R_X86_64_GOTPCREL
+// CHECK-NEXT:   101d0 201f0000
+
+.section .R_X86_64_GOT32,"a",@progbits
+.global R_X86_64_GOT32
+R_X86_64_GOT32:
+        .long zed@got
+
+// CHECK: Contents of section .R_X86_64_GOT32:
+// CHECK-NEXT: f8ffffff
diff --git a/test/ELF/relro-tls.s b/test/ELF/relro-tls.s
new file mode 100644 (file)
index 0000000..0ee5b6d
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+// CHECK:      Type: PT_GNU_RELRO
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress:
+// CHECK-NEXT: PhysicalAddress:
+// CHECK-NEXT: FileSize: 4
+// CHECK-NEXT: MemSize: 4
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+
+.global _start
+_start:
+
+.global d
+.section .foo,"awT",@progbits
+d:
+.long 2
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
new file mode 100644 (file)
index 0000000..d355487
--- /dev/null
@@ -0,0 +1,242 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -z now -z relro -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=FULLRELRO %s
+// RUN: ld.lld %t.o %t2.so -z relro -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=PARTRELRO %s
+// RUN: ld.lld %t.o %t2.so -z norelro -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=NORELRO %s
+// REQUIRES: x86
+
+// FULLRELRO:        Section {
+// FULLRELRO:        Index: 9
+// FULLRELRO-NEXT:   Name: .got
+// FULLRELRO-NEXT:   Type: SHT_PROGBITS
+// FULLRELRO-NEXT:   Flags [
+// FULLRELRO-NEXT:     SHF_ALLOC
+// FULLRELRO-NEXT:     SHF_WRITE
+// FULLRELRO-NEXT:   ]
+// FULLRELRO-NEXT:   Address: 0x12110
+// FULLRELRO-NEXT:   Offset: 0x2110
+// FULLRELRO-NEXT:   Size: 8
+// FULLRELRO-NEXT:   Link: 0
+// FULLRELRO-NEXT:   Info: 0
+// FULLRELRO-NEXT:   AddressAlignment: 8
+// FULLRELRO-NEXT:   EntrySize: 0
+// FULLRELRO-NEXT:   SectionData (
+// FULLRELRO-NEXT:     0000: 00000000 00000000
+// FULLRELRO-NEXT:   )
+// FULLRELRO-NEXT: }
+// FULLRELRO-NEXT: Section {
+// FULLRELRO-NEXT:   Index: 10
+// FULLRELRO-NEXT:   Name: .got.plt
+// FULLRELRO-NEXT:   Type: SHT_PROGBITS
+// FULLRELRO-NEXT:   Flags [
+// FULLRELRO-NEXT:     SHF_ALLOC
+// FULLRELRO-NEXT:     SHF_WRITE
+// FULLRELRO-NEXT:   ]
+// FULLRELRO-NEXT:   Address: 0x12118
+// FULLRELRO-NEXT:   Offset: 0x2118
+// FULLRELRO-NEXT:   Size: 32
+// FULLRELRO-NEXT:   Link: 0
+// FULLRELRO-NEXT:   Info: 0
+// FULLRELRO-NEXT:   AddressAlignment: 8
+// FULLRELRO-NEXT:   EntrySize: 0
+// FULLRELRO-NEXT:   SectionData (
+// FULLRELRO-NEXT:     0000:
+// FULLRELRO-NEXT:     0010:
+// FULLRELRO-NEXT:   )
+// FULLRELRO-NEXT: }
+// FULLRELRO-NEXT: Section {
+// FULLRELRO-NEXT:   Index: 11
+// FULLRELRO-NEXT:   Name: .data
+// FULLRELRO-NEXT:   Type: SHT_PROGBITS
+// FULLRELRO-NEXT:   Flags [
+// FULLRELRO-NEXT:     SHF_ALLOC
+// FULLRELRO-NEXT:     SHF_WRITE
+// FULLRELRO-NEXT:   ]
+// FULLRELRO-NEXT:   Address: 0x13000
+// FULLRELRO-NEXT:   Offset: 0x3000
+// FULLRELRO-NEXT:   Size: 12
+// FULLRELRO-NEXT:   Link: 0
+// FULLRELRO-NEXT:   Info: 0
+// FULLRELRO-NEXT:   AddressAlignment:
+// FULLRELRO-NEXT:   EntrySize: 0
+// FULLRELRO-NEXT:   SectionData (
+// FULLRELRO-NEXT:     0000:
+// FULLRELRO-NEXT:   )
+// FULLRELRO-NEXT: }
+// FULLRELRO-NEXT: Section {
+// FULLRELRO-NEXT:   Index: 12
+// FULLRELRO-NEXT:   Name: .foo
+// FULLRELRO-NEXT:   Type: SHT_PROGBITS
+// FULLRELRO-NEXT:   Flags [
+// FULLRELRO-NEXT:     SHF_ALLOC
+// FULLRELRO-NEXT:     SHF_WRITE
+// FULLRELRO-NEXT:   ]
+// FULLRELRO-NEXT:   Address: 0x1300C
+// FULLRELRO-NEXT:   Offset: 0x300C
+// FULLRELRO-NEXT:   Size: 0
+// FULLRELRO-NEXT:   Link: 0
+// FULLRELRO-NEXT:   Info: 0
+// FULLRELRO-NEXT:   AddressAlignment:
+// FULLRELRO-NEXT:   EntrySize: 0
+// FULLRELRO-NEXT:   SectionData (
+// FULLRELRO-NEXT:   )
+// FULLRELRO-NEXT: }
+// 308 - sizeof(.data)(12) = 296
+// FULLRELRO:       ProgramHeaders [
+// FULLRELRO:       Type: PT_LOAD
+// FULLRELRO:       Offset: 0x2000
+// FULLRELRO-NEXT:  VirtualAddress: [[RWADDR:.*]]
+// FULLRELRO-NEXT:  PhysicalAddress:
+// FULLRELRO-NEXT:  FileSize: 4108
+// FULLRELRO-NEXT:  MemSize: 4108
+// FULLRELRO-NEXT:  Flags [
+// FULLRELRO-NEXT:    PF_R
+// FULLRELRO-NEXT:    PF_W
+// FULLRELRO-NEXT:  ]
+// FULLRELRO-NEXT:  Alignment: 4096
+// FULLRELRO-NEXT:}
+// FULLRELRO:       Type: PT_GNU_RELRO
+// FULLRELRO-NEXT:  Offset: 0x
+// FULLRELRO-NEXT:  VirtualAddress: [[RWADDR]]
+// FULLRELRO-NEXT:  PhysicalAddress:
+// FULLRELRO-NEXT:  FileSize: 312
+// FULLRELRO-NEXT:  MemSize: 312
+// FULLRELRO-NEXT:  Flags [
+// FULLRELRO-NEXT:    PF_R
+// FULLRELRO-NEXT:  ]
+// FULLRELRO-NEXT:  Alignment: 1
+// FULLRELRO-NEXT:}
+
+// PARTRELRO:       Section {
+// PARTRELRO:       Index: 9
+// PARTRELRO-NEXT:  Name: .got
+// PARTRELRO-NEXT:  Type: SHT_PROGBITS
+// PARTRELRO-NEXT:  Flags [
+// PARTRELRO-NEXT:    SHF_ALLOC
+// PARTRELRO-NEXT:    SHF_WRITE
+// PARTRELRO-NEXT:  ]
+// PARTRELRO-NEXT:  Address: 0x120F0
+// PARTRELRO-NEXT:  Offset: 0x20F0
+// PARTRELRO-NEXT:  Size: 8
+// PARTRELRO-NEXT:  Link: 0
+// PARTRELRO-NEXT:  Info: 0
+// PARTRELRO-NEXT:  AddressAlignment: 8
+// PARTRELRO-NEXT:  EntrySize: 0
+// PARTRELRO-NEXT:  SectionData (
+// PARTRELRO-NEXT:    0000:
+// PARTRELRO-NEXT:  )
+// PARTRELRO-NEXT:  }
+// PARTRELRO-NEXT:  Section {
+// PARTRELRO-NEXT:  Index: 10
+// PARTRELRO-NEXT:  Name: .data
+// PARTRELRO-NEXT:  Type: SHT_PROGBITS
+// PARTRELRO-NEXT:  Flags [
+// PARTRELRO-NEXT:    SHF_ALLOC
+// PARTRELRO-NEXT:    SHF_WRITE
+// PARTRELRO-NEXT:  ]
+// PARTRELRO-NEXT:  Address: 0x13000
+// PARTRELRO-NEXT:  Offset: 0x3000
+// PARTRELRO-NEXT:  Size: 12
+// PARTRELRO-NEXT:  Link: 0
+// PARTRELRO-NEXT:  Info: 0
+// PARTRELRO-NEXT:  AddressAlignment: 1
+// PARTRELRO-NEXT:  EntrySize: 0
+// PARTRELRO-NEXT:  SectionData (
+// PARTRELRO-NEXT:    0000:
+// PARTRELRO-NEXT:  )
+// PARTRELRO-NEXT:  }
+// PARTRELRO-NEXT:  Section {
+// PARTRELRO-NEXT:    Index: 11
+// PARTRELRO-NEXT:    Name: .foo
+// PARTRELRO-NEXT:    Type: SHT_PROGBITS
+// PARTRELRO-NEXT:    Flags [
+// PARTRELRO-NEXT:      SHF_ALLOC
+// PARTRELRO-NEXT:      SHF_WRITE
+// PARTRELRO-NEXT:    ]
+// PARTRELRO-NEXT:    Address: 0x1300C
+// PARTRELRO-NEXT:    Offset: 0x300C
+// PARTRELRO-NEXT:    Size: 0
+// PARTRELRO-NEXT:    Link: 0
+// PARTRELRO-NEXT:    Info: 0
+// PARTRELRO-NEXT:    AddressAlignment: 1
+// PARTRELRO-NEXT:    EntrySize: 0
+// PARTRELRO-NEXT:    SectionData (
+// PARTRELRO-NEXT:    )
+// PARTRELRO-NEXT:  }
+// PARTRELRO-NEXT:  Section {
+// PARTRELRO-NEXT:    Index: 12
+// PARTRELRO-NEXT:    Name: .got.plt
+// PARTRELRO-NEXT:    Type: SHT_PROGBITS
+// PARTRELRO-NEXT:    Flags [
+// PARTRELRO-NEXT:      SHF_ALLOC
+// PARTRELRO-NEXT:      SHF_WRITE
+// PARTRELRO-NEXT:    ]
+// PARTRELRO-NEXT:    Address: 0x13010
+// PARTRELRO-NEXT:    Offset: 0x3010
+// PARTRELRO-NEXT:    Size: 32
+// PARTRELRO-NEXT:    Link: 0
+// PARTRELRO-NEXT:    Info: 0
+// PARTRELRO-NEXT:    AddressAlignment: 8
+// PARTRELRO-NEXT:    EntrySize: 0
+// PARTRELRO-NEXT:    SectionData (
+// PARTRELRO-NEXT:      0000:
+// PARTRELRO-NEXT:      0010:
+// PARTRELRO-NEXT:    )
+// PARTRELRO-NEXT:  }
+// PARTRELRO-NEXT:  Section {
+// PARTRELRO-NEXT:    Index: 13
+// PARTRELRO-NEXT:    Name: .bss
+// PARTRELRO-NEXT:    Type: SHT_NOBITS
+// PARTRELRO-NEXT:    Flags [
+// PARTRELRO-NEXT:      SHF_ALLOC
+// PARTRELRO-NEXT:      SHF_WRITE
+// PARTRELRO-NEXT:    ]
+// PARTRELRO-NEXT:    Address: 0x13030
+// PARTRELRO-NEXT:    Offset: 0x3030
+// PARTRELRO-NEXT:    Size: 0
+// PARTRELRO-NEXT:    Link: 0
+// PARTRELRO-NEXT:    Info: 0
+// PARTRELRO-NEXT:    AddressAlignment: 1
+// PARTRELRO-NEXT:    EntrySize: 0
+// PARTRELRO-NEXT:  }
+// PARTRELRO:       ProgramHeader {
+// PARTRELRO:       Type: PT_LOAD
+// PARTRELRO:       Offset: 0x2000
+// PARTRELRO-NEXT:  VirtualAddress: [[RWADDR:.*]]
+// PARTRELRO-NEXT:  PhysicalAddress:
+// PARTRELRO-NEXT:  FileSize: 4144
+// PARTRELRO-NEXT:  MemSize: 4144
+// PARTRELRO-NEXT:  Flags [
+// PARTRELRO-NEXT:    PF_R (0x4)
+// PARTRELRO-NEXT:    PF_W (0x2)
+// PARTRELRO-NEXT:  ]
+// PARTRELRO-NEXT:  Alignment: 4096
+// PARTRELRO:       Type: PT_GNU_RELRO
+// PARTRELRO-NEXT:  Offset: 0x2000
+// PARTRELRO-NEXT:  VirtualAddress: [[RWADDR]]
+// PARTRELRO-NEXT:  PhysicalAddress:
+// PARTRELRO-NEXT:  FileSize: 248
+// PARTRELRO-NEXT:  MemSize: 248
+// PARTRELRO-NEXT:  Flags [
+// PARTRELRO-NEXT:    PF_R
+// PARTRELRO-NEXT:  ]
+// PARTRELRO-NEXT:  Alignment: 1
+
+// NORELRO:     ProgramHeaders [
+// NORELRO-NOT: PT_GNU_RELRO
+
+.global _start
+_start:
+  .long bar
+  jmp *bar2@GOTPCREL(%rip)
+
+.section .data,"aw"
+.quad 0
+
+.zero 4
+.section .foo,"aw"
+.section .bss,"",@nobits
diff --git a/test/ELF/reproduce-error.s b/test/ELF/reproduce-error.s
new file mode 100644 (file)
index 0000000..c66132c
--- /dev/null
@@ -0,0 +1,15 @@
+# Extracting the cpio archive can get over the path limit on windows.
+# REQUIRES: shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir
+# RUN: cd %t.dir
+
+# RUN: not ld.lld --reproduce repro abc -o t 2>&1 | FileCheck %s
+# CHECK: cannot open abc: {{N|n}}o such file or directory
+
+# RUN: grep TRAILER repro.cpio
+# RUN: cpio -id < repro.cpio
+# RUN: FileCheck --check-prefix=RSP %s < repro/response.txt
+# RSP: abc
+# RSP: -o t
diff --git a/test/ELF/reproduce-linkerscript.s b/test/ELF/reproduce-linkerscript.s
new file mode 100644 (file)
index 0000000..a020fcc
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86, shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build/foo.o
+# RUN: echo "INPUT(\"%t.dir/build/foo.o\")" > %t.dir/build/foo.script
+# RUN: cd %t.dir
+# RUN: ld.lld build/foo.script -o bar --reproduce repro
+# RUN: cpio -id < repro.cpio
+# RUN: diff build/foo.script repro/%:t.dir/build/foo.script
+# RUN: diff build/foo.o repro/%:t.dir/build/foo.o
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/reproduce-thin-archive.s b/test/ELF/reproduce-thin-archive.s
new file mode 100644 (file)
index 0000000..0797b6c
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86, shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.dir/foo.o
+# RUN: cd %t.dir
+# RUN: llvm-ar --format=gnu rcT foo.a foo.o
+# RUN: ld.lld -m elf_x86_64 foo.a -o bar --reproduce repro
+# RUN: cpio -id < repro.cpio
+# RUN: diff foo.a repro/%:t.dir/foo.a
+# RUN: diff foo.o repro/%:t.dir/foo.o
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/reproduce-windows.s b/test/ELF/reproduce-windows.s
new file mode 100644 (file)
index 0000000..464b270
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# Test that a repro archive always uses / instead of \.
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build
+# RUN: llvm-mc %s -o %t.dir/build/foo.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: cd %t.dir
+# RUN: not ld.lld build/foo.o --reproduce repro
+# RUN: cpio -t < repro.cpio | FileCheck %s
+
+# CHECK: repro/response.txt
+# CHECK: repro/{{.*}}/build/foo.o
diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s
new file mode 100644 (file)
index 0000000..9d256c1
--- /dev/null
@@ -0,0 +1,67 @@
+# REQUIRES: x86
+
+# Extracting the cpio archive can get over the path limit on windows.
+# REQUIRES: shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build1/foo.o
+# RUN: cd %t.dir
+# RUN: ld.lld --hash-style=gnu build1/foo.o -o bar -shared --as-needed --reproduce repro
+# RUN: cpio -id < repro.cpio
+# RUN: diff build1/foo.o repro/%:t.dir/build1/foo.o
+
+# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
+# RSP: {{^}}--hash-style gnu{{$}}
+# RSP-NOT: repro{{[/\\]}}
+# RSP-NEXT: {{[/\\]}}foo.o
+# RSP-NEXT: -o bar
+# RSP-NEXT: -shared
+# RSP-NEXT: --as-needed
+
+# RUN: FileCheck %s --check-prefix=VERSION < repro/version.txt
+# VERSION: LLD
+
+# RUN: mkdir -p %t.dir/build2/a/b/c
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build2/foo.o
+# RUN: cd %t.dir/build2/a/b/c
+# RUN: env LLD_REPRODUCE=repro ld.lld ./../../../foo.o -o bar -shared --as-needed
+# RUN: cpio -id < repro.cpio
+# RUN: diff %t.dir/build2/foo.o repro/%:t.dir/build2/foo.o
+
+# RUN: echo "{ local: *; };" >  ver
+# RUN: echo > dyn
+# RUN: echo > file
+# RUN: echo > file2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o 'foo bar'
+# RUN: ld.lld --reproduce repro2 'foo bar' -L"foo bar" -Lfile -Tfile2 \
+# RUN:   --dynamic-list dyn -rpath file --script file --version-script ver \
+# RUN:   --dynamic-linker "some unusual/path" -soname 'foo bar' -soname='foo bar'
+# RUN: cpio -id < repro2.cpio
+# RUN: FileCheck %s --check-prefix=RSP2 < repro2/response.txt
+# RSP2:      "{{.*}}foo bar"
+# RSP2-NEXT: -L "{{.*}}foo bar"
+# RSP2-NEXT: -L {{.+}}file
+# RSP2-NEXT: --script {{.+}}file2
+# RSP2-NEXT: --dynamic-list {{.+}}dyn
+# RSP2-NEXT: -rpath {{.+}}file
+# RSP2-NEXT: --script {{.+}}file
+# RSP2-NEXT: --version-script [[PATH:.*]]ver
+# RSP2-NEXT: --dynamic-linker "some unusual/path"
+# RSP2-NEXT: -soname="foo bar"
+# RSP2-NEXT: -soname="foo bar"
+
+# RUN: cpio -t < repro2.cpio | FileCheck %s
+# CHECK:      repro2/response.txt
+# CHECK-NEXT: repro2/version.txt
+# CHECK-NEXT: repro2/{{.*}}/dyn
+# CHECK-NEXT: repro2/{{.*}}/ver
+# CHECK-NEXT: repro2/{{.*}}/foo bar
+# CHECK-NEXT: repro2/{{.*}}/file2
+# CHECK-NEXT: repro2/{{.*}}/file
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/resolution-shared.s b/test/ELF/resolution-shared.s
new file mode 100644 (file)
index 0000000..e1eac07
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-shared.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3 -shared
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// REQUIRES: x86
+
+        .weak foo
+foo:
+
+// CHECK:      Symbol {
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding: Weak
diff --git a/test/ELF/resolution.s b/test/ELF/resolution.s
new file mode 100644 (file)
index 0000000..5596212
--- /dev/null
@@ -0,0 +1,430 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2
+// RUN: ld.lld -discard-all %t %t2 -o %t3
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// REQUIRES: x86
+
+// This is an exhaustive test for checking which symbol is kept when two
+// have the same name. Each symbol has a different size which is used
+// to see which one was chosen.
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 63
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 30
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 55
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 22
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 27
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 26
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 61
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 28
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 53
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 20
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 25
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 10
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 9
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 2
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 6
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 5
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 40
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 7
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 33
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 3
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 51
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 50
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 46
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 45
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 49
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 48
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 44
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 43
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_UndefWeak
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.globl _start
+_start:
+        nop
+
+local:
+
+.weak RegularWeak_with_RegularWeak
+.size RegularWeak_with_RegularWeak, 0
+RegularWeak_with_RegularWeak:
+
+.weak RegularWeak_with_RegularStrong
+.size RegularWeak_with_RegularStrong, 1
+RegularWeak_with_RegularStrong:
+
+.global RegularStrong_with_RegularWeak
+.size RegularStrong_with_RegularWeak, 2
+RegularStrong_with_RegularWeak:
+
+.weak RegularWeak_with_UndefWeak
+.size RegularWeak_with_UndefWeak, 3
+RegularWeak_with_UndefWeak:
+
+.weak RegularWeak_with_UndefStrong
+.size RegularWeak_with_UndefStrong, 4
+RegularWeak_with_UndefStrong:
+
+.global RegularStrong_with_UndefWeak
+.size RegularStrong_with_UndefWeak, 5
+RegularStrong_with_UndefWeak:
+
+.global RegularStrong_with_UndefStrong
+.size RegularStrong_with_UndefStrong, 6
+RegularStrong_with_UndefStrong:
+
+.weak RegularWeak_with_CommonWeak
+.size RegularWeak_with_CommonWeak, 7
+RegularWeak_with_CommonWeak:
+
+.weak RegularWeak_with_CommonStrong
+.size RegularWeak_with_CommonStrong, 8
+RegularWeak_with_CommonStrong:
+
+.global RegularStrong_with_CommonWeak
+.size RegularStrong_with_CommonWeak, 9
+RegularStrong_with_CommonWeak:
+
+.global RegularStrong_with_CommonStrong
+.size RegularStrong_with_CommonStrong, 10
+RegularStrong_with_CommonStrong:
+
+.weak UndefWeak_with_RegularWeak
+.size UndefWeak_with_RegularWeak, 11
+.quad UndefWeak_with_RegularWeak
+
+.weak UndefWeak_with_RegularStrong
+.size UndefWeak_with_RegularStrong, 12
+.quad UndefWeak_with_RegularStrong
+
+.size UndefStrong_with_RegularWeak, 13
+.quad UndefStrong_with_RegularWeak
+
+.size UndefStrong_with_RegularStrong, 14
+.quad UndefStrong_with_RegularStrong
+
+.weak UndefWeak_with_UndefWeak
+.size UndefWeak_with_UndefWeak, 15
+.quad UndefWeak_with_UndefWeak
+
+.weak UndefWeak_with_CommonWeak
+.size UndefWeak_with_CommonWeak, 16
+.quad UndefWeak_with_CommonWeak
+
+.weak UndefWeak_with_CommonStrong
+.size UndefWeak_with_CommonStrong, 17
+.quad UndefWeak_with_CommonStrong
+
+.size UndefStrong_with_CommonWeak, 18
+.quad UndefStrong_with_CommonWeak
+
+.size UndefStrong_with_CommonStrong, 19
+.quad UndefStrong_with_CommonStrong
+
+.weak CommonWeak_with_RegularWeak
+.comm CommonWeak_with_RegularWeak,20,4
+
+.weak CommonWeak_with_RegularStrong
+.comm CommonWeak_with_RegularStrong,21,4
+
+.comm CommonStrong_with_RegularWeak,22,4
+
+.comm CommonStrong_with_RegularStrong,23,4
+
+.weak CommonWeak_with_UndefWeak
+.comm CommonWeak_with_UndefWeak,24,4
+
+.weak CommonWeak_with_UndefStrong
+.comm CommonWeak_with_UndefStrong,25,4
+
+.comm CommonStrong_with_UndefWeak,26,4
+
+.comm CommonStrong_with_UndefStrong,27,4
+
+.weak CommonWeak_with_CommonWeak
+.comm CommonWeak_with_CommonWeak,28,4
+
+.weak CommonWeak_with_CommonStrong
+.comm CommonWeak_with_CommonStrong,29,4
+
+.comm CommonStrong_with_CommonWeak,30,4
+
+.comm CommonStrong_with_CommonStrong,31,4
diff --git a/test/ELF/section-align-0.test b/test/ELF/section-align-0.test
new file mode 100644 (file)
index 0000000..35783f5
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: yaml2obj %s -o %t
+# RUN: ld.lld %t -o %tout
+
+# Verify that lld can handle sections with an alignment of zero.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    AddressAlign:    0
+
+Symbols:
+  Global:
+    - Name:            _start
+      Section:         .text
diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s
new file mode 100644 (file)
index 0000000..2048091
--- /dev/null
@@ -0,0 +1,54 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-readobj -sections %tout | FileCheck %s
+# REQUIRES: x86
+
+# Check that sections are laid out in the correct order.
+
+.global _start
+.text
+_start:
+
+.section t,"x",@nobits
+.section s,"x"
+.section r,"w",@nobits
+.section q,"w"
+.section p,"wx",@nobits
+.section o,"wx"
+.section n,"",@nobits
+.section m,""
+
+.section l,"awx",@nobits
+.section k,"awx"
+.section j,"aw",@nobits
+.section i,"aw"
+.section g,"awT",@nobits
+.section e,"awT"
+.section d,"ax",@nobits
+.section c,"ax"
+.section b,"a",@nobits
+.section a,"a"
+
+// CHECK: Name: a
+// CHECK: Name: b
+// CHECK: Name: c
+// CHECK: Name: d
+
+// TLS sections are only sorted on NOBITS.
+// CHECK: Name: e
+// CHECK: Name: g
+
+// CHECK: Name: i
+// CHECK: Name: j
+// CHECK: Name: k
+// CHECK: Name: l
+
+// Non allocated sections are in input order.
+// CHECK: Name: t
+// CHECK: Name: s
+// CHECK: Name: r
+// CHECK: Name: q
+// CHECK: Name: p
+// CHECK: Name: o
+// CHECK: Name: n
+// CHECK: Name: m
diff --git a/test/ELF/section-name.s b/test/ELF/section-name.s
new file mode 100644 (file)
index 0000000..f470c48
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-readobj -sections %tout | FileCheck %s
+# REQUIRES: x86
+
+.global _start
+.text
+_start:
+
+.section .text.a,"ax"
+.section .text.,"ax"
+.section .rodata.a,"a"
+.section .rodata,"a"
+.section .data.a,"aw"
+.section .data,"aw"
+.section .bss.a,"",@nobits
+.section .bss,"",@nobits
+.section .foo.a,"aw"
+.section .foo,"aw"
+.section .data.rel.ro,"aw",%progbits
+.section .data.rel.ro.a,"aw",%progbits
+.section .data.rel.ro.local,"aw",%progbits
+.section .data.rel.ro.local.a,"aw",%progbits
+.section .tbss.foo,"aGwT",@nobits,foo,comdat
+.section .gcc_except_table.foo,"aG",@progbits,foo,comdat
+.section .tdata.foo,"aGwT",@progbits,foo,comdat
+
+// CHECK-NOT: Name: .rodata.a
+// CHECK:     Name: .rodata
+// CHECK:     Name: .gcc_except_table ({{.*}})
+// CHECK-NOT: Name: .text.a
+// CHECK:     Name: .text
+// CHECK:     Name: .tdata ({{.*}})
+// CHECK:     Name: .tbss ({{.*}})
+// CHECK-NOT: Name: .data.rel.ro.a
+// CHECK-NOT: Name: .data.rel.ro.local.a
+// CHECK:     Name: .data.rel.ro
+// CHECK-NOT: Name: .data.a
+// CHECK:     Name: .data
+// CHECK:     Name: .foo.a
+// CHECK:     Name: .foo
+// CHECK-NOT: Name: .bss.a
+// CHECK:     Name: .bss
diff --git a/test/ELF/section-symbol.s b/test/ELF/section-symbol.s
new file mode 100644 (file)
index 0000000..5cf71ac
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t.so -shared -discard-none
+// RUN: llvm-readobj -t %t.so | FileCheck %s
+
+// Test that we don't include the section symbols from the .o in the .so
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+foo:
+        .quad foo - .
diff --git a/test/ELF/shared-be.s b/test/ELF/shared-be.s
new file mode 100644 (file)
index 0000000..12eb313
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK:      Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELSIZE:.*]]
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[RELENT:.*]]
+
+// CHECK:      DynamicSection [
+// CHECK-NEXT:   Tag                Type                 Name/Value
+// CHECK-NEXT:   0x000000000000001D RUNPATH              foo:bar
+// CHECK-NEXT:   0x0000000000000001 NEEDED               SharedLibrary ({{.*}}2.so)
+// CHECK-NEXT:   0x0000000000000007 RELA                 [[RELADDR]]
+// CHECK-NEXT:   0x0000000000000008 RELASZ               [[RELSIZE]] (bytes)
+// CHECK-NEXT:   0x0000000000000009 RELAENT              [[RELENT]] (bytes)
+// CHECK:        0x0000000000000015 DEBUG                0x0
+// CHECK-NEXT:   0x0000000000000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+.data
+.long bar
+.long zed
+
diff --git a/test/ELF/shared.s b/test/ELF/shared.s
new file mode 100644 (file)
index 0000000..086cc73
--- /dev/null
@@ -0,0 +1,305 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: llvm-readobj -s %t2.so | FileCheck --check-prefix=SO %s
+// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -hash-table %t | FileCheck %s
+// RUN: ld.lld %t.o %t2.so %t2.so -o %t2
+// RUN: llvm-readobj -dyn-symbols %t2 | FileCheck --check-prefix=DONT_EXPORT %s
+// REQUIRES: x86
+
+// Make sure .symtab is properly aligned.
+// SO:      Name: .symtab
+// SO-NEXT: Type: SHT_SYMTAB
+// SO-NEXT: Flags [
+// SO-NEXT: ]
+// SO-NEXT: Address:
+// SO-NEXT: Offset: 0x1030
+// SO-NEXT: Size:
+// SO-NEXT: Link:
+// SO-NEXT: Info:
+// SO-NEXT: AddressAlignment: 4
+
+// CHECK:        Name: .interp
+// CHECK-NEXT:   Type: SHT_PROGBITS
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[INTERPADDR:.*]]
+// CHECK-NEXT:   Offset: [[INTERPOFFSET:.*]]
+// CHECK-NEXT:   Size: [[INTERPSIZE:.*]]
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: 1
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT:   SectionData (
+// CHECK-NEXT:     0000: 2F6C6962 36342F6C 642D6C69 6E75782D  |/lib64/ld-linux-|
+// CHECK-NEXT:     0010: 7838362D 36342E73 6F2E3200           |x86-64.so.2.|
+// CHECK-NEXT:   )
+// CHECK-NEXT: }
+
+// test that .hash is linked to .dynsym
+// CHECK:        Index: 2
+// CHECK-NEXT:   Name: .dynsym
+// CHECK-NEXT:   Type: SHT_DYNSYM
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[DYNSYMADDR:.*]]
+// CHECK-NEXT:   Offset: 0x150
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Link: [[DYNSTR:.*]]
+// CHECK-NEXT:   Info: 1
+// CHECK-NEXT:   AddressAlignment: 4
+// CHECK-NEXT:   EntrySize: 16
+// CHECK-NEXT:   SectionData (
+// CHECK-NEXT:     0000:
+// CHECK-NEXT:     0010:
+// CHECK-NEXT:     0020:
+// CHECK-NEXT:     0030:
+// CHECK-NEXT:   )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT:   Index: 3
+// CHECK-NEXT:    Name: .hash
+// CHECK-NEXT:    Type: SHT_HASH
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: [[HASHADDR:.*]]
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size:
+// CHECK-NEXT:    Link: 2
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize: 4
+
+// CHECK:        Index: [[DYNSTR]]
+// CHECK-NEXT:   Name: .dynstr
+// CHECK-NEXT:   Type: SHT_STRTAB
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[DYNSTRADDR:.*]]
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: 1
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT:   SectionData (
+// CHECK:        )
+// CHECK-NEXT: }
+
+// CHECK:      Name: .rel.dyn
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELSIZE:.*]]
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[RELENT:.*]]
+
+// CHECK:        Name: .dynamic
+// CHECK-NEXT:   Type: SHT_DYNAMIC
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:     SHF_WRITE
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[ADDR:.*]]
+// CHECK-NEXT:   Offset: [[OFFSET:.*]]
+// CHECK-NEXT:   Size: [[SIZE:.*]]
+// CHECK-NEXT:   Link: [[DYNSTR]]
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: [[ALIGN:.*]]
+// CHECK-NEXT:   EntrySize: 8
+// CHECK-NEXT:   SectionData (
+// CHECK:        )
+
+// CHECK:      Name: .symtab
+// CHECK-NEXT: Type: SHT_SYMTAB
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[SYMENT:.*]]
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x12000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @ (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start@
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Non
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// DONT_EXPORT:      DynamicSymbols [
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: @ (0)
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Local (0x0)
+// DONT_EXPORT-NEXT:     Type: None (0x0)
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined (0x0)
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: bar@
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Global
+// DONT_EXPORT-NEXT:     Type: Function
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: zed@
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Global
+// DONT_EXPORT-NEXT:     Type: None
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT: ]
+
+// CHECK:      DynamicSection [
+// CHECK-NEXT:   Tag        Type                 Name/Value
+// CHECK-NEXT:   0x0000001D RUNPATH              foo:bar
+// CHECK-NEXT:   0x00000001 NEEDED               SharedLibrary ({{.*}}2.so)
+// CHECK-NEXT:   0x00000011 REL                  [[RELADDR]]
+// CHECK-NEXT:   0x00000012 RELSZ                [[RELSIZE]] (bytes)
+// CHECK-NEXT:   0x00000013 RELENT               [[RELENT]] (bytes)
+// CHECK-NEXT:   0x00000006 SYMTAB               [[DYNSYMADDR]]
+// CHECK-NEXT:   0x0000000B SYMENT               [[SYMENT]] (bytes)
+// CHECK-NEXT:   0x00000005 STRTAB               [[DYNSTRADDR]]
+// CHECK-NEXT:   0x0000000A STRSZ
+// CHECK-NEXT:   0x00000004 HASH                 [[HASHADDR]]
+// CHECK-NEXT:   0x00000015 DEBUG                0x0
+// CHECK-NEXT:   0x00000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+// CHECK:     ProgramHeaders [
+// CHECK:        Type: PT_INTERP
+// CHECK-NEXT:   Offset: [[INTERPOFFSET]]
+// CHECK-NEXT:   VirtualAddress: [[INTERPADDR]]
+// CHECK-NEXT:   PhysicalAddress: [[INTERPADDR]]
+// CHECK-NEXT:   FileSize: [[INTERPSIZE]]
+// CHECK-NEXT:   MemSize: [[INTERPSIZE]]
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: 1
+// CHECK-NEXT: }
+// CHECK:        Type: PT_DYNAMIC
+// CHECK-NEXT:   Offset: [[OFFSET]]
+// CHECK-NEXT:   VirtualAddress: [[ADDR]]
+// CHECK-NEXT:   PhysicalAddress: [[ADDR]]
+// CHECK-NEXT:   FileSize: [[SIZE]]
+// CHECK-NEXT:   MemSize: [[SIZE]]
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R
+// CHECK-NEXT:     PF_W
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: [[ALIGN]]
+// CHECK-NEXT: }
+
+// CHECK:      HashTable {
+// CHECK-NEXT:   Num Buckets: 4
+// CHECK-NEXT:   Num Chains: 4
+// CHECK-NEXT:   Buckets: [3, 0, 2, 0]
+// CHECK-NEXT:   Chains: [0, 0, 0, 1]
+// CHECK-NEXT: }
+
+.global _start
+_start:
+.long bar@GOT
+.long zed@GOT
diff --git a/test/ELF/soname.s b/test/ELF/soname.s
new file mode 100644 (file)
index 0000000..65e95ce
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -soname=bar -o %t.so
+// RUN: ld.lld %t.o -shared --soname=bar -o %t2.so
+// RUN: ld.lld %t.o %t.so %t2.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+// CHECK:  0x0000000000000001 NEEDED               SharedLibrary (bar)
+// CHECK-NOT: NEEDED
+
+.global _start
+_start:
diff --git a/test/ELF/soname2.s b/test/ELF/soname2.s
new file mode 100644 (file)
index 0000000..d446766
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -soname=foo.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+// CHECK: 0x000000000000000E SONAME  LibrarySoname (foo.so)
+
+.global _start
+_start:
diff --git a/test/ELF/splitstacks.s b/test/ELF/splitstacks.s
new file mode 100644 (file)
index 0000000..6506b48
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s
+# CHECK: objects using splitstacks are not supported
+
+.globl _start
+_start:
+ nop
+
+.section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/start-lib-comdat.s b/test/ELF/start-lib-comdat.s
new file mode 100644 (file)
index 0000000..ce03959
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/start-lib-comdat.s -o %t2.o
+// RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o --end-lib
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// RUN: ld.lld -shared -o %t3 --start-lib %t2.o --end-lib %t1.o
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+
+// CHECK:      Name: zed
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Other:
+// CHECK-NEXT: Section: Undefined
+
+        call bar@plt
+// The other file also has a section in the zed comdat, but it defines the
+// symbol zed. That means that we will have a lazy symbol zed, but when adding
+// the actual file zed will be undefined.
+        .section        .sec,"aG",@progbits,zed,comdat
diff --git a/test/ELF/start-lib.s b/test/ELF/start-lib.s
new file mode 100644 (file)
index 0000000..013a2b2
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/start-lib1.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/start-lib2.s -o %t3.o
+
+// RUN: ld.lld -o %t3 %t1.o %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s
+// TEST1: Name: bar
+// TEST1: Name: foo
+
+// RUN: ld.lld -o %t3 %t1.o -u bar --start-lib %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s
+// TEST2: Name: bar
+// TEST2-NOT: Name: foo
+
+// RUN: ld.lld -o %t3 %t1.o --start-lib %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s
+// TEST3-NOT: Name: bar
+// TEST3-NOT: Name: foo
+
+.globl _start
+_start:
diff --git a/test/ELF/startstop-gccollect.s b/test/ELF/startstop-gccollect.s
new file mode 100644 (file)
index 0000000..b0cd413
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Default run: sections foo and bar exist in output
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+
+## Check that foo and bar sections are not garbage collected,
+## we do not want to reclaim sections if they can be referred
+## by __start_* and __stop_* symbols.
+# RUN: ld.lld %t --gc-sections -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+
+# DISASM:      _start:
+# DISASM-NEXT:    11000:       90      nop
+# DISASM-NEXT: Disassembly of section foo:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:    11001:       90      nop
+# DISASM-NEXT: Disassembly of section bar:
+# DISASM-NEXT: bar:
+# DISASM-NEXT:    11002:       90      nop
+
+.global _start
+.text
+_start:
+ nop
+
+.section foo,"ax"
+ nop
+
+.section bar,"ax"
+ nop
diff --git a/test/ELF/startstop-shared.s b/test/ELF/startstop-shared.s
new file mode 100644 (file)
index 0000000..77411f3
--- /dev/null
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -t %t.so | FileCheck  %s
+
+        .data
+        .quad __start_foo
+        .section foo,"aw"
+// By default the symbol is hidden.
+// CHECK:      R_X86_64_RELATIVE - 0x[[ADDR1:.*]]
+
+        .hidden __start_bar
+        .quad __start_bar
+        .section bar,"a"
+// References do not affect the visibility.
+// CHECK:      R_X86_64_RELATIVE - 0x[[ADDR2:.*]]
+
+// CHECK:      Name: __start_bar
+// CHECK-NEXT: Value: 0x[[ADDR2]]
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local
+
+// CHECK:      Name: __start_foo
+// CHECK-NEXT: Value: 0x[[ADDR1]]
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local
diff --git a/test/ELF/startstop.s b/test/ELF/startstop.s
new file mode 100644 (file)
index 0000000..a7b2e43
--- /dev/null
@@ -0,0 +1,75 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+// RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s
+
+// DISASM: _start:
+// DISASM:    1000:       {{.*}}  callq   10
+// DISASM:    1005:       {{.*}}  callq   8
+// DISASM:    100a:       {{.*}}  callq   3
+// DISASM: Disassembly of section foo:
+// DISASM: __start_foo:
+// DISASM:    100f:       90      nop
+// DISASM:    1010:       90      nop
+// DISASM:    1011:       90      nop
+// DISASM: Disassembly of section bar:
+// DISASM: __start_bar:
+// DISASM:    1012:       90      nop
+// DISASM:    1013:       90      nop
+// DISASM:    1014:       90      nop
+
+
+// SYMBOL:      Relocations [
+// SYMBOL-NEXT:   Section ({{.*}}) .rela.dyn {
+// SYMBOL-NEXT:     0x3000 R_X86_64_RELATIVE - 0x3020
+// SYMBOL-NEXT:     0x3008 R_X86_64_RELATIVE - 0x3021
+// SYMBOL-NEXT:     0x3010 R_X86_64_RELATIVE - 0x3010
+// SYMBOL-NEXT:     0x3018 R_X86_64_RELATIVE - 0x3011
+// SYMBOL-NEXT:   }
+// SYMBOL-NEXT: ]
+
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_bar
+// SYMBOL:   Value: 0x1012
+// SYMBOL:   Section: bar
+// SYMBOL: }
+// SYMBOL-NOT:   Section: __stop_bar
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_foo
+// SYMBOL:   Value: 0x100F
+// SYMBOL:   Section: foo
+// SYMBOL: }
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __stop_foo
+// SYMBOL:   Value: 0x1012
+// SYMBOL:   Section: foo
+// SYMBOL: }
+
+.hidden __start_foo
+.hidden __stop_foo
+.hidden __start_bar
+.global _start
+.text
+_start:
+       call __start_foo
+       call __stop_foo
+       call __start_bar
+
+.section foo,"ax"
+       nop
+       nop
+       nop
+
+.section bar,"ax"
+       nop
+       nop
+       nop
+
+.section zed1, "aw"
+        .quad __stop_zed2
+        .quad __stop_zed2 + 1
+
+.section zed2, "aw"
+        .quad __stop_zed1
+        .quad __stop_zed1 + 1
diff --git a/test/ELF/string-gc.s b/test/ELF/string-gc.s
new file mode 100644 (file)
index 0000000..e7f86a1
--- /dev/null
@@ -0,0 +1,73 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t --gc-sections
+// RUN: llvm-readobj -symbols %t | FileCheck %s
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: s3
+// CHECK-NEXT:     Value: 0x10125
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .rodata (0x1)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: s1
+// CHECK-NEXT:     Value: 0x10120
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rodata (0x1)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: Function (0x2)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text (0x2)
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.text
+.globl _start
+.type _start,@function
+_start:
+movl $s1, %eax
+movl $s3, %eax
+
+.hidden s1
+.type s1,@object
+.section .rodata.str1.1,"aMS",@progbits,1
+.globl s1
+s1:
+.asciz "abcd"
+
+.hidden s2
+.type s2,@object
+.globl s2
+s2:
+.asciz "efgh"
+
+.type s3,@object
+s3:
+.asciz "ijkl"
+
+.type s4,@object
+.globl s4
+s4:
+.asciz "mnop"
diff --git a/test/ELF/string-table.s b/test/ELF/string-table.s
new file mode 100644 (file)
index 0000000..892c348
--- /dev/null
@@ -0,0 +1,80 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.section        foobar,"",@progbits,unique,1
+.section        foobar,"T",@progbits,unique,2
+.section        foobar,"",@nobits,unique,3
+.section        foobar,"",@nobits,unique,4
+
+.section bar, "a"
+
+// Both sections are in the output and that the alloc section is first:
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:  SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x10120
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_TLS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+
+// CHECK-NOT:  Name: foobar
+
+// Test that the string "bar" is merged into "foobar".
+
+// CHECK:       Section {
+// CHECK:       Index:
+// CHECK:       Name: .shstrtab
+// CHECK-NEXT:  Type: SHT_STRTAB
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x0
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:  Size:
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 1
+// CHECK-NEXT:  EntrySize: 0
+// CHECK-NEXT:  SectionData (
+// CHECK-NEXT:    0000: 00626172 002E7465 78740066 6F6F6261  |.bar..text.fooba|
+// CHECK-NEXT:    0010: 72002E73 796D7461 62002E73 68737472  |r..symtab..shstr|
+// CHECK-NEXT:    0020: 74616200 2E737472 74616200           |tab..strtab.|
+// CHECK-NEXT:  )
+// CHECK-NEXT:}
+// CHECK:        Name: .strtab
+// CHECK-NEXT:   Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:   Flags [ (0x0)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: 0x0
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Size: 15
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: 1
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT:   SectionData (
+// CHECK-NEXT:     0000: 00666F6F 62617200 5F737461 727400 |.foobar._start.|
+// CHECK-NEXT:   )
+// CHECK-NEXT: }
diff --git a/test/ELF/strip-all.s b/test/ELF/strip-all.s
new file mode 100644 (file)
index 0000000..f322119
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
+#BEFORE:       .symtab
+#BEFORE-NEXT:  .shstrtab
+#BEFORE-NEXT:  .strtab
+
+#RUN: ld.lld %t.o --strip-all -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
+#AFTER-NOT: .symtab
+#AFTER:     .shstrtab
+#AFTER-NOT: .strtab
+
+# Ignore --strip-all if -r is specified
+#RUN: ld.lld %t.o --strip-all -r -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
+
+# Test alias -s
+#RUN: ld.lld %t.o -s -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/strip-debug.s b/test/ELF/strip-debug.s
new file mode 100644 (file)
index 0000000..81f7572
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -g %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=DEFAULT %s
+# RUN: ld.lld %t -o %t2 --strip-debug
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+# RUN: ld.lld %t -o %t2 -S
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+# RUN: ld.lld %t -o %t2 --strip-all
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+
+# DEFAULT: Name: .debug_info
+# DEFAULT: Name: .debug_abbrev
+# DEFAULT: Name: .debug_aranges
+# DEFAULT: Name: .debug_line
+
+# STRIP-NOT: Name: .debug_info
+# STRIP-NOT: Name: .debug_abbrev
+# STRIP-NOT: Name: .debug_aranges
+# STRIP-NOT: Name: .debug_line
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/symbol-override.s b/test/ELF/symbol-override.s
new file mode 100644 (file)
index 0000000..487885b
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/symbol-override.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t1.o %t2.so -o %t
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: do
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.text
+.globl foo
+.type foo,@function
+foo:  
+nop
+
+.text
+.globl _start
+_start:
+callq do@plt
diff --git a/test/ELF/symbols.s b/test/ELF/symbols.s
new file mode 100644 (file)
index 0000000..a6c838c
--- /dev/null
@@ -0,0 +1,188 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -symbols -sections %t2 | FileCheck %s
+// REQUIRES: x86
+
+.type _start, @function
+.globl _start
+_start:
+
+.type foo, @object
+.weak foo
+foo:
+
+.type bar, @object
+.weak bar
+.long bar
+
+.section        foobar,"a",@nobits,unique,1
+.globl zed
+zed:
+        .long 0
+.globl zed2
+zed2:
+.long 0
+
+.section        foobar,"a",@nobits,unique,2
+.globl zed3
+.size zed3, 4
+zed3:
+
+.globl abs
+abs = 0x123
+
+.comm common,4,4
+
+.global protected
+.protected protected
+protected:
+
+.global hidden
+.hidden hidden
+hidden:
+
+.global internal
+.internal internal
+internal:
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x10158
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1100
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:     Name: hidden
+// CHECK-NEXT:     Value: 0x10160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: internal
+// CHECK-NEXT:     Value: 0x10160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x1)
+// CHECK-NEXT:       STV_INTERNAL
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: abs
+// CHECK-NEXT:     Value: 0x123
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Absolute
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak (0x2)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: common
+// CHECK-NEXT:     Value: 0x12000
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .bss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak (0x2)
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value: 0x10160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed
+// CHECK-NEXT:     Value: 0x10158
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed2
+// CHECK-NEXT:     Value: 0x1015C
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed3
+// CHECK-NEXT:     Value: 0x10160
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/sysroot.s b/test/ELF/sysroot.s
new file mode 100644 (file)
index 0000000..38fd8cd
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: mkdir -p %t/lib
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t/m.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:     %p/Inputs/libsearch-st.s -o %t/st.o
+// RUN: rm -f %t/lib/libls.a
+// RUN: llvm-ar rcs %t/lib/libls.a %t/st.o
+// REQUIRES: x86
+
+// Should not link because of undefined symbol _bar
+// RUN: not ld.lld -o %t/r %t/m.o 2>&1 \
+// RUN:     | FileCheck --check-prefix=UNDEFINED %s
+// UNDEFINED: undefined symbol: _bar
+
+// We need to be sure that there is no suitable library in the /lib directory
+// RUN: not ld.lld -o %t/r %t/m.o -L/lib -l:libls.a 2>&1 \
+// RUN:     | FileCheck --check-prefix=NOLIB %s
+// NOLIB: unable to find library -l:libls.a
+
+// Should just remove the '=' symbol if --sysroot is not specified.
+// Case 1: relative path
+// RUN: cd %t && ld.lld -o %t/r %t/m.o -L=lib -l:libls.a
+// Case 2: absolute path
+// RUN: cd %p && ld.lld -o %t/r %t/m.o -L=%t/lib -l:libls.a
+
+// RUN: cd %p
+
+// Should substitute SysRoot if specified
+// RUN: ld.lld -o %t/r %t/m.o --sysroot=%t -L=lib -l:libls.a
+// RUN: ld.lld -o %t/r %t/m.o --sysroot=%t -L=/lib -l:libls.a
+
+// Should not substitute SysRoot if the directory name does not start with '='
+// RUN: not ld.lld -o %t/r %r/m.o --sysroot=%t -Llib -l:libls.a
+// RUN: not ld.lld -o %t/r %r/m.o --sysroot=%t -L/lib -l:libls.a
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/tail-merge-string-align.s b/test/ELF/tail-merge-string-align.s
new file mode 100644 (file)
index 0000000..a5d4603
--- /dev/null
@@ -0,0 +1,35 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared -O3
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        .section        .rodata.4a,"aMS",@progbits,1
+        .align 4
+        .asciz "abcdef"
+
+        .section        .rodata.4b,"aMS",@progbits,1
+        .align 4
+        .asciz "ef"
+
+        .section        .rodata.4c,"aMS",@progbits,1
+        .align 4
+        .asciz "f"
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:    61626364 65660000 6600               |abcdef..f.|
+// CHECK-NEXT: )
diff --git a/test/ELF/tls-align.s b/test/ELF/tls-align.s
new file mode 100644 (file)
index 0000000..56b404e
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+        .section        .tbss,"awT",@nobits
+        .align  8
+        .long   0
+
+// CHECK:      ProgramHeader {
+// CHECK:        Type: PT_TLS
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   VirtualAddress:
+// CHECK-NEXT:   PhysicalAddress:
+// CHECK-NEXT:   FileSize: 0
+// CHECK-NEXT:   MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R (0x4)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: 8
+// CHECK-NEXT: }
diff --git a/test/ELF/tls-archive.s b/test/ELF/tls-archive.s
new file mode 100644 (file)
index 0000000..9a88fdd
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2
+// RUN: rm -f %t.a
+// RUN: llvm-ar cru %t.a %t2
+// RUN: ld.lld %t.a %t -o %t3
+
+.globl _start,tlsvar
+_start:
+  movq tlsvar@GOTTPOFF(%rip),%rdx
diff --git a/test/ELF/tls-dynamic-i686.s b/test/ELF/tls-dynamic-i686.s
new file mode 100644 (file)
index 0000000..4db6278
--- /dev/null
@@ -0,0 +1,100 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.type  tls2,@object
+.globl tls2
+.hidden tls2
+.align 4
+tls2:
+ .long 0
+ .size tls2, 4
+
+.section .text
+.globl _start
+_start:
+leal tls0@tlsgd(,%ebx,1),%eax
+call __tls_get_addr@plt
+
+leal tls1@tlsgd(,%ebx,1),%eax
+call __tls_get_addr@plt
+
+leal tls2@tlsldm(%ebx),%eax
+call __tls_get_addr@plt
+leal tls2@dtpoff(%eax),%edx
+
+leal tls2@tlsldm(%ebx),%eax
+call __tls_get_addr@plt
+leal tls2@dtpoff(%eax),%edx
+
+movl %gs:0,%eax
+addl tls0@gotntpoff(%ebx),%eax
+
+movl %gs:0,%eax
+addl tls1@gotntpoff(%ebx),%eax
+
+// CHECK:      Index: 10
+// CHECK-NEXT: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2068
+// CHECK-NEXT: Offset: 0x2068
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+
+// CHECK: Relocations [
+// CHECK:      Section ({{.+}}) .rel.dyn {
+// CHECK-NEXT: 0x2078 R_386_TLS_DTPMOD32 - 0x0
+// CHECK-NEXT: 0x2068 R_386_TLS_DTPMOD32 tls0 0x0
+// CHECK-NEXT: 0x206C R_386_TLS_DTPOFF32 tls0 0x0
+// CHECK-NEXT: 0x2080 R_386_TLS_TPOFF tls0 0x0
+// CHECK-NEXT: 0x2070 R_386_TLS_DTPMOD32 tls1 0x0
+// CHECK-NEXT: 0x2074 R_386_TLS_DTPOFF32 tls1 0x0
+// CHECK-NEXT: 0x2084 R_386_TLS_TPOFF tls1 0x0
+// CHECK-NEXT: }
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: _start:
+// General dynamic model:
+// -32 and -24 are first and second GOT entries offsets.
+// Each one is a pair of records.
+// DIS-NEXT: 1000: 8d 04 1d e0 ff ff ff  leal -32(,%ebx), %eax
+// DIS-NEXT: 1007: e8 64 00 00 00        calll 100
+// DIS-NEXT: 100c: 8d 04 1d e8 ff ff ff  leal -24(,%ebx), %eax
+// DIS-NEXT: 1013: e8 58 00 00 00        calll 88
+// Local dynamic model:
+// -16 is a local module tls index offset.
+// DIS-NEXT: 1018: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 101e: e8 4d 00 00 00    calll 77
+// DIS-NEXT: 1023: 8d 90 08 00 00 00 leal 8(%eax), %edx
+// DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 102f: e8 3c 00 00 00    calll 60
+// DIS-NEXT: 1034: 8d 90 08 00 00 00 leal 8(%eax), %edx
+// Initial exec model:
+// DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DIS-NEXT: 1046: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 104c: 03 83 fc ff ff ff addl -4(%ebx), %eax
diff --git a/test/ELF/tls-dynamic.s b/test/ELF/tls-dynamic.s
new file mode 100644 (file)
index 0000000..b627977
--- /dev/null
@@ -0,0 +1,87 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+  leaq  a@tlsld(%rip), %rdi
+  callq __tls_get_addr@PLT
+  leaq  b@tlsld(%rip), %rdi
+  callq __tls_get_addr@PLT
+  leaq  a@dtpoff(%rax), %rcx
+  leaq  b@dtpoff(%rax), %rcx
+  .long b@dtpoff, 0
+  leaq  c@tlsgd(%rip), %rdi
+  rex64
+  callq __tls_get_addr@PLT
+  leaq  a@dtpoff(%rax), %rcx
+  // Initial Exec Model Code Sequence, II
+  movq c@gottpoff(%rip),%rax
+  movq %fs:(%rax),%rax
+  movabs $a@dtpoff, %rax
+  movabs $b@dtpoff, %rax
+  movabs $a@dtpoff, %rax
+
+  .global a
+  .hidden a
+  .section .tbss,"awT",@nobits
+  .align 4
+a:
+  .long 0
+
+  .section .tbss,"awT",@nobits
+  .align 4
+b:
+  .long 0
+  .global c
+  .section .tbss,"awT",@nobits
+  .align 4
+c:
+  .long 0
+
+// Get the address of the got, and check that it has 4 entries.
+
+// CHECK:      Sections [
+// CHECK:          Name: .got
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x20D0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 40
+
+// CHECK:      Relocations [
+// CHECK:        Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT:     0x20D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT:     0x20E0 R_X86_64_DTPMOD64 c 0x0
+// CHECK-NEXT:     0x20E8 R_X86_64_DTPOFF64 c 0x0
+// CHECK-NEXT:     0x20F0 R_X86_64_TPOFF64 c 0x0
+// CHECK-NEXT:   }
+
+// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry.
+// 4285 = (0x20D0 + -4) - (0x100c + 3) // PC relative offset to got entry.
+// 4267 = (0x20E0 + -4) - (0x102e + 3) // PC relative offset to got entry.
+// 4263 = (0x20F0 + -4) - (0x1042 + 3) // PC relative offset to got entry.
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: .text:
+// DIS-NEXT:     1000: {{.+}} leaq    4297(%rip), %rdi
+// DIS-NEXT:     1007: {{.+}} callq
+// DIS-NEXT:     100c: {{.+}} leaq    4285(%rip), %rdi
+// DIS-NEXT:     1013: {{.+}} callq
+// DIS-NEXT:     1018: {{.+}} leaq    (%rax), %rcx
+// DIS-NEXT:     101f: {{.+}} leaq    4(%rax), %rcx
+// DIS-NEXT:     1026: 04 00
+// DIS-NEXT:     1028: 00 00
+// DIS-NEXT:     102a: 00 00
+// DIS-NEXT:     102c: 00 00
+// DIS-NEXT:     102e: {{.+}} leaq    4267(%rip), %rdi
+// DIS-NEXT:     1035: {{.+}} callq
+// DIS-NEXT:     103b: {{.+}} leaq    (%rax), %rcx
+// DIS-NEXT:     1042: {{.+}} movq    4263(%rip), %rax
+// DIS-NEXT:     1049: {{.+}} movq    %fs:(%rax), %rax
+// DIS-NEXT:     104d: {{.+}} movabsq $0, %rax
+// DIS-NEXT:     1057: {{.+}} movabsq $4, %rax
+// DIS-NEXT:     1061: {{.+}} movabsq $0, %rax
diff --git a/test/ELF/tls-error.s b/test/ELF/tls-error.s
new file mode 100644 (file)
index 0000000..b617899
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+// CHECK: R_X86_64_TPOFF32 out of range
+
+.global _start
+_start:
+        movl %fs:a@tpoff, %eax
+.global a
+.section        .tbss,"awT",@nobits
+a:
+.zero 0x80000001
diff --git a/test/ELF/tls-got-entry.s b/test/ELF/tls-got-entry.s
new file mode 100644 (file)
index 0000000..c7b9669
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got-entry.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck %s
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_TPOFF64 tlsshared0 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.globl _start
+_start:
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
diff --git a/test/ELF/tls-got.s b/test/ELF/tls-got.s
new file mode 100644 (file)
index 0000000..f36d94e
--- /dev/null
@@ -0,0 +1,58 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -e main %t1.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Section {
+// CHECK:      Index: 8
+// CHECK-NEXT: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[ADDR:.*]]
+// CHECK-NEXT: Offset: 0x20B0
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: }
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x120B8 R_X86_64_TPOFF64 tls0 0x0
+// CHECK-NEXT:     [[ADDR]] R_X86_64_TPOFF64 tls1 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+//0x11000 + 4249 + 7 = 0x120B0
+//0x1100A + 4247 + 7 = 0x120B8
+//0x11014 + 4237 + 7 = 0x120B8
+//DISASM:      Disassembly of section .text:
+//DISASM-NEXT: main:
+//DISASM-NEXT: 11000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax
+//DISASM-NEXT: 11007: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 1100a: 48 8b 05 a7 10 00 00 movq 4263(%rip), %rax
+//DISASM-NEXT: 11011: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 11014: 48 8b 05 9d 10 00 00 movq 4253(%rip), %rax
+//DISASM-NEXT: 1101b: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 1101e: c3 retq
+
+.section .tdata,"awT",@progbits
+
+.text
+ .globl main
+ .align 16, 0x90
+ .type main,@function
+main:
+ movq tls1@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ movq tls0@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ movq tls0@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ ret
diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s
new file mode 100644 (file)
index 0000000..2a04a55
--- /dev/null
@@ -0,0 +1,69 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: ld.lld %t -shared -o %tsharedout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+// RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
+// RUN: llvm-objdump -d %tsharedout | FileCheck %s --check-prefix=DISSHARED
+// RUN: llvm-readobj -r %tsharedout | FileCheck %s --check-prefix=RELOCSHARED
+
+.section ".tdata", "awT", @progbits
+.globl var
+.globl var1
+var:
+.long 0
+var1:
+.long 1
+
+.section test, "awx"
+.global _start
+_start:
+ movl $var@tpoff, %edx
+ movl %gs:0, %ecx
+ subl %edx, %eax
+ movl $var1@tpoff, %edx
+ movl %gs:0, %ecx
+ subl %edx, %eax
+
+ movl %gs:0, %ecx
+ leal var@ntpoff(%ecx), %eax
+ movl %gs:0, %ecx
+ leal var1@ntpoff+123(%ecx), %eax
+
+// DIS:      Disassembly of section test:
+// DIS-NEXT: _start:
+// DIS-NEXT: 12000: ba 08 00 00 00       movl $8, %edx
+// DIS-NEXT: 12005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 1200c: 29 d0                subl %edx, %eax
+// DIS-NEXT: 1200e: ba 04 00 00 00       movl $4, %edx
+// DIS-NEXT: 12013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 1201a: 29 d0                subl %edx, %eax
+// DIS-NEXT: 1201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 12023: 8d 81 f8 ff ff ff    leal -8(%ecx), %eax
+// DIS-NEXT: 12029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 12030: 8d 81 77 00 00 00    leal 119(%ecx), %eax
+
+// RELOC: Relocations [
+// RELOC-NEXT: ]
+
+// DISSHARED: Disassembly of section test:
+// DISSHARED-NEXT: _start:
+// DISSHARED-NEXT: 2000: ba 00 00 00 00 movl   $0, %edx
+// DISSHARED-NEXT: 2005: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 200c: 29 d0 subl            %edx, %eax
+// DISSHARED-NEXT: 200e: ba 00 00 00 00        movl $0, %edx
+// DISSHARED-NEXT: 2013: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 201a: 29 d0 subl            %edx, %eax
+// DISSHARED-NEXT: 201c: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 2023: 8d 81 00 00 00 00     leal (%ecx), %eax
+// DISSHARED-NEXT: 2029: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 2030: 8d 81 7b 00 00 00     leal 123(%ecx), %eax
+
+// RELOCSHARED:      Relocations [
+// RELOCSHARED-NEXT: Section (4) .rel.dyn {
+// RELOCSHARED-NEXT:   0x2001 R_386_TLS_TPOFF32 var 0x0
+// RELOCSHARED-NEXT:   0x2025 R_386_TLS_TPOFF var 0x0
+// RELOCSHARED-NEXT:   0x200F R_386_TLS_TPOFF32 var1 0x0
+// RELOCSHARED-NEXT:   0x2032 R_386_TLS_TPOFF var1 0x0
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT: ]
diff --git a/test/ELF/tls-in-archive.s b/test/ELF/tls-in-archive.s
new file mode 100644 (file)
index 0000000..71f60e3
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-in-archive.s -o %t1.o
+// RUN: llvm-ar cru %t.a %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.a -o %tout
+
+        .globl  _start
+_start:
+        movq    foo@gottpoff(%rip), %rax
+        .section        .tbss,"awT",@nobits
+        .weak   foo
diff --git a/test/ELF/tls-initial-exec-local.s b/test/ELF/tls-initial-exec-local.s
new file mode 100644 (file)
index 0000000..0aef3c8
--- /dev/null
@@ -0,0 +1,36 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t
+// RUN: llvm-readobj -r -s %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2090 R_X86_64_TPOFF64 - 0x0
+// CHECK-NEXT:     0x2098 R_X86_64_TPOFF64 - 0x4
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 0x1007 + 4233 = 0x2090
+// 0x100e + 4234 = 0x2098
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: .text:
+// DISASM-NEXT:  1000: {{.*}} addq      4233(%rip), %rax
+// DISASM-NEXT:  1007: {{.*}} addq      4234(%rip), %rax
+
+        addq    foo@GOTTPOFF(%rip), %rax
+        addq    bar@GOTTPOFF(%rip), %rax
+
+        .section        .tbss,"awT",@nobits
+foo:
+        .long 0
+bar:
+        .long 0
diff --git a/test/ELF/tls-mismatch.s b/test/ELF/tls-mismatch.s
new file mode 100644 (file)
index 0000000..fb70229
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2
+// RUN: not ld.lld %t %t2 -o %t3 2>&1 | FileCheck %s
+// CHECK: TLS attribute mismatch for symbol: tlsvar
+
+.globl _start,tlsvar
+_start:
+  movl tlsvar,%edx
diff --git a/test/ELF/tls-offset.s b/test/ELF/tls-offset.s
new file mode 100644 (file)
index 0000000..8f5a46d
--- /dev/null
@@ -0,0 +1,56 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -s %tout | FileCheck %s
+
+        .global _start
+_start:
+        retq
+
+        .section        .tdata,"awT",@progbits
+        .align  4
+        .long   42
+
+        .section        .tbss,"awT",@nobits
+        .align  16
+        .zero 16
+
+        .data
+        .long 1
+
+
+// Test that .tbss doesn't show up in the offset or in the address. If this
+// gets out of sync what we get a runtime is different from what the section
+// table says.
+
+// CHECK:      Name: .tdata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_TLS
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 4
+
+// CHECK:      Name: .tbss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_TLS
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12010
+// CHECK-NEXT: Offset: 0x2004
+// CHECK-NEXT: Size: 16
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12004
+// CHECK-NEXT: Offset: 0x2004
+// CHECK-NEXT: Size: 4
diff --git a/test/ELF/tls-opt-gdie.s b/test/ELF/tls-opt-gdie.s
new file mode 100644 (file)
index 0000000..6ed370e
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-opt-gdie.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t1
+// RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=RELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+//RELOC:      Section {
+//RELOC:      Index:
+//RELOC:      Name: .got
+//RELOC-NEXT: Type: SHT_PROGBITS
+//RELOC-NEXT: Flags [
+//RELOC-NEXT:   SHF_ALLOC
+//RELOC-NEXT:   SHF_WRITE
+//RELOC-NEXT: ]
+//RELOC-NEXT: Address: 0x120B0
+//RELOC-NEXT: Offset: 0x20B0
+//RELOC-NEXT: Size: 16
+//RELOC-NEXT: Link: 0
+//RELOC-NEXT: Info: 0
+//RELOC-NEXT: AddressAlignment: 8
+//RELOC-NEXT: EntrySize: 0
+//RELOC-NEXT: }
+//RELOC:      Relocations [
+//RELOC-NEXT:   Section (4) .rela.dyn {
+//RELOC-NEXT:     0x120B0 R_X86_64_TPOFF64 tlsshared0 0x0
+//RELOC-NEXT:     0x120B8 R_X86_64_TPOFF64 tlsshared1 0x0
+//RELOC-NEXT:   }
+//RELOC-NEXT: ]
+
+//0x11009 + (4256 + 7) = 0x120B0
+//0x11019 + (4248 + 7) = 0x120B8
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: {{.*}} movq %fs:0, %rax
+// DISASM-NEXT: 11009: {{.*}} addq 4256(%rip), %rax
+// DISASM-NEXT: 11010: {{.*}} movq %fs:0, %rax
+// DISASM-NEXT: 11019: {{.*}} addq 4248(%rip), %rax
+
+.section .text
+.globl _start
+_start:
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tlsshared1@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
diff --git a/test/ELF/tls-opt-gdiele-i686.s b/test/ELF/tls-opt-gdiele-i686.s
new file mode 100644 (file)
index 0000000..1432a96
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-gdiele-i686.s -o %tso.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %tout
+// RUN: llvm-readobj -r %tout | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
+// NORELOC-NEXT:   0x12058 R_386_TLS_TPOFF tlsshared0 0x0
+// NORELOC-NEXT:   0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// NORELOC-NEXT:   }
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11006: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DISASM-NEXT: 1100c: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11012: 03 83 fc ff ff ff addl -4(%ebx), %eax
+// DISASM-NEXT: 11018: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 1101e: 81 e8 08 00 00 00 subl $8, %eax
+// DISASM-NEXT: 11024: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 1102a: 81 e8 04 00 00 00 subl $4, %eax
+
+.type tlsexe1,@object
+.section .tbss,"awT",@nobits
+.globl tlsexe1
+.align 4
+tlsexe1:
+ .long 0
+ .size tlsexe1, 4
+
+.type tlsexe2,@object
+.section .tbss,"awT",@nobits
+.globl tlsexe2
+.align 4
+tlsexe2:
+ .long 0
+ .size tlsexe2, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+//GD->IE
+leal tlsshared0@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+leal tlsshared1@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+//GD->IE
+leal tlsexe1@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+leal tlsexe2@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
diff --git a/test/ELF/tls-opt-i686.s b/test/ELF/tls-opt-i686.s
new file mode 100644 (file)
index 0000000..dec45b4
--- /dev/null
@@ -0,0 +1,69 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// LD -> LE:
+// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11006: 90                nop
+// DISASM-NEXT: 11007: 8d 74 26 00       leal (%esi), %esi
+// DISASM-NEXT: 1100b: 8d 90 f8 ff ff ff leal -8(%eax), %edx
+// DISASM-NEXT: 11011: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11017: 90                nop
+// DISASM-NEXT: 11018: 8d 74 26 00       leal (%esi), %esi
+// DISASM-NEXT: 1101c: 8d 90 fc ff ff ff leal -4(%eax), %edx
+// IE -> LE:
+// 4294967288 == 0xFFFFFFF8
+// 4294967292 == 0xFFFFFFFC
+// DISASM-NEXT: 11022: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11028: c7 c0 f8 ff ff ff  movl $4294967288, %eax
+// DISASM-NEXT: 1102e: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11034: c7 c0 fc ff ff ff  movl $4294967292, %eax
+// DISASM-NEXT: 1103a: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11040: 8d 80 f8 ff ff ff  leal -8(%eax), %eax
+// DISASM-NEXT: 11046: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 1104c: 8d 80 fc ff ff ff  leal -4(%eax), %eax
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+//LD -> LE:
+leal tls0@tlsldm(%ebx),%eax
+call ___tls_get_addr@plt
+leal tls0@dtpoff(%eax),%edx
+leal tls1@tlsldm(%ebx),%eax
+call ___tls_get_addr@plt
+leal tls1@dtpoff(%eax),%edx
+//IE -> LE:
+movl %gs:0,%eax
+movl tls0@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+movl tls1@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+addl tls0@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+addl tls1@gotntpoff(%ebx),%eax
diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s
new file mode 100644 (file)
index 0000000..b6608c1
--- /dev/null
@@ -0,0 +1,100 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %t1
+// RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=GOTREL %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// GOTREL:      Section {
+// GOTREL:        Index:
+// GOTREL:        Name: .got
+// GOTREL-NEXT:   Type: SHT_PROGBITS
+// GOTREL-NEXT:   Flags [
+// GOTREL-NEXT:     SHF_ALLOC
+// GOTREL-NEXT:     SHF_WRITE
+// GOTREL-NEXT:   ]
+// GOTREL-NEXT:   Address: 0x12058
+// GOTREL-NEXT:   Offset: 0x2058
+// GOTREL-NEXT:   Size: 8
+// GOTREL-NEXT:   Link: 0
+// GOTREL-NEXT:   Info: 0
+// GOTREL-NEXT:   AddressAlignment: 4
+// GOTREL-NEXT:   EntrySize: 0
+// GOTREL-NEXT: }
+// GOTREL:      Relocations [
+// GOTREL-NEXT: Section ({{.*}}) .rel.dyn {
+// GOTREL-NEXT:   0x12058 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTREL-NEXT:   0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// GOTREL-NEXT:  }
+// GOTREL-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// 4294967288 = 0xFFFFFFF8
+// 4294967292 = 0xFFFFFFFC
+// 73808 = (.got)[0] = 0x12058
+// 73812 = (.got)[1] = 0x1205C
+// DISASM-NEXT: 11000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
+// DISASM-NEXT: 11006: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11009: b8 f8 ff ff ff    movl $4294967288, %eax
+// DISASM-NEXT: 1100e: 65 8b 00          movl %gs:(%eax), %eax
+// DISASM-NEXT: 11011: 81 c1 f8 ff ff ff addl $4294967288, %ecx
+// DISASM-NEXT: 11017: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1101a: c7 c1 fc ff ff ff movl $4294967292, %ecx
+// DISASM-NEXT: 11020: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11023: b8 fc ff ff ff    movl $4294967292, %eax
+// DISASM-NEXT: 11028: 65 8b 00          movl %gs:(%eax), %eax
+// DISASM-NEXT: 1102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
+// DISASM-NEXT: 11031: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11034: 8b 0d 58 20 01 00 movl 73816, %ecx
+// DISASM-NEXT: 1103a: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1103d: 03 0d 5c 20 01 00 addl 73820, %ecx
+// DISASM-NEXT: 11043: 65 8b 01          movl %gs:(%ecx), %eax
+
+.type tlslocal0,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal0
+.align 4
+tlslocal0:
+ .long 0
+ .size tlslocal0, 4
+
+.type tlslocal1,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal1
+.align 4
+tlslocal1:
+ .long 0
+ .size tlslocal1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+movl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal0@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlsshared0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+addl tlsshared1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
diff --git a/test/ELF/tls-opt-local.s b/test/ELF/tls-opt-local.s
new file mode 100644 (file)
index 0000000..d2904ac
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: 48 c7 c0 f8 ff ff ff movq $-8, %rax
+// DISASM-NEXT: 11007: 49 c7 c7 f8 ff ff ff movq $-8, %r15
+// DISASM-NEXT: 1100e: 48 8d 80 f8 ff ff ff leaq -8(%rax), %rax
+// DISASM-NEXT: 11015: 4d 8d bf f8 ff ff ff leaq -8(%r15), %r15
+// DISASM-NEXT: 1101c: 48 81 c4 f8 ff ff ff addq $-8, %rsp
+// DISASM-NEXT: 11023: 49 81 c4 f8 ff ff ff addq $-8, %r12
+// DISASM-NEXT: 1102a: 48 c7 c0 fc ff ff ff movq $-4, %rax
+// DISASM-NEXT: 11031: 49 c7 c7 fc ff ff ff movq $-4, %r15
+// DISASM-NEXT: 11038: 48 8d 80 fc ff ff ff leaq -4(%rax), %rax
+// DISASM-NEXT: 1103f: 4d 8d bf fc ff ff ff leaq -4(%r15), %r15
+// DISASM-NEXT: 11046: 48 81 c4 fc ff ff ff addq $-4, %rsp
+// DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff addq $-4, %r12
+
+.section .tbss,"awT",@nobits
+
+.type tls0,@object
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl _start
+_start:
+ movq tls0@GOTTPOFF(%rip), %rax
+ movq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rax
+ addq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rsp
+ addq tls0@GOTTPOFF(%rip), %r12
+ movq tls1@GOTTPOFF(%rip), %rax
+ movq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rax
+ addq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rsp
+ addq tls1@GOTTPOFF(%rip), %r12
diff --git a/test/ELF/tls-opt-no-plt.s b/test/ELF/tls-opt-no-plt.s
new file mode 100644 (file)
index 0000000..53655d0
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-opt-gdie.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s %t.exe | FileCheck %s
+
+// CHECK-NOT: .plt
+
+        .global _start
+_start:
+        data16
+        leaq    foo@TLSGD(%rip), %rdi
+        data16
+        data16
+        rex64
+        callq   __tls_get_addr@PLT
+
+        leaq    bar@TLSLD(%rip), %rdi
+        callq   __tls_get_addr@PLT
+        leaq    bar@DTPOFF(%rax), %rax
+
+        .type   bar,@object
+        .section        .tdata,"awT",@progbits
+        .align  8
+bar:
+        .long   42
+
+
+        .type   foo,@object
+        .section        .tdata,"awT",@progbits
+        .globl  foo
+        .align  8
+foo:
+        .long   42
diff --git a/test/ELF/tls-opt.s b/test/ELF/tls-opt.s
new file mode 100644 (file)
index 0000000..52468f1
--- /dev/null
@@ -0,0 +1,99 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      _start:
+// DISASM-NEXT: 11000: 48 c7 c0 f8 ff ff ff  movq $-8, %rax
+// DISASM-NEXT: 11007: 49 c7 c7 f8 ff ff ff  movq $-8, %r15
+// DISASM-NEXT: 1100e: 48 8d 80 f8 ff ff ff  leaq -8(%rax), %rax
+// DISASM-NEXT: 11015: 4d 8d bf f8 ff ff ff  leaq -8(%r15), %r15
+// DISASM-NEXT: 1101c: 48 81 c4 f8 ff ff ff  addq $-8, %rsp
+// DISASM-NEXT: 11023: 49 81 c4 f8 ff ff ff  addq $-8, %r12
+// DISASM-NEXT: 1102a: 48 c7 c0 fc ff ff ff  movq $-4, %rax
+// DISASM-NEXT: 11031: 49 c7 c7 fc ff ff ff  movq $-4, %r15
+// DISASM-NEXT: 11038: 48 8d 80 fc ff ff ff  leaq -4(%rax), %rax
+// DISASM-NEXT: 1103f: 4d 8d bf fc ff ff ff  leaq -4(%r15), %r15
+// DISASM-NEXT: 11046: 48 81 c4 fc ff ff ff  addq $-4, %rsp
+// DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff  addq $-4, %r12
+
+// LD to LE:
+// DISASM-NEXT: 11054: 66 66 66 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 11060: 48 8d 88 f8 ff ff ff                 leaq -8(%rax), %rcx
+// DISASM-NEXT: 11067: 66 66 66 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 11073: 48 8d 88 fc ff ff ff                 leaq -4(%rax), %rcx
+
+// GD to LE:
+// DISASM-NEXT: 1107a: 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 11083: 48 8d 80 f8 ff ff ff        leaq -8(%rax), %rax
+// DISASM-NEXT: 1108a: 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 11093: 48 8d 80 fc ff ff ff        leaq -4(%rax), %rax
+
+// LD to LE:
+// DISASM:     _DTPOFF64_1:
+// DISASM-NEXT: 1109a: f8 clc
+// DISASM:      _DTPOFF64_2:
+// DISASM-NEXT: 110a3: fc cld
+
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl _start
+_start:
+ movq tls0@GOTTPOFF(%rip), %rax
+ movq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rax
+ addq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rsp
+ addq tls0@GOTTPOFF(%rip), %r12
+ movq tls1@GOTTPOFF(%rip), %rax
+ movq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rax
+ addq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rsp
+ addq tls1@GOTTPOFF(%rip), %r12
+
+ // LD to LE
+ leaq tls0@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq tls0@dtpoff(%rax),%rcx
+ leaq tls1@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq tls1@dtpoff(%rax),%rcx
+
+ // GD to LE
+ .byte 0x66
+ leaq tls0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tls1@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ // LD to LE
+_DTPOFF64_1:
+ .quad tls0@DTPOFF
+ nop
+
+_DTPOFF64_2:
+ .quad tls1@DTPOFF
+ nop
diff --git a/test/ELF/tls-static.s b/test/ELF/tls-static.s
new file mode 100644 (file)
index 0000000..4c515ab
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared.s -o %tso
+// RUN: ld.lld -static %t -o %tout
+// RUN: ld.lld %t -o %tout
+// RUN: ld.lld -shared %tso -o %tshared
+// RUN: not ld.lld -static %t %tshared -o %tout 2>&1 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  call __tls_get_addr
+
+// CHECK: undefined symbol: __tls_get_addr
diff --git a/test/ELF/tls-two-relocs.s b/test/ELF/tls-two-relocs.s
new file mode 100644 (file)
index 0000000..7c5d6ab
--- /dev/null
@@ -0,0 +1,30 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-readobj -r %tout | FileCheck %s
+
+ data16
+ leaq   g_tls_s@TLSGD(%rip), %rdi
+ data16
+ data16
+ rex64
+ callq  __tls_get_addr@PLT
+
+ data16
+ leaq   g_tls_s@TLSGD(%rip), %rdi
+ data16
+ data16
+ rex64
+ callq  __tls_get_addr@PLT
+
+// Check that we handle two gd relocations to the same symbol.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_DTPMOD64 g_tls_s 0x0
+// CHECK-NEXT:     R_X86_64_DTPOFF64 g_tls_s 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rela.plt {
+// CHECK-NEXT:      R_X86_64_JUMP_SLOT __tls_get_addr 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/tls.s b/test/ELF/tls.s
new file mode 100644 (file)
index 0000000..525890b
--- /dev/null
@@ -0,0 +1,170 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -symbols -sections -program-headers %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+.global _start
+_start:
+  movl %fs:a@tpoff, %eax
+  movl %fs:b@tpoff, %eax
+  movl %fs:c@tpoff, %eax
+  movl %fs:d@tpoff, %eax
+
+  .global a
+       .section        .tbss,"awT",@nobits
+a:
+       .long   0
+
+  .global b
+       .section        .tdata,"awT",@progbits
+b:
+       .long   1
+
+  .global c
+       .section        .thread_bss,"awT",@nobits
+c:
+       .long   0
+
+  .global d
+       .section        .thread_data,"awT",@progbits
+d:
+       .long   2
+
+// CHECK:          Name: .tdata
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: [[TDATA_ADDR:0x.*]]
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .thread_data
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .tbss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: [[TBSS_ADDR:0x.*]]
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .thread_bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+
+// 0x1200C = TBSS_ADDR + 4
+
+// CHECK-NEXT:     Address: 0x1200C
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+
+// CHECK:      Symbols [
+// CHECK:          Name: a
+// CHECK-NEXT:     Value: 0x8
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tbss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: b
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tdata
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: c
+// CHECK-NEXT:     Value: 0xC
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_bss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: d
+// CHECK-NEXT:     Value: 0x4
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_data
+// CHECK-NEXT:   }
+
+// Check that the TLS NOBITS sections weren't added to the R/W PT_LOAD's size.
+
+// CHECK:      ProgramHeaders [
+// CHECK:          Type: PT_LOAD
+// CHECK:          Type: PT_LOAD
+// CHECK:          Type: PT_LOAD
+// CHECK:          FileSize: 8
+// CHECK-NEXT:     MemSize: 8
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       PF_R
+// CHECK-NEXT:       PF_W
+// CHECK-NEXT:     ]
+// CHECK:          Type: PT_TLS
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     VirtualAddress: [[TDATA_ADDR]]
+// CHECK-NEXT:     PhysicalAddress: [[TDATA_ADDR]]
+// CHECK-NEXT:     FileSize: 8
+// CHECK-NEXT:     MemSize: 16
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       PF_R
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment:
+// CHECK-NEXT:   }
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: _start:
+// DIS-NEXT:    11000: {{.+}} movl    %fs:-8, %eax
+// DIS-NEXT:    11008: {{.+}} movl    %fs:-16, %eax
+// DIS-NEXT:    11010: {{.+}} movl    %fs:-4, %eax
+// DIS-NEXT:    11018: {{.+}} movl    %fs:-12, %eax
diff --git a/test/ELF/trace-ar.s b/test/ELF/trace-ar.s
new file mode 100644 (file)
index 0000000..1d178dc
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.foo.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar1.s -o %t.obj1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar2.s -o %t.obj2.o
+# RUN: llvm-ar rcs %t.boo.a %t.obj1.o %t.obj2.o
+
+## Check how -t works with achieves
+# RUN: ld.lld %t.foo.o %t.boo.a -o %t.out -t 2>&1 | FileCheck %s
+# CHECK:      {{.*}}.foo.o
+# CHECK-NEXT: {{.*}}.boo.a({{.*}}.obj1.o)
+# CHECK-NOT:  {{.*}}.boo.a({{.*}}.obj2.o)
+
+## Test output with --start-lib
+# RUN: ld.lld %t.foo.o --start-lib %t.obj1.o %t.obj2.o -o %t.out -t 2>&1 | FileCheck --check-prefix=STARTLIB %s
+# STARTLIB:      {{.*}}.foo.o
+# STARTLIB-NEXT: {{.*}}.obj1.o
+# STARTLIB-NOT:  {{.*}}.obj2.o
+
+.globl _start, _used
+_start:
+ call _used
diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s
new file mode 100644 (file)
index 0000000..7f6bca8
--- /dev/null
@@ -0,0 +1,78 @@
+# Test -y symbol and -trace-symbol=symbol
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-weak.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-strong.s -o %t2
+# RUN: ld.lld -shared %t1 -o %t1.so
+# RUN: ld.lld -shared %t2 -o %t2.so
+# RUN: llvm-ar rcs %t1.a %t1
+# RUN: llvm-ar rcs %t2.a %t2
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTRFOO %s
+# OBJECTRFOO: trace-symbols.s.tmp: reference to foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTDCOMMON %s
+# OBJECTDCOMMON: trace-symbols.s.tmp1: common definition of common
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD1FOO %s
+# OBJECTD1FOO: trace-symbols.s.tmp: reference to foo
+# OBJECTD1FOO: trace-symbols.s.tmp1: common definition of common
+# OBJECTD1FOO: trace-symbols.s.tmp1: definition of foo
+# OBJECTD1FOO: trace-symbols.s.tmp2: definition of foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common --trace-symbol=hsymbol \
+# RUN:   %t %t2 %t1 -o %t4 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=OBJECTD2FOO %s
+# OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=SHLIBDCOMMON %s
+# SHLIBDCOMMON: trace-symbols.s.tmp1.so: definition of common
+
+# RUN: ld.lld -y foo -y common %t %t2.so %t1.so -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=SHLIBD2FOO %s
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=NO-SHLIBD2FOO %s
+# SHLIBD2FOO:        trace-symbols.s.tmp2.so: definition of foo
+# NO-SHLIBD2FOO-NOT: trace-symbols.s.tmp2.so: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=ARCHIVEDCOMMON %s
+# ARCHIVEDCOMMON-NOT: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of \
+# common
+
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=ARCHIVED1FOO %s
+# ARCHIVED1FOO: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of foo
+
+# RUN: ld.lld -y foo %t %t1.a %t2.a -o %t3 | \
+# RUN:   FileCheck -check-prefix=ARCHIVED2FOO %s
+# ARCHIVED2FOO: trace-symbols.s.tmp2.a(trace-symbols.s.tmp2): definition of foo
+
+# RUN: ld.lld -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=SHLIBDBAR %s
+# SHLIBDBAR: trace-symbols.s.tmp2.so: definition of bar
+
+# RUN: ld.lld -y foo -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=SHLIBRBAR %s
+# SHLIBRBAR-NOT: trace-symbols.s.tmp1.so: reference to bar
+
+# RUN: ld.lld -y foo -y bar %t -u bar --start-lib %t1 %t2 --end-lib -o %t3 | \
+# RUN:   FileCheck -check-prefix=STARTLIB %s
+# STARTLIB: trace-symbols.s.tmp1: reference to bar
+
+.hidden hsymbol
+.globl _start
+.type  _start, @function
+_start:
+call foo
diff --git a/test/ELF/trace.s b/test/ELF/trace.s
new file mode 100644 (file)
index 0000000..4374d93
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.foo.o
+
+## Check -t
+# RUN: ld.lld -shared %t.foo.o -o %t.so -t 2>&1 | FileCheck %s
+# CHECK: {{.*}}.foo.o
+
+## Check --trace alias
+# RUN: ld.lld -shared %t.foo.o -o %t.so -t 2>&1 | FileCheck %s
diff --git a/test/ELF/undef-shared.s b/test/ELF/undef-shared.s
new file mode 100644 (file)
index 0000000..ed91035
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+# CHECK: undefined symbol: hidden in {{.*}}
+.global hidden
+.hidden hidden
+
+# CHECK: undefined symbol: internal in {{.*}}
+.global internal
+.internal internal
+
+# CHECK: undefined symbol: protected in {{.*}}
+.global protected
+.protected protected
diff --git a/test/ELF/undef-start.s b/test/ELF/undef-start.s
new file mode 100644 (file)
index 0000000..bf1d898
--- /dev/null
@@ -0,0 +1,4 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+# CHECK: undefined symbol: _start
+# REQUIRES: x86
diff --git a/test/ELF/undef-version-script.s b/test/ELF/undef-version-script.s
new file mode 100644 (file)
index 0000000..9f0a5a4
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# This does not match gold's behavior because gold does not create undefined
+# symbols in dynsym without an appropriate (e.g. PLT) relocation in the input.
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar@ (1)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Weak (0x2)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo@ (5)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global foo
+.weak bar
diff --git a/test/ELF/undef-with-plt-addr-i686.s b/test/ELF/undef-with-plt-addr-i686.s
new file mode 100644 (file)
index 0000000..755f0da
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+
+.globl _start
+_start:
+mov $set_data, %eax
+
+// Test that set_data has an address in the .plt
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11010
+
+// CHECK:      Name:    set_data
+// CHECK-NEXT: Value:   0x11020
diff --git a/test/ELF/undef-with-plt-addr.s b/test/ELF/undef-with-plt-addr.s
new file mode 100644 (file)
index 0000000..792d85f
--- /dev/null
@@ -0,0 +1,45 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -t -s -r %t3 | FileCheck %s
+
+.globl _start
+_start:
+movabsq        $set_data, %rax
+
+.data
+.quad foo
+// Test that set_data has an address in the .plt, but foo is not
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11010
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x13000 R_X86_64_64 foo 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   0x13020 R_X86_64_JUMP_SLOT set_data 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      Name:    set_data
+// CHECK-NEXT: Value:   0x11020
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/undef.s b/test/ELF/undef.s
new file mode 100644 (file)
index 0000000..c8211c7
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o
+# RUN: llvm-ar rc %t2.a %t2.o
+# RUN: not ld.lld %t.o %t2.a -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld -pie %t.o %t2.a -o %t.exe 2>&1 | FileCheck %s
+# CHECK: undefined symbol: bar in {{.*}}
+# CHECK: undefined symbol: foo in {{.*}}
+# CHECK: undefined symbol: zed2 in {{.*}}2.a({{.*}}.o)
+
+  .globl _start
+_start:
+  call foo
+  call bar
+  call zed1
diff --git a/test/ELF/undefined-opt.s b/test/ELF/undefined-opt.s
new file mode 100644 (file)
index 0000000..ddd34f4
--- /dev/null
@@ -0,0 +1,66 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:     %p/Inputs/abs.s -o %tabs.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:     %p/Inputs/shared.s -o %tshared.o
+# RUN: rm -f %tar.a
+# RUN: llvm-ar rcs %tar.a %tabs.o %tshared.o
+# REQUIRES: x86
+
+# Symbols from the archive are not in if not needed
+# RUN: ld.lld -o %t1 %t.o %tar.a
+# RUN: llvm-readobj --symbols %t1 | FileCheck --check-prefix=NO-UNDEFINED %s
+# NO-UNDEFINED: Symbols [
+# NO-UNDEFINED-NOT: Name: abs
+# NO-UNDEFINED-NOT: Name: big
+# NO-UNDEFINED-NOT: Name: bar
+# NO-UNDEFINED-NOT: Name: zed
+# NO-UNDEFINED: ]
+
+# Symbols from the archive are in if needed, but only from the
+# containing object file
+# RUN: ld.lld -o %t2 %t.o %tar.a -u bar
+# RUN: llvm-readobj --symbols %t2 | FileCheck --check-prefix=ONE-UNDEFINED %s
+# ONE-UNDEFINED: Symbols [
+# ONE-UNDEFINED-NOT: Name: abs
+# ONE-UNDEFINED-NOT: Name: big
+# ONE-UNDEFINED: Name: bar
+# ONE-UNDEFINED: Name: zed
+# ONE-UNDEFINED: ]
+
+# Use the option couple of times, both short and long forms
+# RUN: ld.lld -o %t3 %t.o %tar.a -u bar --undefined=abs
+# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s
+# TWO-UNDEFINED: Symbols [
+# TWO-UNDEFINED: Name: abs
+# TWO-UNDEFINED: Name: big
+# TWO-UNDEFINED: Name: bar
+# TWO-UNDEFINED: Name: zed
+# TWO-UNDEFINED: ]
+# Now the same logic but linker script is used to set undefines
+# RUN: echo "EXTERN( bar abs )" > %t.script
+# RUN: ld.lld -o %t3 %t.o %tar.a %t.script
+# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s
+
+# Added undefined symbol may be left undefined without error, but
+# shouldn't show up in the dynamic table.
+# RUN: ld.lld -shared -o %t4 %t.o %tar.a -u unknown
+# RUN: llvm-readobj --dyn-symbols %t4 | \
+# RUN:     FileCheck --check-prefix=UNK-UNDEFINED-SO %s
+# UNK-UNDEFINED-SO: DynamicSymbols [
+# UNK-UNDEFINED-SO-NOT:     Name: unknown
+# UNK-UNDEFINED-SO: ]
+
+# Added undefined symbols should appear in the dynamic table if necessary.
+# RUN: ld.lld -shared -o %t5 %t.o -u export
+# RUN: llvm-readobj --dyn-symbols %t5 | \
+# RUN:     FileCheck --check-prefix=EXPORT-SO %s
+# EXPORT-SO: DynamicSymbols [
+# EXPORT-SO:   Name: export
+# EXPORT-SO: ]
+
+.globl _start
+_start:
+
+.globl export
+export:
diff --git a/test/ELF/unresolved-symbols.s b/test/ELF/unresolved-symbols.s
new file mode 100644 (file)
index 0000000..2fa59cb
--- /dev/null
@@ -0,0 +1,63 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/unresolved-symbols.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t.so
+
+## Check that %t2.o contains undefined symbol undef.
+# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | \
+# RUN:   FileCheck -check-prefix=UNDCHECK %s
+# UNDCHECK: undefined symbol: undef in {{.*}}2.o
+
+## Error out if unknown option value was set.
+# RUN: not ld.lld %t1.o %t2.o -o %t --unresolved-symbols=xxx 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR1 %s
+# ERR1: unknown --unresolved-symbols value: xxx
+
+## Ignore all should not produce error for symbols from object except
+## case when --no-undefined specified.
+# RUN: ld.lld %t2.o -o %t1_1 --unresolved-symbols=ignore-all
+# RUN: llvm-readobj %t1_1 > /dev/null 2>&1
+# RUN: not ld.lld %t2.o -o %t1_2 --unresolved-symbols=ignore-all --no-undefined 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+# ERRUND: undefined symbol: undef
+## Also ignore all should not produce error for symbols from DSOs.
+# RUN: ld.lld %t1.o %t.so -o %t1_3 --unresolved-symbols=ignore-all
+# RUN: llvm-readobj %t1_3 > /dev/null 2>&1
+
+## Ignoring undefines in objects should not produce error for symbol from object.
+# RUN: ld.lld %t1.o %t2.o -o %t2 --unresolved-symbols=ignore-in-object-files
+# RUN: llvm-readobj %t2 > /dev/null 2>&1
+## And still should not should produce for undefines from DSOs.
+# RUN: ld.lld %t1.o %t.so -o %t2_1 --unresolved-symbols=ignore-in-object-files
+# RUN: llvm-readobj %t2 > /dev/null 2>&1
+
+## Ignoring undefines in shared should produce error for symbol from object.
+# RUN: not ld.lld %t2.o -o %t3 --unresolved-symbols=ignore-in-shared-libs 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+## And should not produce errors for symbols from DSO.
+# RUN: ld.lld %t1.o %t.so -o %t3_1 --unresolved-symbols=ignore-in-shared-libs
+# RUN: llvm-readobj %t3_1 > /dev/null 2>&1
+
+## Ignoring undefines in shared libs should not produce error for symbol from object
+## if we are linking DSO.
+# RUN: ld.lld -shared %t1.o -o %t4 --unresolved-symbols=ignore-in-shared-libs
+# RUN: llvm-readobj %t4 > /dev/null 2>&1
+
+## Do not report undefines if linking relocatable.
+# RUN: ld.lld -r %t1.o %t2.o -o %t5 --unresolved-symbols=report-all
+# RUN: llvm-readobj %t5 > /dev/null 2>&1
+
+## report-all is the default one. Check that we do not report
+## undefines from DSO and do report undefines from object. With
+## report-all specified and without.
+# RUN: ld.lld -shared %t1.o %t.so -o %t6 --unresolved-symbols=report-all
+# RUN: llvm-readobj %t6 > /dev/null 2>&1
+# RUN: ld.lld -shared %t1.o %t.so -o %t6_1
+# RUN: llvm-readobj %t6_1 > /dev/null 2>&1
+# RUN: not ld.lld %t2.o -o %t7 --unresolved-symbols=report-all 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+
+.globl _start
+_start:
diff --git a/test/ELF/user_def_init_array_start.s b/test/ELF/user_def_init_array_start.s
new file mode 100644 (file)
index 0000000..6c33166
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t2.so -shared
+// Allow user defined __init_array_start. This is used by musl because of the
+// the bfd linker not handling these properly. We always create them as
+// hidden, musl should not have problems with lld.
+
+        .hidden __init_array_start
+        .globl  __init_array_start
+__init_array_start:
+        .zero   8
diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s
new file mode 100644 (file)
index 0000000..4d84734
--- /dev/null
@@ -0,0 +1,205 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/verdef-defaultver.s -o %t1
+# RUN: echo "LIBSAMPLE_1.0{               \
+# RUN:          global: a;                \
+# RUN:          local: *; };              \
+# RUN:       LIBSAMPLE_2.0{               \
+# RUN:          global: b; c;             \
+# RUN:       }LIBSAMPLE_1.0;" > %t.script
+# RUN: ld.lld -shared -soname shared %t1 --version-script %t.script -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: @
+# DSO-NEXT:      Value: 0x0
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Local
+# DSO-NEXT:      Type: None
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: Undefined
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: a@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1000
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: b@@LIBSAMPLE_2.0
+# DSO-NEXT:      Value: 0x1002
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: b@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1001
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: c@@LIBSAMPLE_2.0
+# DSO-NEXT:      Value: 0x1003
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:  ]
+# DSO-NEXT:  Version symbols {
+# DSO-NEXT:    Section Name: .gnu.version
+# DSO-NEXT:    Address: 0x240
+# DSO-NEXT:    Offset: 0x240
+# DSO-NEXT:    Link: 1
+# DSO-NEXT:    Symbols [
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 0
+# DSO-NEXT:        Name: @
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: a@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: b@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: b@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: c@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+# DSO-NEXT:  SHT_GNU_verdef {
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: Base
+# DSO-NEXT:      Index: 1
+# DSO-NEXT:      Hash: 127830196
+# DSO-NEXT:      Name: shared
+# DSO-NEXT:    }
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: 0x0
+# DSO-NEXT:      Index: 2
+# DSO-NEXT:      Hash: 98457184
+# DSO-NEXT:      Name: LIBSAMPLE_1.0
+# DSO-NEXT:    }
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: 0x0
+# DSO-NEXT:      Index: 3
+# DSO-NEXT:      Hash: 98456416
+# DSO-NEXT:      Name: LIBSAMPLE_2.0
+# DSO-NEXT:    }
+# DSO-NEXT:  }
+
+## Check that we can link against DSO produced.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
+# RUN: ld.lld %t2 %t.so -o %t3
+# RUN: llvm-readobj -V -dyn-symbols %t3 | FileCheck --check-prefix=EXE %s
+
+# EXE:      DynamicSymbols [
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: @
+# EXE-NEXT:      Value: 0x0
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Local
+# EXE-NEXT:      Type: None
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: a@LIBSAMPLE_1.0
+# EXE-NEXT:      Value: 0x11020
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: b@LIBSAMPLE_2.0
+# EXE-NEXT:      Value: 0x11030
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: c@LIBSAMPLE_2.0
+# EXE-NEXT:      Value: 0x11040
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:  ]
+# EXE-NEXT:  Version symbols {
+# EXE-NEXT:    Section Name: .gnu.version
+# EXE-NEXT:    Address: 0x10228
+# EXE-NEXT:    Offset: 0x228
+# EXE-NEXT:    Link: 1
+# EXE-NEXT:    Symbols [
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 0
+# EXE-NEXT:        Name: @
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 2
+# EXE-NEXT:        Name: a@LIBSAMPLE_1.0
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 3
+# EXE-NEXT:        Name: b@LIBSAMPLE_2.0
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 3
+# EXE-NEXT:        Name: c@LIBSAMPLE_2.0
+# EXE-NEXT:      }
+# EXE-NEXT:    ]
+# EXE-NEXT:  }
+# EXE-NEXT:  SHT_GNU_verdef {
+# EXE-NEXT:  }
+# EXE-NEXT:  SHT_GNU_verneed {
+# EXE-NEXT:    Dependency {
+# EXE-NEXT:      Version: 1
+# EXE-NEXT:      Count: 2
+# EXE-NEXT:      FileName: shared
+# EXE-NEXT:      Entry {
+# EXE-NEXT:        Hash: 98457184
+# EXE-NEXT:        Flags: 0x0
+# EXE-NEXT:        Index: 2
+# EXE-NEXT:        Name: LIBSAMPLE_1.0
+# EXE-NEXT:      }
+# EXE-NEXT:      Entry {
+# EXE-NEXT:        Hash: 98456416
+# EXE-NEXT:        Flags: 0x0
+# EXE-NEXT:        Index: 3
+# EXE-NEXT:        Name: LIBSAMPLE_2.0
+# EXE-NEXT:      }
+# EXE-NEXT:    }
+# EXE-NEXT:  }
+
+.globl _start
+_start:
+  callq a
+  callq b
+  callq c
diff --git a/test/ELF/verdef-dependency.s b/test/ELF/verdef-dependency.s
new file mode 100644 (file)
index 0000000..92627dd
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0{               \
+# RUN:          global: a;                \
+# RUN:          local: *; };              \
+# RUN:       LIBSAMPLE_2.0{               \
+# RUN:          global: b;                \
+# RUN:          local: *; }LIBSAMPLE_1.0; \
+# RUN:       LIBSAMPLE_3.0{               \
+# RUN:          global: c;                \
+# RUN:       }LIBSAMPLE_2.0;" > %t.script
+# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      SHT_GNU_verdef {
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: Base
+# DSO-NEXT:     Index: 1
+# DSO-NEXT:     Hash: 127830196
+# DSO-NEXT:     Name: shared
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 2
+# DSO-NEXT:     Hash: 98457184
+# DSO-NEXT:     Name: LIBSAMPLE_1.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 3
+# DSO-NEXT:     Hash: 98456416
+# DSO-NEXT:     Name: LIBSAMPLE_2.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 4
+# DSO-NEXT:     Hash: 98456672
+# DSO-NEXT:     Name: LIBSAMPLE_3.0
+# DSO-NEXT:   }
+# DSO-NEXT: }
diff --git a/test/ELF/verdef.s b/test/ELF/verdef.s
new file mode 100644 (file)
index 0000000..9463de0
--- /dev/null
@@ -0,0 +1,117 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0{  \
+# RUN:          global: a;   \
+# RUN:          local: *; }; \
+# RUN:       LIBSAMPLE_2.0{  \
+# RUN:          global: b;   \
+# RUN:          local: *; }; \
+# RUN:       LIBSAMPLE_3.0{  \
+# RUN:          global: c;   \
+# RUN:          local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:        Version symbols {
+# DSO-NEXT:   Section Name: .gnu.version
+# DSO-NEXT:   Address: 0x228
+# DSO-NEXT:   Offset: 0x228
+# DSO-NEXT:   Link: 1
+# DSO-NEXT:   Symbols [
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 0
+# DSO-NEXT:       Name: @
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 2
+# DSO-NEXT:       Name: a@@LIBSAMPLE_1.0
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 3
+# DSO-NEXT:       Name: b@@LIBSAMPLE_2.0
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 4
+# DSO-NEXT:       Name: c@@LIBSAMPLE_3.0
+# DSO-NEXT:     }
+# DSO-NEXT:   ]
+# DSO-NEXT: }
+# DSO-NEXT: SHT_GNU_verdef {
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: Base
+# DSO-NEXT:     Index: 1
+# DSO-NEXT:     Hash: 127830196
+# DSO-NEXT:     Name: shared
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 2
+# DSO-NEXT:     Hash: 98457184
+# DSO-NEXT:     Name: LIBSAMPLE_1.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 3
+# DSO-NEXT:     Hash: 98456416
+# DSO-NEXT:     Name: LIBSAMPLE_2.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 4
+# DSO-NEXT:     Hash: 98456672
+# DSO-NEXT:     Name: LIBSAMPLE_3.0
+# DSO-NEXT:   }
+# DSO-NEXT: }
+# DSO-NEXT: SHT_GNU_verneed {
+# DSO-NEXT: }
+
+## Check that we can link agains DSO we produced.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/verdef.s -o %tmain.o
+# RUN: ld.lld %tmain.o %t.so -o %tout
+# RUN: llvm-readobj -V %tout | FileCheck --check-prefix=MAIN %s
+
+# MAIN:      Version symbols {
+# MAIN-NEXT:   Section Name: .gnu.version
+# MAIN-NEXT:   Address: 0x10228
+# MAIN-NEXT:   Offset: 0x228
+# MAIN-NEXT:   Link: 1
+# MAIN-NEXT:   Symbols [
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 0
+# MAIN-NEXT:       Name: @
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 2
+# MAIN-NEXT:       Name: a@LIBSAMPLE_1.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 3
+# MAIN-NEXT:       Name: b@LIBSAMPLE_2.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 4
+# MAIN-NEXT:       Name: c@LIBSAMPLE_3.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:   ]
+# MAIN-NEXT: }
+# MAIN-NEXT: SHT_GNU_verdef {
+# MAIN-NEXT: }
+
+.globl a
+.type  a,@function
+a:
+retq
+
+.globl b
+.type  b,@function
+b:
+retq
+
+.globl c
+.type  c,@function
+c:
+retq
diff --git a/test/ELF/verneed-as-needed-weak.s b/test/ELF/verneed-as-needed-weak.s
new file mode 100644 (file)
index 0000000..a8efdc4
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o --as-needed %S/Inputs/verneed1.so -o %t
+# RUN: llvm-readobj -V %t | FileCheck %s
+
+# CHECK:       SHT_GNU_verneed {
+# CHECK-NEXT:  }
+
+.weak f1
+
+.globl _start
+_start:
+.data
+.quad f1
diff --git a/test/ELF/verneed-local.s b/test/ELF/verneed-local.s
new file mode 100644 (file)
index 0000000..a50f670
--- /dev/null
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o %S/Inputs/verneed1.so -o %t 2>&1 | FileCheck %s
+
+# CHECK: undefined symbol: f3 in
+.globl _start
+_start:
+call f3
diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s
new file mode 100644 (file)
index 0000000..e9d7c53
--- /dev/null
@@ -0,0 +1,173 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %S/Inputs/verneed1.so %S/Inputs/verneed2.so -o %t
+# RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s
+
+# CHECK:        Section {
+# CHECK:         Index: 1
+# CHECK-NEXT:    Name: .dynsym (1)
+# CHECK-NEXT:    Type: SHT_DYNSYM (0xB)
+# CHECK-NEXT:    Flags [ (0x2)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x101C8
+# CHECK-NEXT:    Offset: 0x1C8
+# CHECK-NEXT:    Size: 96
+# CHECK-NEXT:    Link: 5
+# CHECK-NEXT:    Info: 1
+# CHECK-NEXT:    AddressAlignment: 8
+# CHECK-NEXT:    EntrySize: 24
+# CHECK:       Section {
+# CHECK-NEXT:   Index: 2
+# CHECK-NEXT:   Name: .gnu.version (9)
+# CHECK-NEXT:   Type: SHT_GNU_versym (0x6FFFFFFF)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10228
+# CHECK-NEXT:   Offset: 0x228
+# CHECK-NEXT:   Size: 8
+# CHECK-NEXT:   Link: 1
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 2
+# CHECK-NEXT:   EntrySize: 2
+# CHECK:       Section {
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .gnu.version_r (22)
+# CHECK-NEXT:   Type: SHT_GNU_verneed (0x6FFFFFFE)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10230
+# CHECK-NEXT:   Offset: 0x230
+# CHECK-NEXT:   Size: 80
+# CHECK-NEXT:   Link: 5
+# CHECK-NEXT:   Info: 2
+# CHECK-NEXT:   AddressAlignment: 4
+# CHECK-NEXT:   EntrySize: 0
+# CHECK:      Section {
+# CHECK:        Index: 5
+# CHECK-NEXT:   Name: .dynstr
+# CHECK-NEXT:   Type: SHT_STRTAB
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x102A8
+# CHECK-NEXT:   Offset: 0x2A8
+# CHECK-NEXT:   Size: 47
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 00663100 7665726E 65656431 2E736F2E  |.f1.verneed1.so.|
+# CHECK-NEXT:     0010: 30007633 00663200 76320067 31007665  |0.v3.f2.v2.g1.ve|
+# CHECK-NEXT:     0020: 726E6565 64322E73 6F2E3000 763100    |rneed2.so.0.v1.|
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f1@v3 (1)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f2@v2 (21)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: g1@v1 (27)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK:      0x000000006FFFFFF0 VERSYM               0x10228
+# CHECK-NEXT: 0x000000006FFFFFFE VERNEED              0x10230
+# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM           2
+
+# CHECK:      Version symbols {
+# CHECK-NEXT:    Section Name: .gnu.version
+# CHECK-NEXT:    Address: 0x10228
+# CHECK-NEXT:    Offset: 0x228
+# CHECK-NEXT:    Link: 1
+# CHECK-NEXT:    Symbols [
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 0
+# CHECK-NEXT:        Name: @
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 2
+# CHECK-NEXT:        Name: f1@v3
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 3
+# CHECK-NEXT:        Name: f2@v2
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 4
+# CHECK-NEXT:        Name: g1@v1
+# CHECK-NEXT:      }
+# CHECK-NEXT:    ]
+# CHECK-NEXT:  }
+# CHECK-NEXT:  SHT_GNU_verdef {
+# CHECK-NEXT:  }
+# CHECK-NEXT:  SHT_GNU_verneed {
+# CHECK-NEXT:    Dependency {
+# CHECK-NEXT:      Version: 1
+# CHECK-NEXT:      Count: 2
+# CHECK-NEXT:      FileName: verneed1.so.0
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1938
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 3
+# CHECK-NEXT:        Name: v2
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1939
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 2
+# CHECK-NEXT:        Name: v3
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:    Dependency {
+# CHECK-NEXT:      Version: 1
+# CHECK-NEXT:      Count: 1
+# CHECK-NEXT:      FileName: verneed2.so.0
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1937
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 4
+# CHECK-NEXT:        Name: v1
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
+call f1@plt
+call f2@plt
+call g1@plt
diff --git a/test/ELF/version-script-err.s b/test/ELF/version-script-err.s
new file mode 100644 (file)
index 0000000..15b69e9
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so --version-script %p/Inputs/version-script-err.script 2>&1 | FileCheck %s
+// CHECK: ; expected, but got }
+
+// RUN: echo    "\"" > %terr1.script
+// RUN: not ld.lld --version-script %terr1.script -shared %t.o -o %t.so 2>&1 | \
+// RUN:   FileCheck -check-prefix=ERR1 %s
+// ERR1: unclosed quote
diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s
new file mode 100644 (file)
index 0000000..4396534
--- /dev/null
@@ -0,0 +1,97 @@
+# REQUIRES: shell
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { \
+# RUN:   global:             \
+# RUN:      extern "C++" {   \
+# RUN:         \"foo(int)\";    \
+# RUN:         \"zed(int)\";    \
+# RUN:   };                  \
+# RUN: };                    \
+# RUN: LIBSAMPLE_2.0 {       \
+# RUN:   global:             \
+# RUN:     extern "C++" {    \
+# RUN:       \"bar(int)\";      \
+# RUN:   };                  \
+# RUN: }; " > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: @
+# DSO-NEXT:      Value: 0x0
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Local
+# DSO-NEXT:      Type: None
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: Undefined
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      Value: 0x1001
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1000
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1002
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global (0x1)
+# DSO-NEXT:      Type: Function (0x2)
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text (0x6)
+# DSO-NEXT:    }
+# DSO-NEXT:  ]
+# DSO-NEXT:  Version symbols {
+# DSO-NEXT:    Section Name: .gnu.version
+# DSO-NEXT:    Address: 0x228
+# DSO-NEXT:    Offset: 0x228
+# DSO-NEXT:    Link: 1
+# DSO-NEXT:    Symbols [
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 0
+# DSO-NEXT:        Name: @
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+
+.text
+.globl _Z3fooi
+.type _Z3fooi,@function
+_Z3fooi:
+retq
+
+.globl _Z3bari
+.type _Z3bari,@function
+_Z3bari:
+retq
+
+.globl _Z3zedi
+.type _Z3zedi,@function
+_Z3zedi:
+retq
diff --git a/test/ELF/version-script-noundef.s b/test/ELF/version-script-noundef.s
new file mode 100644 (file)
index 0000000..4a251d6
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: echo "VERSION_1.0{    \
+# RUN:          global: bar; \
+# RUN:       };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld --version-script %t.script -shared --no-undefined-version \
+# RUN:   %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: version script assignment of VERSION_1.0 to symbol bar failed: symbol not defined
+
+# RUN: echo "VERSION_1.0{    \
+# RUN:          global: und; \
+# RUN:       };" > %t2.script
+# RUN: not ld.lld --version-script %t2.script -shared --no-undefined-version \
+# RUN:   %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: version script assignment of VERSION_1.0 to symbol und failed: symbol not defined
+
+.text
+.globl foo
+.type foo,@function
+foo:
+callq und@PLT
diff --git a/test/ELF/version-script.s b/test/ELF/version-script.s
new file mode 100644 (file)
index 0000000..ba9c95a
--- /dev/null
@@ -0,0 +1,274 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+
+# RUN: echo "{ global: foo1; foo3; local: *; };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# RUN: echo "# comment" > %t3.script
+# RUN: echo "{ local: *; # comment" >> %t3.script
+# RUN: echo -n "}; # comment" >> %t3.script
+# RUN: ld.lld --version-script %t3.script -shared %t.o %t2.so -o %t3.so
+# RUN: llvm-readobj -dyn-symbols %t3.so | FileCheck --check-prefix=DSO2 %s
+
+# --version-script filters --dynamic-list.
+# RUN: echo "{ foo1; foo2; };" > %t.list
+# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t
+# RUN: llvm-readobj -dyn-symbols %t | FileCheck --check-prefix=EXE %s
+
+# RUN: echo "VERSION_1.0{      \
+# RUN:          global: foo1;  \
+# RUN:          local: *; };   \
+# RUN:       VERSION_2.0{      \
+# RUN:          global: foo3;  \
+# RUN:          local: *; }; " > %t4.script
+# RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so
+# RUN: llvm-readobj -dyn-symbols %t4.so | FileCheck --check-prefix=VERDSO %s
+
+# RUN: echo "VERSION_1.0{     \
+# RUN:          global: foo1; \
+# RUN:          local: *; };  \
+# RUN:          {             \
+# RUN:          global: foo3; \
+# RUN:          local: *; }; " > %t5.script
+# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+# ERR: anonymous version definition is used in combination with other version definitions
+
+# RUN: echo    "{             \
+# RUN:          global: foo1; \
+# RUN:          local: *; };  \
+# RUN:       VERSION_2.0 {    \
+# RUN:          global: foo3; \
+# RUN:          local: *; }; " > %t5.script
+# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+
+# RUN: echo "VERSION_1.0{     \
+# RUN:          global: foo1; \
+# RUN:          local: *; };  \
+# RUN:       VERSION_2.0 {    \
+# RUN:          global: foo1; \
+# RUN:          local: *; }; " > %t6.script
+# RUN: ld.lld --version-script %t6.script -shared %t.o %t2.so -o %t6.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=WARN2 %s
+# WARN2: duplicate symbol foo1 in version script
+
+# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2
+# RUN: llvm-readobj %t2 > /dev/null
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: @ (0)
+# DSO-NEXT:     Value: 0x0
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Local (0x0)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: Undefined (0x0)
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: bar@ (1)
+# DSO-NEXT:     Value: 0x0
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: Function (0x2)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: Undefined (0x0)
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: foo1@ (5)
+# DSO-NEXT:     Value: 0x1000
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: .text
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: foo3@ (10)
+# DSO-NEXT:     Value: 0x1007
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: .text
+# DSO-NEXT:   }
+# DSO-NEXT: ]
+
+# DSO2:      DynamicSymbols [
+# DSO2-NEXT:   Symbol {
+# DSO2-NEXT:     Name: @ (0)
+# DSO2-NEXT:     Value: 0x0
+# DSO2-NEXT:     Size: 0
+# DSO2-NEXT:     Binding: Local (0x0)
+# DSO2-NEXT:     Type: None (0x0)
+# DSO2-NEXT:     Other: 0
+# DSO2-NEXT:     Section: Undefined (0x0)
+# DSO2-NEXT:   }
+# DSO2-NEXT:   Symbol {
+# DSO2-NEXT:     Name: bar@ (1)
+# DSO2-NEXT:     Value: 0x0
+# DSO2-NEXT:     Size: 0
+# DSO2-NEXT:     Binding: Global (0x1)
+# DSO2-NEXT:     Type: Function (0x2)
+# DSO2-NEXT:     Other: 0
+# DSO2-NEXT:     Section: Undefined (0x0)
+# DSO2-NEXT:   }
+# DSO2-NEXT: ]
+
+# EXE:      DynamicSymbols [
+# EXE-NEXT:   Symbol {
+# EXE-NEXT:     Name: @ (0)
+# EXE-NEXT:     Value: 0x0
+# EXE-NEXT:     Size: 0
+# EXE-NEXT:     Binding: Local (0x0)
+# EXE-NEXT:     Type: None (0x0)
+# EXE-NEXT:     Other: 0
+# EXE-NEXT:     Section: Undefined (0x0)
+# EXE-NEXT:   }
+# EXE-NEXT:   Symbol {
+# EXE-NEXT:     Name: bar@ (1)
+# EXE-NEXT:     Value: 0x0
+# EXE-NEXT:     Size: 0
+# EXE-NEXT:     Binding: Global (0x1)
+# EXE-NEXT:     Type: Function (0x2)
+# EXE-NEXT:     Other: 0
+# EXE-NEXT:     Section: Undefined (0x0)
+# EXE-NEXT:   }
+# EXE-NEXT:   Symbol {
+# EXE-NEXT:     Name: foo1@ (5)
+# EXE-NEXT:     Value: 0x11000
+# EXE-NEXT:     Size: 0
+# EXE-NEXT:     Binding: Global (0x1)
+# EXE-NEXT:     Type: None (0x0)
+# EXE-NEXT:     Other: 0
+# EXE-NEXT:     Section: .text
+# EXE-NEXT:   }
+# EXE-NEXT: ]
+
+# VERDSO:      DynamicSymbols [
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: @
+# VERDSO-NEXT:     Value: 0x0
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Local
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: Undefined
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: bar@
+# VERDSO-NEXT:     Value: 0x0
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: Function
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: Undefined
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: foo1@@VERSION_1.0
+# VERDSO-NEXT:     Value: 0x1000
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: .text
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: foo3@@VERSION_2.0
+# VERDSO-NEXT:     Value: 0x1007
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: .text
+# VERDSO-NEXT:   }
+# VERDSO-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s
+
+# RUN: echo "{ global: foo1; foo3; };" > %t2.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --version-script %t2.script -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s
+
+# ALL:      DynamicSymbols [
+# ALL-NEXT:   Symbol {
+# ALL-NEXT:     Name: @
+# ALL-NEXT:     Value: 0x0
+# ALL-NEXT:     Size: 0
+# ALL-NEXT:     Binding: Local
+# ALL-NEXT:     Type: None
+# ALL-NEXT:     Other: 0
+# ALL-NEXT:     Section: Undefined
+# ALL-NEXT:   }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: _start@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: bar@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: Function
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: Undefined
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo1@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo2@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo3@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT: ]
+
+.globl foo1
+foo1:
+  call bar@PLT
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo3
+foo3:
+  call foo2@PLT
+  ret
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/version-undef-sym.s b/test/ELF/version-undef-sym.s
new file mode 100644 (file)
index 0000000..20e92e6
--- /dev/null
@@ -0,0 +1,42 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-readobj --dyn-symbols %p/Inputs/version-undef-sym.so | FileCheck %s
+
+
+// Inputs/version-undef-sym.so consists of the assembly file
+//
+//         .global bar
+// bar:
+//        .weak abc1
+//        .weak abc2
+//        .weak abc3
+//        .weak abc4
+//        .weak abc5
+//
+// linked into a shared library with the version script
+//
+// VER_1 {
+// global:
+//   bar;
+// };
+//
+// Assuming we can reproduce the desired property (a few undefined symbols
+// before bar) we should create it with lld itself once it supports that.
+
+
+// Show that the input .so has undefined symbols before bar. That is what would
+// get our version parsing out of sync.
+
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Name: bar
+
+// But now we can successfully find bar.
+// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o %t.exe
+
+        .global _start
+_start:
+        call bar@plt
diff --git a/test/ELF/version-use.s b/test/ELF/version-use.s
new file mode 100644 (file)
index 0000000..7ef12bc
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o %p/Inputs/version-use.so -o %t.so -shared -z defs
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+
+        call    bar@PLT
+
+// CHECK-NOT: SHT_GNU_versym
diff --git a/test/ELF/version-wildcard.test b/test/ELF/version-wildcard.test
new file mode 100644 (file)
index 0000000..80cb9ca
--- /dev/null
@@ -0,0 +1,114 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VERSION_1.0{      \
+# RUN:          global: foo*;  \
+# RUN:          local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo2@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1001
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo3@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1007
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VERSION_1.0{      \
+# RUN:          global: foo2;  \
+# RUN:          local: *; };   \
+# RUN:       VERSION_2.0{      \
+# RUN:          global: foo*;  \
+# RUN:       }; " > %t2.script
+# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
+# RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck --check-prefix=MIX %s
+
+# MIX:      DynamicSymbols [
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: @
+# MIX-NEXT:     Value: 0x0
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Local
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: Undefined
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo1@@VERSION_2.0
+# MIX-NEXT:     Value: 0x1000
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo2@@VERSION_1.0
+# MIX-NEXT:     Value: 0x1001
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo3@@VERSION_2.0
+# MIX-NEXT:     Value: 0x1007
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT: ]
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  call foo1@PLT
+  ret
+
+.globl foo3
+foo3:
+  call foo2@PLT
+  ret
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/visibility.s b/test/ELF/visibility.s
new file mode 100644 (file)
index 0000000..2043894
--- /dev/null
@@ -0,0 +1,129 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2
+// RUN: ld.lld -shared %t %t2 -o %t3
+// RUN: llvm-readobj -t -dyn-symbols %t3 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: hidden
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: internal
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x1)
+// CHECK-NEXT:       STV_INTERNAL
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected_with_hidden
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: default
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @ (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: default
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global default
+default:
+
+.global protected
+protected:
+
+.global hidden
+hidden:
+
+.global internal
+internal:
+
+.global protected_with_hidden
+.protected
+protected_with_hidden:
diff --git a/test/ELF/warn-common.s b/test/ELF/warn-common.s
new file mode 100644 (file)
index 0000000..783a9ab
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common2.s -o %t3.o
+
+## Report multiple commons if warn-common is specified
+# RUN: ld.lld --warn-common %t1.o %t2.o -o %t.out 2>&1 | FileCheck %s --check-prefix=WARN
+# WARN: multiple common of arr
+
+## no-warn-common is ignored
+# RUN: ld.lld --no-warn-common %t1.o %t2.o -o %t.out
+# RUN: llvm-readobj %t.out > /dev/null
+
+## Report if common is overridden
+# RUN: ld.lld --warn-common %t1.o %t3.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER
+# OVER: common arr is overridden
+
+## Report if common is overridden, but in different order
+# RUN: ld.lld --warn-common %t3.o %t1.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER
+
+.globl _start
+_start:
+
+.type arr,@object
+.comm arr,4,4
diff --git a/test/ELF/weak-undef-hidden.s b/test/ELF/weak-undef-hidden.s
new file mode 100644 (file)
index 0000000..70b951b
--- /dev/null
@@ -0,0 +1,29 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+.data
+.weak g
+.hidden g
+.quad g
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/weak-undef-shared.s b/test/ELF/weak-undef-shared.s
new file mode 100644 (file)
index 0000000..862a086
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/shared.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -t %t.exe | FileCheck %s
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value: 0x11020
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+.global _start
+_start:
+        .weak bar
+        .quad bar
diff --git a/test/ELF/weak-undef.s b/test/ELF/weak-undef.s
new file mode 100644 (file)
index 0000000..0255553
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.weak foo
+
+.globl _start
+_start:
diff --git a/test/ELF/whole-archive.s b/test/ELF/whole-archive.s
new file mode 100644 (file)
index 0000000..c65f116
--- /dev/null
@@ -0,0 +1,40 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/whole-archive.s -o %ta.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %ta.o
+
+// Should not add symbols from the archive by default as they are not required
+// RUN: ld.lld -o %t3 %t.o %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+// NOTADDED: Symbols [
+// NOTADDED-NOT: Name: _bar
+// NOTADDED: ]
+
+// Should add symbols from the archive if --whole-archive is used
+// RUN: ld.lld -o %t3 %t.o --whole-archive %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+// ADDED: Symbols [
+// ADDED: Name: _bar
+// ADDED: ]
+
+// --no-whole-archive should restore default behaviour
+// RUN: ld.lld -o %t3 %t.o --whole-archive --no-whole-archive %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+
+// --whole-archive and --no-whole-archive should affect only archives which follow them
+// RUN: ld.lld -o %t3 %t.o %t.a --whole-archive --no-whole-archive
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+// RUN: ld.lld -o %t3 %t.o --whole-archive %t.a --no-whole-archive
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+
+// --whole-archive should also work with thin archives
+// RUN: rm -f %tthin.a
+// RUN: llvm-ar --format=gnu rcsT %tthin.a %ta.o
+// RUN: ld.lld -o %t3 %t.o --whole-archive %tthin.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+
+.globl _start
+_start:
diff --git a/test/ELF/wildcards.s b/test/ELF/wildcards.s
new file mode 100644 (file)
index 0000000..2fe0f88
--- /dev/null
@@ -0,0 +1,80 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Default case: abc and abx included in text.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .abx) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+# SEC-DEFAULT:      Sections:
+# SEC-DEFAULT-NEXT: Idx Name          Size      Address          Type
+# SEC-DEFAULT-NEXT:   0               00000000 0000000000000000
+# SEC-DEFAULT-NEXT:   1 .text         00000008 0000000000000120 TEXT DATA
+# SEC-DEFAULT-NEXT:   2 .abcd         00000004 0000000000000128 TEXT DATA
+# SEC-DEFAULT-NEXT:   3 .ad           00000004 000000000000012c TEXT DATA
+# SEC-DEFAULT-NEXT:   4 .ag           00000004 0000000000000130 TEXT DATA
+# SEC-DEFAULT-NEXT:   5 .symtab       00000030 0000000000000000
+# SEC-DEFAULT-NEXT:   6 .shstrtab     0000002f 0000000000000000
+# SEC-DEFAULT-NEXT:   7 .strtab       00000008 0000000000000000
+
+## Now replace the symbol with '?' and check that results are the same.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .ab?) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+## Now see how replacing '?' with '*' will consume whole abcd.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .ab*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-ALL %s
+# SEC-ALL:      Sections:
+# SEC-ALL-NEXT: Idx Name          Size      Address          Type
+# SEC-ALL-NEXT:   0               00000000 0000000000000000
+# SEC-ALL-NEXT:   1 .text         0000000c 0000000000000120 TEXT DATA
+# SEC-ALL-NEXT:   2 .ad           00000004 000000000000012c TEXT DATA
+# SEC-ALL-NEXT:   3 .ag           00000004 0000000000000130 TEXT DATA
+# SEC-ALL-NEXT:   4 .symtab       00000030 0000000000000000
+# SEC-ALL-NEXT:   5 .shstrtab     00000029 0000000000000000
+# SEC-ALL-NEXT:   6 .strtab       00000008 0000000000000000
+
+## All sections started with .a are merged.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.a*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-NO %s
+# SEC-NO: Sections:
+# SEC-NO-NEXT: Idx Name          Size      Address          Type
+# SEC-NO-NEXT:   0               00000000 0000000000000000
+# SEC-NO-NEXT:   1 .text         00000014 0000000000000120 TEXT DATA
+# SEC-NO-NEXT:   2 .symtab       00000030 0000000000000000
+# SEC-NO-NEXT:   3 .shstrtab     00000021 0000000000000000
+# SEC-NO-NEXT:   4 .strtab       00000008 0000000000000000
+
+.text
+.section .abc,"ax",@progbits
+.long 0
+
+.text
+.section .abx,"ax",@progbits
+.long 0
+
+.text
+.section .abcd,"ax",@progbits
+.long 0
+
+.text
+.section .ad,"ax",@progbits
+.long 0
+
+.text
+.section .ag,"ax",@progbits
+.long 0
+
+
+.globl _start
+_start:
diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s
new file mode 100644 (file)
index 0000000..17aac2d
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap.s -o %t2
+
+// RUN: ld.lld -o %t3 %t %t2 -wrap foo -wrap nosuchsym
+// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s
+// RUN: ld.lld -o %t3 %t %t2 --wrap foo -wrap=nosuchsym
+// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s
+
+// CHECK: _start:
+// CHECK-NEXT: movl $0x11010, %edx
+// CHECK-NEXT: movl $0x11010, %edx
+// CHECK-NEXT: movl $0x11000, %edx
+
+.global _start
+_start:
+  movl $foo, %edx
+  movl $__wrap_foo, %edx
+  movl $__real_foo, %edx
diff --git a/test/ELF/writable-merge.s b/test/ELF/writable-merge.s
new file mode 100644 (file)
index 0000000..431cb62
--- /dev/null
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: writable SHF_MERGE section is not supported
+
+.section .foo,"awM",@progbits,4
diff --git a/test/ELF/x86-64-dyn-rel-error.s b/test/ELF/x86-64-dyn-rel-error.s
new file mode 100644 (file)
index 0000000..c814fbe
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld %t2.o -shared -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+        .global _start
+_start:
+        .data
+        .long bar
+
+// CHECK: R_X86_64_32 cannot be used against shared object; recompile with -fPIC.
diff --git a/test/ELF/x86-64-dyn-rel-error2.s b/test/ELF/x86-64-dyn-rel-error2.s
new file mode 100644 (file)
index 0000000..c1d3da3
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld %t2.o -shared -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+        .global _start
+_start:
+        .data
+        .long bar - .
+
+// CHECK: R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC.
diff --git a/test/ELF/x86-64-rela.s b/test/ELF/x86-64-rela.s
new file mode 100644 (file)
index 0000000..41bdd76
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux-gnux32 %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+
+        call foo@plt
+
+// CHECK:  0x{{0+}}14 PLTREL{{ +}}RELA
diff --git a/test/ELF/x86-64-relax-offset.s b/test/ELF/x86-64-relax-offset.s
new file mode 100644 (file)
index 0000000..a7c7ce6
--- /dev/null
@@ -0,0 +1,13 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %s \
+// RUN:   -o %t.o
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/x86-64-relax-offset.s -o %t2.o
+// RUN: ld.lld %t2.o %t.o -o %t.so -shared
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+        mov foo@gotpcrel(%rip), %rax
+        nop
+
+// CHECK:      1004: {{.*}} leaq    -11(%rip), %rax
+// CHECK-NEXT: 100b: {{.*}} nop
diff --git a/test/ELF/x86-64-reloc-32-fpic.s b/test/ELF/x86-64-reloc-32-fpic.s
new file mode 100644 (file)
index 0000000..0a0f1a0
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC.
+
+.data
+.long _shared
diff --git a/test/ELF/x86-64-reloc-error.s b/test/ELF/x86-64-reloc-error.s
new file mode 100644 (file)
index 0000000..9b7e17d
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld -shared %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: x86
+
+  movl $big, %edx
+  movq $foo - 0x1000000000000, %rdx
+
+# CHECK: R_X86_64_32 out of range
+# CHECK: R_X86_64_32S out of range
diff --git a/test/ELF/x86-64-reloc-pc32-fpic.s b/test/ELF/x86-64-reloc-pc32-fpic.s
new file mode 100644 (file)
index 0000000..ed91215
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+# CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC.
+
+.data
+call _shared
diff --git a/test/ELF/x86-64-reloc-range.s b/test/ELF/x86-64-reloc-range.s
new file mode 100644 (file)
index 0000000..8319eaa
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+// CHECK: relocation R_X86_64_PC32 out of range
+// CHECK-NOT: relocation
+
+        lea     foo(%rip), %rax
+        lea     foo(%rip), %rax
+
+        .hidden foo
+        .bss
+        .zero 0x7fffe007
+foo:
diff --git a/test/ELF/x86-64-tls-gd-got.s b/test/ELF/x86-64-tls-gd-got.s
new file mode 100644 (file)
index 0000000..f86c3aa
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/x86-64-tls-gd-got.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+        .globl  _start
+_start:
+        .byte   0x66
+        leaq    bar@tlsgd(%rip), %rdi
+        .byte   0x66
+        rex64
+        call    *__tls_get_addr@GOTPCREL(%rip)
+        ret
+
+// CHECK:      _start:
+// CHECK-NEXT:   movq    %fs:0, %rax
+// CHECK-NEXT:   leaq    -4(%rax), %rax
+// CHECK-NEXT:   retq
diff --git a/test/ELF/x86-64-tls-gd-local.s b/test/ELF/x86-64-tls-gd-local.s
new file mode 100644 (file)
index 0000000..843b891
--- /dev/null
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+        .byte   0x66
+        leaq    foo@tlsgd(%rip), %rdi
+        .value  0x6666
+        rex64
+        call    __tls_get_addr@PLT
+
+        .byte   0x66
+        leaq    bar@tlsgd(%rip), %rdi
+        .value  0x6666
+        rex64
+        call    __tls_get_addr@PLT
+
+        .section        .tbss,"awT",@nobits
+
+        .hidden foo
+        .globl  foo
+foo:
+        .zero   4
+
+        .hidden bar
+        .globl  bar
+bar:
+        .zero   4
+
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20D0
+// CHECK-NEXT: Offset: 0x20D0
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:   0010: 00000000 00000000 04000000 00000000  |................|
+// CHECK-NEXT: )
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x20D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT:   0x20E0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/x86-64-tls-pie.s b/test/ELF/x86-64-tls-pie.s
new file mode 100644 (file)
index 0000000..5ef0f54
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-cloudabi %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# Bug 27174: R_X86_64_TPOFF32 and R_X86_64_GOTTPOFF relocations should
+# be eliminated when building a PIE executable, as the static TLS layout
+# is fixed.
+#
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+       .globl  _start
+_start:
+       movq    %fs:0, %rax
+       movl    $3, i@TPOFF(%rax)
+
+       movq    %fs:0, %rdx
+       movq    i@GOTTPOFF(%rip), %rcx
+       movl    $3, (%rdx,%rcx)
+
+       .section        .tbss.i,"awT",@nobits
+       .globl  i
+i:
+       .long   0
+       .size   i, 4
diff --git a/test/ELF/zdefs.s b/test/ELF/zdefs.s
new file mode 100644 (file)
index 0000000..410da18
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t1.so
+
+# RUN: not ld.lld -z defs -shared %t.o -o %t1.so 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: undefined symbol: foo
+
+callq foo@PLT
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
new file mode 100644 (file)
index 0000000..4bc973a
--- /dev/null
@@ -0,0 +1,23 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+
+import lit.formats
+
+# name: The name of this test suite.
+config.name = 'lld-Unit'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes =  []
+
+# test_source_root: The root path where unit test binaries are located.
+# test_exec_root: The root path where tests should be run.
+config.test_source_root = os.path.join(config.lld_obj_root, 'unittests')
+config.test_exec_root = config.test_source_root
+
+# testFormat: The test format to use to interpret tests.
+if not hasattr(config, 'llvm_build_mode'):
+    lit_config.fatal("unable to find llvm_build_mode value on config")
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
diff --git a/test/Unit/lit.site.cfg.in b/test/Unit/lit.site.cfg.in
new file mode 100644 (file)
index 0000000..c2f3054
--- /dev/null
@@ -0,0 +1,25 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.lld_src_root = "@LLD_SOURCE_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+    config.llvm_build_mode = config.llvm_build_mode % lit_config.params
+except KeyError as e:
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/test/darwin/Inputs/native-and-mach-o.objtxt b/test/darwin/Inputs/native-and-mach-o.objtxt
new file mode 100644 (file)
index 0000000..58124eb
--- /dev/null
@@ -0,0 +1,17 @@
+--- !mach-o
+arch:         x86_64
+file-type:    MH_OBJECT
+sections:
+ - segment:     __TEXT
+   section:     __text
+   type:        S_REGULAR
+   attributes:  [ S_ATTR_PURE_INSTRUCTIONS ]
+   address:     0
+   content:     [ 0xC3 ]
+global-symbols:
+ - name:        _foo
+   type:        N_SECT
+   scope:       [ N_EXT ]
+   sect:        1
+   desc:        [ ]
+   value:       0
diff --git a/test/darwin/Inputs/native-and-mach-o2.objtxt b/test/darwin/Inputs/native-and-mach-o2.objtxt
new file mode 100644 (file)
index 0000000..344c9bc
--- /dev/null
@@ -0,0 +1,19 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/darwin/cmdline-objc_gc.objtxt b/test/darwin/cmdline-objc_gc.objtxt
new file mode 100644 (file)
index 0000000..b5225a1
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc is rejected.
+#
+
+# CHECK: error: -objc_gc is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/cmdline-objc_gc_compaction.objtxt b/test/darwin/cmdline-objc_gc_compaction.objtxt
new file mode 100644 (file)
index 0000000..acf7183
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc_compaction is rejected.
+#
+
+# CHECK: error: -objc_gc_compaction is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/cmdline-objc_gc_only.objtxt b/test/darwin/cmdline-objc_gc_only.objtxt
new file mode 100644 (file)
index 0000000..db1cef9
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc_only is rejected.
+#
+
+# CHECK: error: -objc_gc_only is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/native-and-mach-o.objtxt b/test/darwin/native-and-mach-o.objtxt
new file mode 100644 (file)
index 0000000..1dee76d
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/native-and-mach-o.objtxt  \
+# RUN: %p/Inputs/native-and-mach-o2.objtxt -o %t  && \
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test a mix of atoms and mach-o both encoded in yaml
+#
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 55, 48, 89, E5, 30, C0, E8, 00,
+                           00, 00, 00, 31, C0, 5D, C3 ]
+      references:
+      - offset:          7
+        kind:            branch32
+        target:          _foo
+
+undefined-atoms:
+ - name:                _foo
+
+...
+
+# CHECK:       {{[0-9a-f]+}} T _foo
+# CHECK:       {{[0-9a-f]+}} T _main
diff --git a/test/lit.cfg b/test/lit.cfg
new file mode 100644 (file)
index 0000000..5ff4fc4
--- /dev/null
@@ -0,0 +1,253 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+import locale
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'lld'
+
+# Tweak PATH for Win32
+if sys.platform in ['win32']:
+    # Seek sane tools in directories and set to $PATH.
+    path = getattr(config, 'lit_tools_dir', None)
+    path = lit_config.getToolsPath(path,
+                                   config.environment['PATH'],
+                                   ['cmp.exe', 'grep.exe', 'sed.exe'])
+    if path is not None:
+        path = os.path.pathsep.join((path,
+                                     config.environment['PATH']))
+        config.environment['PATH'] = path
+
+# Choose between lit's internal shell pipeline runner and a real shell.  If
+# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
+use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
+if use_lit_shell:
+    # 0 is external, "" is default, and everything else is internal.
+    execute_external = (use_lit_shell == "0")
+else:
+    # Otherwise we default to internal on Windows and external elsewhere, as
+    # bash on Windows is usually very slow.
+    execute_external = (not sys.platform in ['win32'])
+
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.ll', '.objtxt', '.test']
+
+# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
+# subdirectories contain auxiliary inputs for various tests in their parent
+# directories.
+config.excludes = ['Inputs']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+lld_obj_root = getattr(config, 'lld_obj_root', None)
+if lld_obj_root is not None:
+    config.test_exec_root = os.path.join(lld_obj_root, 'test')
+
+# Set llvm_{src,obj}_root for use by others.
+config.llvm_src_root = getattr(config, 'llvm_src_root', None)
+config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+if lld_obj_root is not None:
+    llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+    if not llvm_tools_dir:
+        lit_config.fatal('No LLVM tools dir set!')
+    path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+    path = os.path.pathsep.join((os.path.join(getattr(config, 'llvm_src_root', None),'test','Scripts'),path))
+
+    config.environment['PATH'] = path
+
+    llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
+    if not llvm_libs_dir:
+        lit_config.fatal('No LLVM libs dir set!')
+    path = os.path.pathsep.join((llvm_libs_dir,
+                                 config.environment.get('LD_LIBRARY_PATH','')))
+    config.environment['LD_LIBRARY_PATH'] = path
+
+    # Propagate LLVM_SRC_ROOT into the environment.
+    config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '')
+
+    # Propagate PYTHON_EXECUTABLE into the environment
+    config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable',
+                                                      '')
+###
+
+# Check that the object root is known.
+if config.test_exec_root is None:
+    # Otherwise, we haven't loaded the site specific configuration (the user is
+    # probably trying to run on a test file directly, and either the site
+    # configuration hasn't been created by the build system, or we are in an
+    # out-of-tree build situation).
+
+    # Check for 'lld_site_config' user parameter, and use that if available.
+    site_cfg = lit_config.params.get('lld_site_config', None)
+    if site_cfg and os.path.exists(site_cfg):
+        lit_config.load_config(config, site_cfg)
+        raise SystemExit
+
+    # Try to detect the situation where we are using an out-of-tree build by
+    # looking for 'llvm-config'.
+    #
+    # FIXME: I debated (i.e., wrote and threw away) adding logic to
+    # automagically generate the lit.site.cfg if we are in some kind of fresh
+    # build situation. This means knowing how to invoke the build system though,
+    # and I decided it was too much magic. We should solve this by just having
+    # the .cfg files generated during the configuration step.
+
+    llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
+    if not llvm_config:
+        lit_config.fatal('No site specific configuration available!')
+
+    # Get the source and object roots.
+    llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
+    llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
+    lld_src_root = os.path.join(llvm_src_root, "tools", "lld")
+    lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld")
+
+    # Validate that we got a tree which points to here, using the standard
+    # tools/lld layout.
+    this_src_root = os.path.dirname(config.test_source_root)
+    if os.path.realpath(lld_src_root) != os.path.realpath(this_src_root):
+        lit_config.fatal('No site specific configuration available!')
+
+    # Check that the site specific configuration exists.
+    site_cfg = os.path.join(lld_obj_root, 'test', 'lit.site.cfg')
+    if not os.path.exists(site_cfg):
+        lit_config.fatal(
+            'No site specific configuration available! You may need to '
+            'run "make test" in your lld build directory.')
+
+    # Okay, that worked. Notify the user of the automagic, and reconfigure.
+    lit_config.note('using out-of-tree build at %r' % lld_obj_root)
+    lit_config.load_config(config, site_cfg)
+    raise SystemExit
+
+# For each occurrence of a lld tool name as its own word, replace it
+# with the full path to the build directory holding that tool.  This
+# ensures that we are testing the tools just built and not some random
+# tools that might happen to be in the user's PATH.
+
+# Regex assertions to reject neighbor hyphens/dots (seen in some tests).
+# For example, we want to prefix 'lld' and 'ld.lld' but not the 'lld' inside
+# of 'ld.lld'.
+NoPreJunk = r"(?<!(-|\.|/))"
+NoPostJunk = r"(?!(-|\.))"
+
+tool_patterns = [r"\bFileCheck\b",
+                 r"\bnot\b",
+                 NoPreJunk + r"\blld\b" + NoPostJunk,
+                 r"\bld.lld\b",
+                 r"\blld-link\b",
+                 r"\bllvm-mc\b",
+                 r"\bllvm-nm\b",
+                 r"\bllvm-objdump\b",
+                 r"\bllvm-readobj\b",
+                 r"\byaml2obj\b"]
+
+for pattern in tool_patterns:
+    # Extract the tool name from the pattern.  This relies on the tool
+    # name being surrounded by \b word match operators.  If the
+    # pattern starts with "| ", include it in the string to be
+    # substituted.
+    tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_\.]+)\\b\W*$",
+                          pattern)
+    tool_pipe = tool_match.group(2)
+    tool_name = tool_match.group(4)
+    tool_path = lit.util.which(tool_name, llvm_tools_dir)
+    if not tool_path:
+        # Warn, but still provide a substitution.
+        lit_config.note('Did not find ' + tool_name + ' in ' + llvm_tools_dir)
+        tool_path = llvm_tools_dir + '/' + tool_name
+    config.substitutions.append((pattern, tool_pipe + tool_path))
+
+# Add site-specific substitutions.
+config.substitutions.append( ('%python', config.python_executable) )
+
+###
+
+# When running under valgrind, we mangle '-vg' onto the end of the triple so we
+# can check it with XFAIL and XTARGET.
+if lit_config.useValgrind:
+    config.target_triple += '-vg'
+
+# Shell execution
+if execute_external:
+    config.available_features.add('shell')
+
+# zlib compression library
+if config.have_zlib == "1":
+    config.available_features.add("zlib")
+
+# Running on Darwin OS
+if platform.system() in ['Darwin']:
+    config.available_features.add('system-linker-mach-o')
+
+# Running on ELF based *nix
+if platform.system() in ['FreeBSD', 'Linux']:
+    config.available_features.add('system-linker-elf')
+
+# Set if host-cxxabi's demangler can handle target's symbols.
+if platform.system() not in ['Windows']:
+    config.available_features.add('demangler')
+
+# llvm-config knows whether it is compiled with asserts (and)
+# whether we are operating in release/debug mode.
+import subprocess
+try:
+    llvm_config_cmd = \
+     subprocess.Popen([os.path.join(llvm_tools_dir, 'llvm-config'),
+                     '--build-mode', '--assertion-mode', '--targets-built'],
+                      stdout = subprocess.PIPE)
+except OSError as why:
+    print("Could not find llvm-config in " + llvm_tools_dir)
+    exit(42)
+
+llvm_config_output = llvm_config_cmd.stdout.read().decode('utf_8')
+llvm_config_output_list = llvm_config_output.split("\n")
+
+if re.search(r'DEBUG', llvm_config_output_list[0]):
+    config.available_features.add('debug')
+if re.search(r'ON', llvm_config_output_list[1]):
+    config.available_features.add('asserts')
+
+archs = llvm_config_output_list[2]
+if re.search(r'AArch64', archs):
+    config.available_features.add('aarch64')
+if re.search(r'ARM', archs):
+    config.available_features.add('arm')
+if re.search(r'Mips', archs):
+    config.available_features.add('mips')
+if re.search(r'X86', archs):
+    config.available_features.add('x86')
+if re.search(r'PowerPC', archs):
+    config.available_features.add('ppc')
+if re.search(r'AMDGPU', archs):
+    config.available_features.add('amdgpu')
+llvm_config_cmd.wait()
+
+# Check if Windows resource file compiler exists.
+cvtres = lit.util.which('cvtres', config.environment['PATH'])
+rc = lit.util.which('rc', config.environment['PATH'])
+if cvtres and rc:
+    config.available_features.add('winres')
+
+# Check if "lib.exe" command exists.
+if lit.util.which('lib', config.environment['PATH']):
+    config.available_features.add('winlib')
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
new file mode 100644 (file)
index 0000000..5293f24
--- /dev/null
@@ -0,0 +1,23 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+config.have_zlib = "@HAVE_LIBZ@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError as e:
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/lit.cfg")
diff --git a/test/mach-o/Inputs/DependencyDump.py b/test/mach-o/Inputs/DependencyDump.py
new file mode 100755 (executable)
index 0000000..0f4d49d
--- /dev/null
@@ -0,0 +1,30 @@
+# -*- Python -*-
+
+
+#
+# Dump out Xcode binary dependency file.
+#
+
+import sys
+
+f = open(sys.argv[1], "rb")
+byte = f.read(1)
+while byte != b'':
+    if byte == b'\000':
+        sys.stdout.write("linker-vers: ")
+    elif byte == b'\020':
+        sys.stdout.write("input-file:  ")
+    elif byte == b'\021':
+        sys.stdout.write("not-found:   ")
+    elif byte == b'\100':
+        sys.stdout.write("output-file: ")
+    byte = f.read(1)
+    while byte != b'\000':
+        if byte != b'\012':
+            sys.stdout.write(byte.decode("ascii"))
+        byte = f.read(1)
+    sys.stdout.write("\n")
+    byte = f.read(1)
+
+f.close()
+
diff --git a/test/mach-o/Inputs/PIE.yaml b/test/mach-o/Inputs/PIE.yaml
new file mode 100644 (file)
index 0000000..0463154
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/arm-interworking.yaml b/test/mach-o/Inputs/arm-interworking.yaml
new file mode 100644 (file)
index 0000000..d78a299
--- /dev/null
@@ -0,0 +1,83 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFE, 0xFF, 0xFF, 0xEB, 0x02, 0x00, 0x00, 0xFA,
+                       0xFC, 0xFF, 0xFF, 0xEB, 0xFB, 0xFF, 0xFF, 0xFA,
+                       0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1 ]
+    relocations:
+      - offset:          0x0000000C
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000004
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            _d2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000018
+global-symbols:
+  - name:            _a1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _a2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000014
+undefined-symbols:
+  - name:            _t1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/arm-shims.yaml b/test/mach-o/Inputs/arm-shims.yaml
new file mode 100644 (file)
index 0000000..8baebef
--- /dev/null
@@ -0,0 +1,60 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+                       0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+                       0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+    relocations:
+      - offset:          0x00000014
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000002
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _a2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _t2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _a1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/bar.yaml b/test/mach-o/Inputs/bar.yaml
new file mode 100644 (file)
index 0000000..5605e67
--- /dev/null
@@ -0,0 +1,18 @@
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/cstring-sections.yaml b/test/mach-o/Inputs/cstring-sections.yaml
new file mode 100644 (file)
index 0000000..eb227f2
--- /dev/null
@@ -0,0 +1,25 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __objc_methname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
+  - segment:         __TEXT
+    section:         __objc_classname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000006
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
diff --git a/test/mach-o/Inputs/exported_symbols_list.exp b/test/mach-o/Inputs/exported_symbols_list.exp
new file mode 100644 (file)
index 0000000..ff66533
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# For use with exported_symbols_list.yaml
+#
+_foo
+_b
+
diff --git a/test/mach-o/Inputs/full.filelist b/test/mach-o/Inputs/full.filelist
new file mode 100644 (file)
index 0000000..abf98b6
--- /dev/null
@@ -0,0 +1,3 @@
+/foo/bar/a.o
+/foo/bar/b.o
+/foo/x.a
diff --git a/test/mach-o/Inputs/got-order.yaml b/test/mach-o/Inputs/got-order.yaml
new file mode 100644 (file)
index 0000000..d256e9d
--- /dev/null
@@ -0,0 +1,53 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000019
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _zazzle
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/got-order2.yaml b/test/mach-o/Inputs/got-order2.yaml
new file mode 100644 (file)
index 0000000..faddeda
--- /dev/null
@@ -0,0 +1,11 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libfoobar.dylib
+exports:
+  - name:            _bar
+  - name:            _zazzle
+  - name:            _foo
+  - name:            _aaa
+  - name:            _fff
+  - name:            _zzz
diff --git a/test/mach-o/Inputs/hello-world-arm64.yaml b/test/mach-o/Inputs/hello-world-arm64.yaml
new file mode 100644 (file)
index 0000000..31de71e
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:            arm64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _fprintf
+  - name:            ___stdoutp
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-armv6.yaml b/test/mach-o/Inputs/hello-world-armv6.yaml
new file mode 100644 (file)
index 0000000..0b29f65
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            armv6
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-armv7.yaml b/test/mach-o/Inputs/hello-world-armv7.yaml
new file mode 100644 (file)
index 0000000..4e26120
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-x86.yaml b/test/mach-o/Inputs/hello-world-x86.yaml
new file mode 100644 (file)
index 0000000..dbec62b
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            x86
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-x86_64.yaml b/test/mach-o/Inputs/hello-world-x86_64.yaml
new file mode 100644 (file)
index 0000000..7840d5c
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _fprintf
+  - name:            dyld_stub_binder
+  - name:            ___stdoutp
diff --git a/test/mach-o/Inputs/hw.raw_bytes b/test/mach-o/Inputs/hw.raw_bytes
new file mode 100644 (file)
index 0000000..ce01362
--- /dev/null
@@ -0,0 +1 @@
+hello
diff --git a/test/mach-o/Inputs/interposing-section.yaml b/test/mach-o/Inputs/interposing-section.yaml
new file mode 100644 (file)
index 0000000..45966b6
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _open
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64-2.yaml b/test/mach-o/Inputs/lazy-bind-x86_64-2.yaml
new file mode 100644 (file)
index 0000000..50a97bc
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libfoo.dylib
+compat-version:    2.0
+current-version:   3.4
+exports:
+  - name:            _foo
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64-3.yaml b/test/mach-o/Inputs/lazy-bind-x86_64-3.yaml
new file mode 100644 (file)
index 0000000..2f61cc0
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbaz.dylib
+compat-version:    3.0
+current-version:   4.5
+exports:
+  - name:            _baz
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64.yaml b/test/mach-o/Inputs/lazy-bind-x86_64.yaml
new file mode 100644 (file)
index 0000000..7e6cd90
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbar.dylib
+compat-version:    1.0
+current-version:   2.3
+exports:
+  - name:            _bar
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
new file mode 100755 (executable)
index 0000000..71185fb
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
new file mode 100644 (file)
index 0000000..b120629
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
new file mode 100644 (file)
index 0000000..f9a923d
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o differ
diff --git a/test/mach-o/Inputs/libSystem.yaml b/test/mach-o/Inputs/libSystem.yaml
new file mode 100644 (file)
index 0000000..2a7f463
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+---
+shared-library-atoms:
+    - name:              dyld_stub_binder
+      load-name:         /usr/lib/libSystem.B.dylib
+      type:              code
+      size:              0
+
+...
diff --git a/test/mach-o/Inputs/libbar.a b/test/mach-o/Inputs/libbar.a
new file mode 100644 (file)
index 0000000..64cae6c
Binary files /dev/null and b/test/mach-o/Inputs/libbar.a differ
diff --git a/test/mach-o/Inputs/libfoo.a b/test/mach-o/Inputs/libfoo.a
new file mode 100644 (file)
index 0000000..21194ef
Binary files /dev/null and b/test/mach-o/Inputs/libfoo.a differ
diff --git a/test/mach-o/Inputs/linker-as-ld.yaml b/test/mach-o/Inputs/linker-as-ld.yaml
new file mode 100644 (file)
index 0000000..0463154
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/no-version-min-load-command-object.yaml b/test/mach-o/Inputs/no-version-min-load-command-object.yaml
new file mode 100644 (file)
index 0000000..35f83c6
--- /dev/null
@@ -0,0 +1,22 @@
+
+# This object file has no version min and so will prevent any -r link from emitting
+# a version min.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
diff --git a/test/mach-o/Inputs/order_file-basic.order b/test/mach-o/Inputs/order_file-basic.order
new file mode 100644 (file)
index 0000000..0ac90cb
--- /dev/null
@@ -0,0 +1,11 @@
+
+# input file for order_file-basic.yaml
+
+_func2
+libfoo.a(foo.o):_foo  # tests file specific ordering within archive
+i386:_func3           # wrong arch, so ignored
+armv7:_func3          # wrong arch, so ignored
+_func1
+_notfound             # unknown symbol silently ignored
+_data3                # data symbols should be orderable
+
diff --git a/test/mach-o/Inputs/partial.filelist b/test/mach-o/Inputs/partial.filelist
new file mode 100644 (file)
index 0000000..281581b
--- /dev/null
@@ -0,0 +1,3 @@
+bar/a.o
+bar/b.o
+x.a
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal.yaml
new file mode 100644 (file)
index 0000000..1941b40
--- /dev/null
@@ -0,0 +1,21 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libfoo.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
+dependents:
+  - path:            /junk/libbar.dylib
+    kind:            LC_REEXPORT_DYLIB
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml
new file mode 100644 (file)
index 0000000..5aaf8c1
--- /dev/null
@@ -0,0 +1,18 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libbar.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml
new file mode 100644 (file)
index 0000000..43ba07c
--- /dev/null
@@ -0,0 +1,19 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/swift-version-1.yaml b/test/mach-o/Inputs/swift-version-1.yaml
new file mode 100644 (file)
index 0000000..1337d7a
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 ]
+...
diff --git a/test/mach-o/Inputs/unwind-info-simple-arm64.yaml b/test/mach-o/Inputs/unwind-info-simple-arm64.yaml
new file mode 100644 (file)
index 0000000..5f7ae50
--- /dev/null
@@ -0,0 +1,13 @@
+--- !mach-o
+arch:            arm64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libc++.dylib
+exports:
+  - name:            __Unwind_Resume
+  - name:            __ZTIl
+  - name:            __ZTIi
+  - name:            ___cxa_end_catch
+  - name:            ___cxa_begin_catch
+  - name:            ___cxa_allocate_exception
+  - name:            ___cxa_throw
+  - name:            ___gxx_personality_v0
diff --git a/test/mach-o/Inputs/use-dylib-install-names.yaml b/test/mach-o/Inputs/use-dylib-install-names.yaml
new file mode 100644 (file)
index 0000000..cec2559
--- /dev/null
@@ -0,0 +1,28 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+                       0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _myGlobal
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/use-simple-dylib.yaml b/test/mach-o/Inputs/use-simple-dylib.yaml
new file mode 100644 (file)
index 0000000..9081bcf
--- /dev/null
@@ -0,0 +1,58 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+  - name:            _myVariablePreviouslyKnownAsPrivateExtern
+    type:            N_SECT
+    scope:           [ N_PEXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000011
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _myHiddenWeak
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000007
+  - name:            _myResolver
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000010
+
+install-name:        libspecial.dylib
diff --git a/test/mach-o/Inputs/write-final-sections.yaml b/test/mach-o/Inputs/write-final-sections.yaml
new file mode 100644 (file)
index 0000000..ed43491
--- /dev/null
@@ -0,0 +1,20 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
diff --git a/test/mach-o/Inputs/wrong-arch-error.yaml b/test/mach-o/Inputs/wrong-arch-error.yaml
new file mode 100644 (file)
index 0000000..304c872
--- /dev/null
@@ -0,0 +1,24 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/PIE.yaml b/test/mach-o/PIE.yaml
new file mode 100644 (file)
index 0000000..24f8773
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -o %t  && \
+# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -pie -o %t\
+# RUN:  &&  llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -no_pie -o %t\
+# RUN:  &&  llvm-objdump -macho -private-headers %t \
+# RUN:  | FileCheck --check-prefix=CHECK_NO_PIE %s
+#
+# Test various PIE options.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+# CHECK:                 MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
+# CHECK_NO_PIE-NOT:    MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
diff --git a/test/mach-o/align_text.yaml b/test/mach-o/align_text.yaml
new file mode 100644 (file)
index 0000000..66b5afb
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test that alignment info round trips through -r
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x90, 0x90, 0x90, 0xC3, 0xC3, 0xC3 ]
+local-symbols:
+  - name:            _f1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000003
+  - name:            _f2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _f3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000005
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - content:         [ 90, 90, 90 ]
+# CHECK:     alignment:       16
+# CHECK:   - name:            _f1
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       3 mod 16
+# CHECK:   - name:            _f2
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       4 mod 16
+# CHECK:   - name:            _f3
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       5 mod 16
diff --git a/test/mach-o/arm-interworking-movw.yaml b/test/mach-o/arm-interworking-movw.yaml
new file mode 100644 (file)
index 0000000..0423ed6
--- /dev/null
@@ -0,0 +1,393 @@
+# REQUIRES: arm
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib -print_atoms %t -o %t2 \
+# RUN:     %p/Inputs/libSystem.yaml -sectalign __TEXT __text 0x1000  | FileCheck %s
+# RUN: llvm-objdump -d -macho -no-symbolic-operands %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test movw/movt pairs have low bit set properly for thumb vs arm.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x40, 0xF2, 0x25, 0x00, 0xC0, 0xF2, 0x00, 0x00,
+                       0x40, 0xF2, 0x01, 0x01, 0xC0, 0xF2, 0x00, 0x01,
+                       0x40, 0xF2, 0x4E, 0x02, 0xC0, 0xF2, 0x00, 0x02,
+                       0x40, 0xF2, 0x2A, 0x03, 0xC0, 0xF2, 0x00, 0x03,
+                       0x78, 0x44, 0x70, 0x47, 0x70, 0x47, 0x25, 0x00,
+                       0x00, 0xE3, 0x00, 0x00, 0x40, 0xE3, 0xD7, 0x1F,
+                       0x0F, 0xE3, 0xFF, 0x1F, 0x4F, 0xE3, 0x4E, 0x20,
+                       0x00, 0xE3, 0x00, 0x20, 0x40, 0xE3, 0x00, 0x30,
+                       0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3, 0x0F, 0x00,
+                       0x80, 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF,
+                       0x2F, 0xE1 ]
+    relocations:
+      - offset:          0x00000042
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000003E
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000003A
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000004E
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000036
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000032
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x0000FFD6
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000002E
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x0000FFFF
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000002A
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000025
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000026
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x0000002A
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000014
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000004E
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000010
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000000C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000004
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000025
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000000
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+local-symbols:
+  - name:            _t1
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000024
+  - name:            _a2
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000004E
+  - name:            _a1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000026
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _t1
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_movw
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movt
+# CHECK:         offset:          4
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movw_funcRel
+# CHECK:         offset:          8
+# CHECK:         target:          _t2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movt_funcRel
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movw
+# CHECK:         offset:          16
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movt
+# CHECK:         offset:          20
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movw_funcRel
+# CHECK:         offset:          24
+# CHECK:         target:          _a2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movt_funcRel
+# CHECK:         offset:          28
+# CHECK:         target:          _a2
+# CHECK:         addend:          -36
+# CHECK:   - name:            _t2
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:   - name:            _a1
+# CHECK:     references:
+# CHECK:       - kind:            arm_movw
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movt
+# CHECK:         offset:          4
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movw_funcRel
+# CHECK:         offset:          8
+# CHECK:         target:          _t2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movt_funcRel
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movw
+# CHECK:         offset:          16
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movt
+# CHECK:         offset:          20
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movw_funcRel
+# CHECK:         offset:          24
+# CHECK:         target:          _a2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movt_funcRel
+# CHECK:         offset:          28
+# CHECK:         target:          _a2
+# CHECK:         addend:          -40
+# CHECK:   - name:            _a2
+
+
+# CODE: _t1:
+# CODE-NEXT:                    movw   r0, #4133
+# CODE-NEXT:                   movt    r0, #0
+# CODE-NEXT:                   movw    r1, #1
+# CODE-NEXT:                   movt    r1, #0
+# CODE-NEXT:                   movw    r2, #4174
+# CODE-NEXT:                   movt    r2, #0
+# CODE-NEXT:                   movw    r3, #42
+# CODE-NEXT:                   movt    r3, #0
+
+
+# CODE: _a1:
+# CODE-NEXT:                    movw   r0, #4133
+# CODE-NEXT:                   movt    r0, #0
+# CODE-NEXT:                   movw    r1, #65495
+# CODE-NEXT:                   movt    r1, #65535
+# CODE-NEXT:                   movw    r2, #4174
+# CODE-NEXT:                   movt    r2, #0
+# CODE-NEXT:                   movw    r3, #0
+# CODE-NEXT:                   movt    r3, #0
+
+
+
+#      .syntax unified
+#      .align  2
+#
+#      .code   16
+#  .thumb_func _t1
+#_t1:
+#      movw    r0, :lower16:(_t2)
+#      movt    r0, :upper16:(_t2)
+#      movw    r1, :lower16:(_t2-(L0+4))
+#      movt    r1, :upper16:(_t2-(L0+4))
+#      movw    r2, :lower16:(_a2)
+#      movt    r2, :upper16:(_a2)
+#      movw    r3, :lower16:(_a2-(L0+4))
+#      movt    r3, :upper16:(_a2-(L0+4))
+#L0:
+#      add     r0, pc
+#      bx      lr
+#
+#
+#      .code   16
+#      .thumb_func     _t2
+#_t2:
+#      bx      lr
+#
+#
+#
+#      .code   32
+#_a1:
+#      movw    r0, :lower16:(_t2)
+#      movt    r0, :upper16:(_t2)
+#      movw    r1, :lower16:(_t2-(L1+8))
+#      movt    r1, :upper16:(_t2-(L1+8))
+#      movw    r2, :lower16:(_a2)
+#      movt    r2, :upper16:(_a2)
+#      movw    r3, :lower16:(_a2-(L1+8))
+#      movt    r3, :upper16:(_a2-(L1+8))
+#L1:
+#      add     r0, pc
+#      bx      lr
+#
+#_a2:
+#      bx      lr
+
diff --git a/test/mach-o/arm-interworking.yaml b/test/mach-o/arm-interworking.yaml
new file mode 100644 (file)
index 0000000..59c4605
--- /dev/null
@@ -0,0 +1,288 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s \
+# RUN: %p/Inputs/arm-interworking.yaml -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch armv7 -dylib -print_atoms \
+# RUN:         %p/Inputs/libSystem.yaml %t -o %t2  | FileCheck %s \
+# RUN: && llvm-readobj -s -sd %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test bl/blx instructions are fixed up properly.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFF, 0xF7, 0xFE, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+                       0xFC, 0xEF, 0xC0, 0x46, 0xFF, 0xF7, 0xF8, 0xEF,
+                       0xFF, 0xF7, 0xF6, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+                       0xF3, 0xFF, 0xC0, 0x46, 0x00, 0xF0, 0x06, 0xE8,
+                       0xC0, 0x46, 0x00, 0xF0, 0x03, 0xF8, 0x00, 0xF0,
+                       0x02, 0xF8, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47 ]
+    relocations:
+      - offset:          0x00000026
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000022
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x0000001C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000016
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000010
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x0000000C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000000
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000030
+    content:         [ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            _t3
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x000000000000002E
+  - name:            _d1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000030
+global-symbols:
+  - name:            _t1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x000000000000002C
+undefined-symbols:
+  - name:            _a1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _a2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _d1
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _a1
+# CHECK:   - name:            _d2
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _a1
+# CHECK:   - name:            _t1
+# CHECK:     scope:           global
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          0
+# CHECK:         target:          _a1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          6
+# CHECK:         target:          _a2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          12
+# CHECK:         target:          _a2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          16
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          22
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          28
+# CHECK:         target:          _t2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          34
+# CHECK:         target:          _t2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          38
+# CHECK:         target:          _t3
+# CHECK:   - name:            _t2
+# CHECK:     scope:           global
+# CHECK:     content:         [ 70, 47 ]
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:   - name:            _t3
+# CHECK:     content:         [ 70, 47 ]
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t3
+# CHECK:   - name:            _a1
+# CHECK:     scope:           global
+# CHECK:     references:
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          0
+# CHECK:         target:          _a1
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          4
+# CHECK:         target:          _a2
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          8
+# CHECK:         target:          _t1
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:   - name:            _a2
+# CHECK:     scope:           global
+
+# CODE:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CODE:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CODE:     SectionData (
+# CODE:       0000: 00F016E8 C04600F0 1EE8C046 00F01AE8
+# CODE:       0010: FFF7F6FF C046FFF7 F3FFC046 00F006F8
+# CODE:       0020: C04600F0 03F800F0 02F87047 70477047
+# CODE:       0030: FEFFFFEB 020000EB F0FFFFFA FAFFFFFA
+# CODE:       0040: 1EFF2FE1 1EFF2FE1
+# CODE:     )
+
+# CODE:     Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CODE:     Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CODE:     SectionData (
+# CODE:       0000: E50F0000 E80F0000 B90F0000 E80F0000
+# CODE:     )
+
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+# Verify the low (thumb) bit is set on the first and third pointers but not the second and fourth.
+
+
+
+# Input file one:
+#
+#      .align  2
+#      .code   16
+#  .globl _t1
+#  .thumb_func _t1
+#_t1:
+#    bl  _a1
+#    nop
+#    blx _a2
+#    nop
+#    blx _a2
+#    bl  _t1
+#    nop
+#    bl  _t1
+#    nop
+#    blx _t2
+#    nop
+#    blx  _t2
+#    bx   lr
+#
+#  .globl _t2
+#  .thumb_func _t2
+#_t2:
+#    bx   lr
+#
+#    .data
+#_d1:  .long _t2
+#      .long _a1
+
+
+
+# Input file two:
+#
+#      .align  2
+#      .code   32
+#  .globl _a1
+#_a1:
+#    bl  _a1
+#    blx _a2
+#    bl  _t1
+#    blx _t2
+#    bx   lr
+#
+#  .globl _a2
+#_a2:
+#    bx   lr
+#
+#    .data
+#_d2:  .long _t1
+#      .long _a1
+
+
+
+
diff --git a/test/mach-o/arm-shims.yaml b/test/mach-o/arm-shims.yaml
new file mode 100644 (file)
index 0000000..62739c9
--- /dev/null
@@ -0,0 +1,126 @@
+# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/arm-shims.yaml \
+# RUN: -dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-readobj -s -sd %t | FileCheck %s
+#
+# Test b from arm to thumb or vice versa has shims added.s
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+                       0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+                       0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+    relocations:
+      - offset:          0x00000014
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000002
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _a1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _t1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _a2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:   Section {
+# CHECK:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK:     SectionData (
+# CHECK:       0000: 00BF00F0 10E800F0 19B80000 00F020E3
+# CHECK:       0010: 000000FA 0F0000EA 00BFFFF7 F8EF00F0
+# CHECK:       0020: 07B80000 00F020E3 F4FFFFFA 050000EA
+# CHECK:       0030: DFF804C0 FF446047 D4FFFFFF DFF804C0
+# CHECK:       0040: FF446047 E0FFFFFF 04C09FE5 0CC08FE0
+# CHECK:       0050: 1CFF2FE1 ADFFFFFF 04C09FE5 0CC08FE0
+# CHECK:       0060: 1CFF2FE1 B5FFFFFF
+# CHECK:     )
+
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+
+
+# Input file one:
+#
+#      .align  2
+#      .code   16
+#  .globl _t1
+#  .thumb_func _t1
+#_t1:
+#    nop
+#    blx _a2
+#    b   _a2
+#
+#      .code   32
+#  .align 2
+#  .globl _a1
+#_a1:
+#    nop
+#    blx _t2
+#    b   _t2
+
+
+
+# Input file two:
+#
+#      .align  2
+#      .code   16
+#  .globl _t2
+#  .thumb_func _t2
+#_t2:
+#    nop
+#    blx _a1
+#    b   _a1
+#
+#      .code   32
+#  .align 2
+#  .globl _a2
+#_a2:
+#    nop
+#    blx _t1
+#    b   _t1
diff --git a/test/mach-o/arm-subsections-via-symbols.yaml b/test/mach-o/arm-subsections-via-symbols.yaml
new file mode 100644 (file)
index 0000000..23c2847
--- /dev/null
@@ -0,0 +1,60 @@
+# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s
+#
+# Test that assembly written without .subsections_via_symbols is parsed so
+# that atoms are non-dead-strip and there is a layout-after references
+# chaining atoms together.
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x04, 0x10, 0x9F, 0xE5, 0x04, 0x20, 0x9F, 0xE5,
+                       0x1E, 0xFF, 0x2F, 0xE1, 0x78, 0x56, 0x34, 0x12,
+                       0x21, 0x43, 0x65, 0x87 ]
+local-symbols:
+  - name:            constants1
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000C
+  - name:            constants2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - name:            _foo
+# CHECK:    scope:           global
+# CHECK:    content:         [ 04, 10, 9F, E5, 04, 20, 9F, E5, 1E, FF, 2F, E1 ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:
+# CHECK:      - kind:            layout-after
+# CHECK:        offset:          0
+# CHECK:        target:          constants1
+# CHECK:  - name:            constants1
+# CHECK:    content:         [ 78, 56, 34, 12 ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:
+# CHECK:      - kind:            layout-after
+# CHECK:        offset:          0
+# CHECK:        target:          constants2
+# CHECK:  - name:            constants2
+# CHECK:    content:         [ 21, 43, 65, 87 ]
+# CHECK:    dead-strip:      never
diff --git a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml
new file mode 100644 (file)
index 0000000..4da8809
--- /dev/null
@@ -0,0 +1,124 @@
+# RUN: lld -flavor darwin -arch arm64 -r %s -o %t
+# RUN: lld -flavor darwin -arch arm64 -r %t -o %t2
+# RUN: llvm-objdump -s -section="__eh_frame" %t | FileCheck %s
+# RUN: llvm-objdump -s -section="__eh_frame" %t2 | FileCheck %s
+
+# The reference from FDE->CIE is implicitly created as a negDelta32.
+# We don't emit these in to the binary as relocations, so we need to
+# make sure that the offset in the FDE to the CIE is the correct value.
+# CHECK: {{[0-9abcdef]*}} 10000000 00000000 017a5200 01781e01
+# CHECK: {{[0-9abcdef]*}} 100c1f00 20000000 18000000 b8ffffff
+# Note, this one that matters               ^~~~~~~~
+# It needs to be 0x18 as that is the offset back to 0 where the CIE is.
+# CHECK: {{[0-9abcdef]*}} ffffffff 20000000 00000000 00480e10
+# CHECK: {{[0-9abcdef]*}} 9e019d02 00000000
+
+---  !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:        
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91, 
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x91, 
+                       0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x80, 0x52, 
+                       0xFD, 0x7B, 0xC1, 0xA8, 0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:     
+      - offset:          0x00000010
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 
+                       0x72, 0x6C, 0x64, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000030
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000050
+    content:         [ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x1E, 0x01, 
+                       0x10, 0x0C, 0x1F, 0x00, 0x20, 0x00, 0x00, 0x00, 
+                       0x18, 0x00, 0x00, 0x00, 0x94, 0xFF, 0xFF, 0xFF, 
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0E, 0x10, 
+                       0x9E, 0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:   
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            L_str
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp2
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000030
+  - name:            ltmp3
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000050
+global-symbols:  
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols: 
+  - name:            _puts
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
diff --git a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml
new file mode 100644 (file)
index 0000000..08e41bc
--- /dev/null
@@ -0,0 +1,65 @@
+# RUN: not lld -flavor darwin -arch arm64 %s -r \
+# RUN: 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFF, 0x83, 0x00, 0xD1, 0xE0, 0x0B, 0x00, 0xF9, 
+                       0x08, 0x00, 0x40, 0xB9, 0x08, 0x0D, 0x00, 0x71, 
+                       0x08, 0x09, 0x00, 0x71, 0xE8, 0x0F, 0x00, 0xB9, 
+                       0xC8, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x14, 
+                       0xE8, 0x03, 0x00, 0x32, 0x08, 0x01, 0x00, 0x12, 
+                       0xE8, 0x7F, 0x00, 0x39, 0x02, 0x00, 0x00, 0x14 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x000000000001C348
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+
+# Make sure that the offsets of the subtractor and unsigned both match.
+# CHECK: bad relocation (paired relocs must have the same offset) in section __DATA/__data (r1_address=1, r1_type=1, r1_extern=1, r1_length=3, r1_pcrel=0, r1_symbolnum=1), (r2_address=0, r2_type=0, r2_extern=1, r2_length=3, r2_pcrel=0, r2_symbolnum=1)
+      - offset:          0x00000001
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _f1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000001C348
+  - name:            _f2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+  - name:            _f3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000020
diff --git a/test/mach-o/arm64-section-order.yaml b/test/mach-o/arm64-section-order.yaml
new file mode 100644 (file)
index 0000000..50d6846
--- /dev/null
@@ -0,0 +1,67 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+# Make sure that the sections are sorted.  Currently we want this order:
+# __text, __unwind_info
+
+# CHECK: Sections:
+# CHECK: 0 __text        {{.*}} TEXT
+# CHECK: 1 __compact_unwind {{.*}}
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z4foo2i
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000004
diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml
new file mode 100644 (file)
index 0000000..433dffc
--- /dev/null
@@ -0,0 +1,65 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t -print_atoms | FileCheck %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __objc_methname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x64, 0x65, 0x66, 0x00 ]
+  - segment:         __TEXT
+    section:         __objc_classname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000006
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x67, 0x68, 0x69, 0x00 ]
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x6A, 0x6B, 0x6C, 0x00 ]
+
+
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_methname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 64, 65, 66, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_methname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_classname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 67, 68, 69, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_classname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 6A, 6B, 6C, 00 ]
+# CHECK:     merge:           by-content
diff --git a/test/mach-o/data-in-code-load-command.yaml b/test/mach-o/data-in-code-load-command.yaml
new file mode 100644 (file)
index 0000000..604592a
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -data_in_code_info -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -r -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -r -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_DATA_IN_CODE
+# CHECK:   cmdsize 16
+# CHECK:   dataoff
+# CHECK:   datasize
+
+# NO_DATA_IN_CODE_INFO-NOT: LC_DATA_IN_CODE
diff --git a/test/mach-o/data-only-dylib.yaml b/test/mach-o/data-only-dylib.yaml
new file mode 100644 (file)
index 0000000..8d21430
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test that a data-only dylib can be built.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _myData
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: _myData
diff --git a/test/mach-o/dead-strip-globals.yaml b/test/mach-o/dead-strip-globals.yaml
new file mode 100644 (file)
index 0000000..df5ff73
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -flavor darwin -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -flavor darwin -arch x86_64 -dead_strip %s -dylib %p/Inputs/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s
+
+#
+# Test that -export_dynamic -dead-strip from removing globals.
+#
+
+---
+defined-atoms:
+  - name:            def
+    scope:           global
+    dead-strip:      never
+  - name:            dead
+    scope:           global
+shared-library-atoms:
+  - name:            dyld_stub_binder
+    load-name:       /usr/lib/libSystem.B.dylib
+    type:            unknown
+...
+
+# CHECK1:       name: def
+# CHECK1:       name: dead
+
+# CHECK2:       name: def
+# CHECK2-NOT:   name: dead
+
diff --git a/test/mach-o/demangle.yaml b/test/mach-o/demangle.yaml
new file mode 100644 (file)
index 0000000..f8a76cd
--- /dev/null
@@ -0,0 +1,74 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s  \
+# RUN:     -dylib -o %t %p/Inputs/libSystem.yaml  2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN:     -dylib -o %t %p/Inputs/libSystem.yaml -demangle 2> %t.err2
+# RUN: FileCheck %s --check-prefix=DCHECK < %t.err2
+#
+# Test -demangle option works on undefined symbol errors.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00,
+                       0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000000B
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000006
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000001
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            __Z1xv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __Znam
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __Znotcpp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:  __Znotcpp
+# CHECK:  __Znam
+# CHECK:  _foo
+
+# DCHECK:  __Znotcpp
+# DCHECK: operator new[](unsigned long)
+# DCHECK:  _foo
+
diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml
new file mode 100644 (file)
index 0000000..2ec59b8
--- /dev/null
@@ -0,0 +1,19 @@
+# Test -dependency_info option
+#
+# RUN: lld -flavor darwin -arch x86_64 -test_file_usage  \
+# RUN:        -dependency_info %t.info \
+# RUN:        -path_exists /System/Library/Frameworks \
+# RUN:        -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -framework Bar \
+# RUN:        -framework Foo
+# RUN: %python %p/Inputs/DependencyDump.py %t.info | FileCheck %s
+
+
+# CHECK: linker-vers: lld
+# CHECK: input-file:  /Custom/Frameworks{{[/\\]}}Bar.framework{{[/\\]}}Bar
+# CHECK: not-found:   /Custom/Frameworks{{[/\\]}}Foo.framework{{[/\\]}}Foo
+# CHECK: input-file:  /System/Library/Frameworks{{[/\\]}}Foo.framework{{[/\\]}}Foo
+# CHECK: output-file: a.out
diff --git a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml
new file mode 100644 (file)
index 0000000..70f76b5
--- /dev/null
@@ -0,0 +1,208 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x80, 0x52,
+                       0xFD, 0x7B, 0xC1, 0xA8, 0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x00000010
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F,
+                       0x72, 0x6C, 0x64, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000030
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000050
+    content:         [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x1E, 0x07, 0x00, 0x9D, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0x00, 0x10, 0x0C, 0x1F, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x48, 0x0E, 0x10, 0x9E, 0x01, 0x9D, 0x02 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x00000000000000A0
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            L_str
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp2
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000030
+  - name:            ltmp3
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000050
+  - name:            ltmp4
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000070
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _puts
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 48, 65, 6C, 6C, 6F, 20, 77, 6F, 72, 6C, 64, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 1C, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 50, 4C,
+# CHECK:                        52, 00, 01, 78, 1E, 07, 00, {{..}}, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, 00, 10, 0C, 1F, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 24, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 20, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 48, 0E, 10,
+# CHECK:                        9E, 01, 9D, 02 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3fooi
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 20, 00, 00, 00,
+# CHECK:                        00, 00, 00, 03, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __Z3fooi
+# CHECK:   - name:            __Z3fooi
+# CHECK:     scope:           global
+# CHECK:     content:         [ FD, 7B, BF, A9, FD, 03, 00, 91, 00, 00, 00, 90,
+# CHECK:                        00, 00, 00, 91, 00, 00, 00, 94, 00, 00, 80, 52,
+# CHECK:                        FD, 7B, C1, A8, C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:     references:
+# CHECK:       - kind:            page21
+# CHECK:         offset:          8
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            offset12
+# CHECK:         offset:          12
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          16
+# CHECK:         target:          _puts
+
+# Make sure we don't have any relocations in the __eh_frame section
+# CODE-NOT: RELOCATION RECORDS FOR [__eh_frame]
+
+# Also make sure the reloc for the FDE->function is the correct offset
+# It should be the offset from the fixup location back to the address
+# of the function we are referencing
+# CODE: Contents of section __eh_frame:
+# This is the CIE:
+# CODE-NEXT: {{[0-9abcdef]*}} 1c000000 00000000 017a504c 52000178
+# CODE-NEXT: {{[0-9abcdef]*}} 1e0700bd ffffffff ffffff00 100c1f00
+# This is the FDE:
+# CODE-NEXT: {{[0-9abcdef]*}} 24000000 24000000 a8ffffff ffffffff
+# This is the important offset for FDE->func    ^~~~~~~~ ~~~~~~~~
+
+# CODE-NEXT: {{[0-9abcdef]*}} 20000000 00000000 08c3ffff ffffffff
+# And this is the offset for FDE->lsda            ^~~~~~~~ ~~~~~~
+# CODE-NEXT: {{[0-9abcdef]*}} ff480e10 9e019d02
+# And this byte               ^~
diff --git a/test/mach-o/dso_handle.yaml b/test/mach-o/dso_handle.yaml
new file mode 100644 (file)
index 0000000..400e2c8
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch x86_64  %s  %p/Inputs/libSystem.yaml -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/libSystem.yaml -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/libSystem.yaml -dylib -o %t3
+# RUN: llvm-nm -m -n %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/libSystem.yaml -bundle -o %t4
+# RUN: llvm-nm -m -n %t4 | FileCheck %s
+#
+# Test that ___dso_handle symbol is available for executables, bundles, and dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            ___dso_handle
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK_NOT:   ___dso_handle
+# CHECK:      _main
diff --git a/test/mach-o/dylib-install-names.yaml b/test/mach-o/dylib-install-names.yaml
new file mode 100644 (file)
index 0000000..845085b
--- /dev/null
@@ -0,0 +1,74 @@
+# Check we accept -install_name correctly:
+# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     %p/Inputs/libSystem.yaml %s -o %t.dylib
+# RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+# Check we read LC_ID_DYLIB correctly:
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \
+# RUN:      %p/Inputs/libSystem.yaml %t.dylib -dylib -o %t2.dylib
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-READ
+
+# Check we default the install-name to the output file:
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+# RUN: rm -f libwibble.dylib
+
+# Check -single_module does nothing
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     -single_module -o %t2.dylib %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_ID_DYLIB
+# CHECK-BINARY-WRITE-NEXT: cmdsize 40
+# CHECK-BINARY-WRITE-NEXT:  name libwibble.dylib (offset 24)
+# CHECK-BINARY-WRITE-NEXT:  time stamp 1
+# CHECK-BINARY-WRITE-NEXT:  current version 5.3.0
+# CHECK-BINARY-WRITE-NEXT:  compatibility version 2.0.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 56
+# CHECK-BINARY-READ-NEXT:  name /usr/lib/libSystem.B.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT:  time stamp 2
+# CHECK-BINARY-READ-NEXT:  current version 0.16.0
+# CHECK-BINARY-READ-NEXT:  compatibility version 0.16.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 40
+# CHECK-BINARY-READ-NEXT:  name libwibble.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT:  time stamp 2
+# CHECK-BINARY-READ-NEXT:  current version 5.3.0
+# CHECK-BINARY-READ-NEXT:  compatibility version 2.0.0
diff --git a/test/mach-o/eh-frame-relocs-arm64.yaml b/test/mach-o/eh-frame-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..6681ded
--- /dev/null
@@ -0,0 +1,318 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:        
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6, 
+                       0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000014
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000020
+    content:         [ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000060
+    content:         [ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, 
+                       0x1E, 0x07, 0x9B, 0xED, 0xFF, 0xFF, 0xFF, 0x10, 
+                       0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00, 
+                       0x20, 0x00, 0x00, 0x00, 0xDC, 0xFF, 0xFF, 0xFF, 
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x08, 0xCB, 0xFF, 0xFF, 
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E, 
+                       0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, 
+                       0x1E, 0x07, 0x9B, 0xA9, 0xFF, 0xFF, 0xFF, 0x10, 
+                       0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00, 
+                       0x20, 0x00, 0x00, 0x00, 0x94, 0xFF, 0xFF, 0xFF, 
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x08, 0x83, 0xFF, 0xFF, 
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E, 
+                       0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x0000007D
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x0000007D
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x0000006C
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x0000006C
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x0000005B
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+      - offset:          0x00000035
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000035
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000024
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000024
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          7
+      - offset:          0x00000013
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+local-symbols:   
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _bar1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _bar2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000018
+  - name:            ltmp12
+    type:            N_SECT
+    sect:            3
+    value:           0x000000000000001C
+  - name:            ltmp13
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000020
+  - name:            ltmp16
+    type:            N_SECT
+    sect:            5
+    value:           0x0000000000000060
+global-symbols:  
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000008
+  - name:            __Z4foo2i
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            __gxx_personality_v0
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __gxx_personality_v1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000010
+  - name:            _someData
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x000000000000001C
+page-size:       0x00000000
+...
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:   
+# CHECK:   - ref-name:        L000
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C, 
+# CHECK:                        52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10, 
+# CHECK:                        10, 0C, 1F, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:      
+# CHECK:       - kind:            unwindCIEToPersonalityFunction
+# CHECK:         offset:          19
+# CHECK:         target:          __gxx_personality_v0
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, 
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00, 
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E, 
+# CHECK:                        01, 9D, 02, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       4 mod 8
+# CHECK:     references:      
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L000
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3fooi
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          _bar1
+# CHECK:   - ref-name:        L001
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C, 
+# CHECK:                        52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10, 
+# CHECK:                        10, 0C, 1F, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:      
+# CHECK:       - kind:            unwindCIEToPersonalityFunction
+# CHECK:         offset:          19
+# CHECK:         target:          __gxx_personality_v1
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, 
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00, 
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E, 
+# CHECK:                        01, 9D, 02, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       4 mod 8
+# CHECK:     references:      
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L001
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z4foo2i
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          _bar2
+# CHECK:   - name:            _bar1
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            _bar2
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            _someData
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            __gxx_personality_v0
+# CHECK:     scope:           global
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __gxx_personality_v1
+# CHECK:     scope:           global
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __Z3fooi
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __Z4foo2i
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            _main
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK: ...
+
+# # Make sure we don't have any relocations in the __eh_frame section
+# CODE-NOT: RELOCATION RECORDS FOR [__eh_frame]
+
+# Also make sure the reloc for the CIE->personality function is the
+# correct offset
+# It should be the offset from the fixup location back to the address
+# of the function we are referencing
+# CODE: Contents of section __eh_frame:
+# This is the CIE:
+# CODE-NEXT: {{[0-9abcdef]*}} 18000000 00000000 037a504c 52000178
+# CODE-NEXT: {{[0-9abcdef]*}} 1e079bd1 ffffff10 100c1f00 28000000
+# This is the important offset for CIE->pfunc
+#                                   ^~~~~~~~~
+# Then we have an FDE starting from 28000000 above
+# CODE-NEXT: {{[0-9abcdef]*}} 20000000 c8ffffff ffffffff 04000000
+# CODE-NEXT: {{[0-9abcdef]*}} 00000000 08c3ffff ffffffff ff0e109e
+# And a new CIE starts at this 00000018 right below here
+# CODE-NEXT: {{[0-9abcdef]*}} 019d0200 00000000 18000000 00000000
+# CODE-NEXT: {{[0-9abcdef]*}} 037a504c 52000178 1e079b8d ffffff10
+# This is the important offset for its CIE->pfunc     ^~~~~~~~~
\ No newline at end of file
diff --git a/test/mach-o/error-simulator-vs-macosx.yaml b/test/mach-o/error-simulator-vs-macosx.yaml
new file mode 100644 (file)
index 0000000..bd62db3
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s %p/Inputs/hello-world-x86.yaml -o %t && llvm-nm -m %t | FileCheck %s
+# RUN: not lld -flavor darwin -arch i386 -ios_simulator_version_min 5.0 %s %p/Inputs/hello-world-x86.yaml -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+#
+# Test that i386 can link with a macos version but gives an error with a simululator version.
+#
+
+--- !mach-o
+arch:            x86
+OS:              Mac OS X
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x90 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+
+# ERROR: cannot be linked due to incompatible operating systems
diff --git a/test/mach-o/exe-offsets.yaml b/test/mach-o/exe-offsets.yaml
new file mode 100644 (file)
index 0000000..a751507
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start %p/Inputs/libSystem.yaml
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+# Make sure data gets put at offset
+
+--- !native
+defined-atoms:
+   - name:            start
+     scope:           global
+     content:         [ 90 ]
+
+   - name:            _s1
+     type:            data
+     content:         [ 31, 32, 33, 34 ]
+
+   - name:            _s2
+     type:            zero-fill
+     size:            8192
+
+   - name:            _s3
+     type:            zero-fill
+     size:            100
+
+   - name:            _s4
+     type:            data
+     content:         [ 01 ]
+
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __text
+# CHECK:     Segment: __TEXT
+# CHECK:     Size: 0x1
+# CHECK:     Offset: 0
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __data
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x5
+# CHECK:     Offset: 4096
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __bss
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x2064
+# CHECK:     Offset: 0
diff --git a/test/mach-o/exe-segment-overlap.yaml b/test/mach-o/exe-segment-overlap.yaml
new file mode 100644 (file)
index 0000000..a416ee3
--- /dev/null
@@ -0,0 +1,44 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         [ 90 ]
+
+   - name:            _s2
+     type:            data
+     content:         [ 31, 32, 33, 34 ]
+
+   - name:            _kustom
+     scope:           global
+     type:            unknown
+     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+     section-choice:  custom-required
+     section-name:    __CUST/__custom
+
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __text
+# CHECK:     Segment: __TEXT
+# CHECK:     Size: 0x1
+# CHECK:     Offset: 4095
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __data
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x4
+# CHECK:     Offset: 4096
+# CHECK:     SectionData (
+# CHECK-NEXT: 0000: 31323334
+# CHECK-NEXT: )
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __custom{{ }}
+# CHECK:     Segment: __CUST{{ }}
+# CHECK:     Size: 0x8
+# CHECK:     Offset: 8192
+# CHECK:     SectionData (
+# CHECK-NEXT: 0000: 01020304 05060708
+# CHECK-NEXT: )
diff --git a/test/mach-o/executable-exports.yaml b/test/mach-o/executable-exports.yaml
new file mode 100644 (file)
index 0000000..b14e2d2
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t  && \
+# RUN: llvm-objdump -exports-trie %t | FileCheck %s
+#
+#
+# Tests that exports trie builds properly.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+global-symbols:
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _myRegular
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000003
+...
+
+# CHECK-NOT:  _myHidden
+# CHECK:      0x00000FFD  _myRegular
+# CHECK:      0x00000FFE  _myWeak [weak_def]
diff --git a/test/mach-o/exported_symbols_list-dylib.yaml b/test/mach-o/exported_symbols_list-dylib.yaml
new file mode 100644 (file)
index 0000000..f526140
--- /dev/null
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t \
+# RUN:      -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t2 \
+# RUN:      -exported_symbol _foo -exported_symbol _b  && \
+# RUN: llvm-nm -m %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t3 \
+# RUN:      -unexported_symbol _bar -unexported_symbol _a  && \
+# RUN: llvm-nm -m %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -dead_strip -o %t \
+# RUN:      -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck -check-prefix=CHECK_DEAD %s
+#
+# Test -exported_symbols_list and -exported_symbol properly changes visibility.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) non-external (was a private external) _bar
+# CHECK: (__TEXT,__text) external _foo
+
+# CHECK_DEAD-NOT:  (__DATA,__data) non-external (was a private external) _a
+# CHECK_DEAD:      (__DATA,__data) external _b
+# CHECK_DEAD-NOT:  (__TEXT,__text) non-external (was a private external) _bar
+# CHECK_DEAD:      (__TEXT,__text) external _foo
diff --git a/test/mach-o/exported_symbols_list-obj.yaml b/test/mach-o/exported_symbols_list-obj.yaml
new file mode 100644 (file)
index 0000000..31b325c
--- /dev/null
@@ -0,0 +1,67 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t -exported_symbol _bar \
+# RUN:    && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t2 -keep_private_externs \
+# RUN:      -exported_symbol _bar && \
+# RUN: llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# RUN: not lld -flavor darwin -arch x86_64 -r  %s -o %t3  \
+# RUN:      -exported_symbol _foo 2> %t4
+
+# Test -exported_symbols_list properly changes visibility in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT  ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) non-external (was a private external) _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/exported_symbols_list-undef.yaml b/test/mach-o/exported_symbols_list-undef.yaml
new file mode 100644 (file)
index 0000000..1e2fc82
--- /dev/null
@@ -0,0 +1,55 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2
+#
+# Test -exported_symbol fails if exported symbol not found.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) private external _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) private external _bar
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/fat-archive.yaml b/test/mach-o/fat-archive.yaml
new file mode 100644 (file)
index 0000000..86828d6
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN:    -L %p/Inputs -lfoo %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that fat archives are handled.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/filelist.yaml b/test/mach-o/filelist.yaml
new file mode 100644 (file)
index 0000000..28bfeb7
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: lld -flavor darwin -test_file_usage  \
+# RUN:    -filelist %p/Inputs/full.filelist \
+# RUN:        -path_exists /foo/bar/a.o \
+# RUN:        -path_exists /foo/bar/b.o \
+# RUN:        -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -test_file_usage -t \
+# RUN:    -filelist %p/Inputs/partial.filelist,/foo \
+# RUN:        -path_exists /foo/bar/a.o \
+# RUN:        -path_exists /foo/bar/b.o \
+# RUN:        -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Found filelist entry /foo/bar/a.o
+# CHECK: Found filelist entry /foo/bar/b.o
+# CHECK: Found filelist entry /foo/x.a
diff --git a/test/mach-o/flat_namespace_undef_error.yaml b/test/mach-o/flat_namespace_undef_error.yaml
new file mode 100644 (file)
index 0000000..904b9c7
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/libSystem.yaml 2>&1 | FileCheck %s
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
+
+# Make sure we error out for -flat_namespace -undefined error.
+# CHECK: Undefined symbol: : _bar
diff --git a/test/mach-o/flat_namespace_undef_suppress.yaml b/test/mach-o/flat_namespace_undef_suppress.yaml
new file mode 100644 (file)
index 0000000..5152a1c
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/libSystem.yaml
+#
+# Sanity check '-flat_namespace -undefined suppress'.
+# This should pass without error, even though '_bar' is undefined.
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
diff --git a/test/mach-o/force_load-dylib.yaml b/test/mach-o/force_load-dylib.yaml
new file mode 100644 (file)
index 0000000..c8f559b
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN:     -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \
+# RUN:      -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+#
+# Test -all_load does not break linking with dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/force_load-x86_64.yaml b/test/mach-o/force_load-x86_64.yaml
new file mode 100644 (file)
index 0000000..1be216c
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/libSystem.yaml \
+# RUN:      %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/libSystem.yaml \
+# RUN:      -force_load %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck --check-prefix=CHECKF %s
+#
+# Test that -force_load causes members of static library to be loaded.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:      {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK-NOT:   {{[0-9a-f]+}} (__TEXT,__text) external _main
+
+# CHECKF:     {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECKF:     {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECKF-NOT: {{[0-9a-f]+}} (__TEXT,__text) external _bar
diff --git a/test/mach-o/framework-user-paths.yaml b/test/mach-o/framework-user-paths.yaml
new file mode 100644 (file)
index 0000000..80d6e3b
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Test framework and SDK search paths.
+#   myFrameworks is not an absolute path, so it should not by found in SDK
+#   /Custom/Frameworks should be found in SDK
+#   /opt/Frameworks should not be found in SDK
+#   /System/Library/Frameworks is implicit and should be in SDK
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists myFrameworks \
+# RUN:        -path_exists myFrameworks/my.framework/my \
+# RUN:        -path_exists /opt/Frameworks \
+# RUN:        -path_exists /opt/Frameworks/other.framework/other \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /System/Library/Frameworks \
+# RUN:        -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -path_exists /SDK/myFrameworks \
+# RUN:        -path_exists /SDK/myFrameworks/my.framework/my \
+# RUN:        -path_exists /SDK/Custom/Frameworks \
+# RUN:        -path_exists /SDK/Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /SDK/System/Library/Frameworks \
+# RUN:        -path_exists /SDK/System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -syslibroot /SDK \
+# RUN:        -FmyFrameworks \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -F/opt/Frameworks \
+# RUN:        -framework my \
+# RUN:        -framework Bar \
+# RUN:        -framework Foo \
+# RUN:        -framework other \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK:        Framework search paths:
+# CHECK-NEXT:     myFrameworks
+# CHECK-NEXT:     /SDK/Custom/Frameworks
+# CHECK-NEXT:     /opt/Frameworks
+# CHECK-NEXT:     /SDK/System/Library/Frameworks
+# CHECK: Found framework myFrameworks/my.framework/my
+# CHECK: Found framework /SDK/Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found framework /SDK/System/Library/Frameworks/Foo.framework/Foo
+# CHECK: Found framework /opt/Frameworks/other.framework/other
diff --git a/test/mach-o/function-starts-load-command.yaml b/test/mach-o/function-starts-load-command.yaml
new file mode 100644 (file)
index 0000000..9f25189
--- /dev/null
@@ -0,0 +1,32 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -function_starts && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -function_starts -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_FUNCTION_STARTS
+# CHECK:   cmdsize 16
+# CHECK:   dataoff
+# CHECK:   datasize
+
+# NO_FUNCTION_STARTS-NOT: LC_FUNCTION_STARTS
diff --git a/test/mach-o/gcc_except_tab-got-arm64.yaml b/test/mach-o/gcc_except_tab-got-arm64.yaml
new file mode 100644 (file)
index 0000000..7d105ec
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch arm64 %s \
+# RUN: -dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# Make sure that the GOT relocation from gcc_except_tab to the data
+# is not removed.
+
+--- !native
+defined-atoms:   
+  - name:            _main
+    scope:           global
+    content:         [ FD, 7B, BF, A9, FD, 03, 00, 91, FF, 43, 00, D1, 
+                       BF, C3, 1F, B8, 00, 00, 00, 94, BF, 03, 00, 91, 
+                       FD, 7B, C1, A8, C0, 03, 5F, D6 ]
+    alignment:       4
+  - name:            __ZTSP1A
+    scope:           hidden
+    type:            constant
+    content:         [ 50, 31, 41, 00 ]
+    merge:           as-weak
+  - name:            GCC_except_table0
+    type:            unwind-lsda
+    content:         [ FF, 9B, E7, 80, 00, 03, 5B, 00, 00, 00, 00, 1C, 
+                       00, 00, 00, 00, 00, 00, 00, 00, 1C, 00, 00, 00, 
+                       18, 00, 00, 00, 84, 00, 00, 00, 03, 40, 00, 00, 
+                       00, 10, 00, 00, 00, 94, 00, 00, 00, 03, 60, 00, 
+                       00, 00, 20, 00, 00, 00, B4, 00, 00, 00, 05, 80, 
+                       00, 00, 00, 68, 00, 00, 00, 00, 00, 00, 00, 00, 
+                       E8, 00, 00, 00, 08, 00, 00, 00, 28, 01, 00, 00, 
+                       00, F0, 00, 00, 00, 74, 00, 00, 00, 00, 00, 00, 
+                       00, 00, 00, 00, 01, 7D, 01, 00, A8, FF, FF, FF ]
+    alignment:       4
+    references:      
+      - kind:            delta32ToGOT
+        offset:          104
+        target:          __ZTIP1A
+  - name:            __ZTIP1A
+    scope:           hidden
+    type:            data
+    content:         [ 10, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
+                       00, 00, 00, 80, 00, 00, 00, 00, 00, 00, 00, 00, 
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    merge:           as-weak
+    alignment:       16
+shared-library-atoms:
+  - name:            dyld_stub_binder
+    load-name:       /usr/lib/libSystem.B.dylib
+    type:            unknown
+...
+
+# Make sure we have a GOT relocation.
+# This could only have come from __gcc_except_tab to __ZTIP1A
+# CHECK: __got
\ No newline at end of file
diff --git a/test/mach-o/got-order.yaml b/test/mach-o/got-order.yaml
new file mode 100644 (file)
index 0000000..b69877e
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/got-order.yaml \
+# RUN: %p/Inputs/got-order2.yaml -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -bind %t | FileCheck %s
+#
+# Test that GOT slots are sorted by name
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000019
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+global-symbols:
+  - name:            _func
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _aaa
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fff
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _zzz
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:           __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _aaa
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _bar
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _fff
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _foo
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _zazzle
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _zzz
diff --git a/test/mach-o/hello-world-arm64.yaml b/test/mach-o/hello-world-arm64.yaml
new file mode 100644 (file)
index 0000000..75ac4f7
--- /dev/null
@@ -0,0 +1,94 @@
+# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that arm64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xF9,
+                       0x00, 0x01, 0x40, 0xF9, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94,
+                       0x00, 0x00, 0x80, 0x52, 0xFD, 0x7B, 0xC1, 0xA8,
+                       0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000018
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000014
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000002C
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            l_.str
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external ___stdoutp (from libSystem)
+# CHECK:       (undefined) external _fprintf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
diff --git a/test/mach-o/hello-world-armv6.yaml b/test/mach-o/hello-world-armv6.yaml
new file mode 100644 (file)
index 0000000..8a9edee
--- /dev/null
@@ -0,0 +1,64 @@
+# RUN: lld -flavor darwin -arch armv6 %s %p/Inputs/hello-world-armv6.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that armv6 (arm) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            armv6
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x80, 0x40, 0x2D, 0xE9, 0x10, 0x00, 0x9F, 0xE5,
+                       0x0D, 0x70, 0xA0, 0xE1, 0x00, 0x00, 0x8F, 0xE0,
+                       0xFA, 0xFF, 0xFF, 0xEB, 0x00, 0x00, 0xA0, 0xE3,
+                       0x80, 0x80, 0xBD, 0xE8, 0x0C, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-armv7.yaml b/test/mach-o/hello-world-armv7.yaml
new file mode 100644 (file)
index 0000000..1871d68
--- /dev/null
@@ -0,0 +1,76 @@
+# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/hello-world-armv7.yaml -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that armv7 (thumb) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x80, 0xB5, 0x40, 0xF2, 0x06, 0x00, 0x6F, 0x46,
+                       0xC0, 0xF2, 0x00, 0x00, 0x78, 0x44, 0xFF, 0xF7,
+                       0xF8, 0xEF, 0x00, 0x20, 0x80, 0xBD ]
+    relocations:
+      - offset:          0x0000000E
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000016
+      - offset:          0x00000006
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000002
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000016
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000016
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external [Thumb] _main
diff --git a/test/mach-o/hello-world-x86.yaml b/test/mach-o/hello-world-x86.yaml
new file mode 100644 (file)
index 0000000..779b681
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that i386 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x58, 0x8D, 0x80, 0x16, 0x00,
+                       0x00, 0x00, 0x89, 0x04, 0x24, 0xE8, 0xE6, 0xFF,
+                       0xFF, 0xFF, 0x31, 0xC0, 0x83, 0xC4, 0x08, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000E
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000021
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000B
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000021
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-x86_64.yaml b/test/mach-o/hello-world-x86_64.yaml
new file mode 100644 (file)
index 0000000..8803c44
--- /dev/null
@@ -0,0 +1,120 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/hello-world-x86_64.yaml \
+# RUN: -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/hello-world-x86_64.yaml \
+# RUN: -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# Test that x86_64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D,
+                       0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000018
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000011
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          0
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000028
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            L1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            EH_frame0
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000048
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _main.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x0000000000000060
+undefined-symbols:
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       (undefined) external ___stdoutp (from libSystem)
+# CHECK:       (undefined) external _fprintf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) [referenced dynamically] external __mh_execute_header
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
diff --git a/test/mach-o/image-base.yaml b/test/mach-o/image-base.yaml
new file mode 100644 (file)
index 0000000..d274621
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/libSystem.yaml
+# RUN: llvm-readobj -macho-segment %t | FileCheck %s
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 1000 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-OVERLAP
+# RUN: not lld -flavor darwin -arch x86_64 -image_base hithere %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         []
+
+# CHECK: Segment {
+# CHECK:   Cmd: LC_SEGMENT_64
+# CHECK:   Name: __TEXT
+# CHECK-NEXT:   Size: 152
+# CHECK-NEXT:   vmaddr: 0x31415926000
+# CHECK-NEXT:   vmsize: 0x1000
+
+
+# CHECK-ERROR-MISPAGED: error: image_base must be a multiple of page size (0x1000)
+
+# CHECK-ERROR-OVERLAP: error: image_base overlaps with __PAGEZERO
+
+# CHECK-ERROR-NOTHEX: error: image_base expects a hex number
diff --git a/test/mach-o/infer-arch.yaml b/test/mach-o/infer-arch.yaml
new file mode 100644 (file)
index 0000000..c09c94d
--- /dev/null
@@ -0,0 +1,29 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s -r -o %t \
+# RUN: && lld -flavor darwin -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test linker can detect architecture without -arch option.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK:  - name:            _foo
diff --git a/test/mach-o/interposing-section.yaml b/test/mach-o/interposing-section.yaml
new file mode 100644 (file)
index 0000000..4f6bafc
--- /dev/null
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/interposing-section.yaml \
+# RUN: -dylib -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s -r -o %t1
+# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
+#
+# Test that interposing section is preserved by linker.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __interpose
+    type:            S_INTERPOSING
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+local-symbols:
+  - name:            _my_open
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __interpose_open
+    type:            N_SECT
+    sect:            2
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000010
+undefined-symbols:
+  - name:            _open
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:         sectname __interposing
+# CHECK:          segname __DATA
+# CHECK:             type S_INTERPOSING
+
diff --git a/test/mach-o/keep_private_externs.yaml b/test/mach-o/keep_private_externs.yaml
new file mode 100644 (file)
index 0000000..e7adf18
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t \
+# RUN:    && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t2 -keep_private_externs \
+# RUN:    && llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT  ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) external _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) external _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/lazy-bind-x86_64.yaml b/test/mach-o/lazy-bind-x86_64.yaml
new file mode 100644 (file)
index 0000000..ee3e227
--- /dev/null
@@ -0,0 +1,111 @@
+# REQUIRES: x86
+
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/lazy-bind-x86_64.yaml  %p/Inputs/lazy-bind-x86_64-2.yaml \
+# RUN: %p/Inputs/lazy-bind-x86_64-3.yaml -o %t  \
+# RUN:   %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -lazy-bind %t | FileCheck %s
+# RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s
+# RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s
+#
+# Test that correct two-level namespace ordinals are used for lazy bindings.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00,
+                       0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000015
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000007
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _baz
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:    libbar        _bar
+# CHECK:    libbaz        _baz
+# CHECK:    libfoo        _foo
+
+
+# CHECK-NM:   (undefined) external _bar (from libbar)
+# CHECK-NM:   (undefined) external _baz (from libbaz)
+# CHECK-NM:   (undefined) external _foo (from libfoo)
+
+
+# CHECK-HELPERS:Disassembly of section __TEXT,__stub_helper:
+# CHECK-HELPERS:       68 00 00 00 00            pushq $0
+# CHECK-HELPERS:       68 10 00 00 00            pushq $16
+# CHECK-HELPERS:       68 20 00 00 00            pushq $32
+
+# Make sure the stub helper is correctly aligned
+# CHECK-DYLIBS:   sectname __stub_helper
+# CHECK-DYLIBS-NEXT:    segname __TEXT
+# CHECK-DYLIBS-NEXT:       addr
+# CHECK-DYLIBS-NEXT:       size
+# CHECK-DYLIBS-NEXT:     offset
+# CHECK-DYLIBS-NEXT:      align 2^2 (4)
+
+# Make sure the __nl_symbol_ptr section is used instea of __got as this is x86_64
+# CHECK-DYLIBS:   sectname __nl_symbol_ptr
+# CHECK-DYLIBS-NEXT:    segname __DATA
+
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbar.dylib (offset 24)
+# CHECK-DYLIBS:       current version 2.3.0
+# CHECK-DYLIBS: compatibility version 1.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libfoo.dylib (offset 24)
+# CHECK-DYLIBS:       current version 3.4.0
+# CHECK-DYLIBS: compatibility version 2.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbaz.dylib (offset 24)
+# CHECK-DYLIBS:       current version 4.5.0
+# CHECK-DYLIBS: compatibility version 3.0.0
+
+
diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml
new file mode 100644 (file)
index 0000000..5005f01
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1  | FileCheck %s
+
+--- !native
+undefined-atoms:
+    - name: _from_myshared
+    - name: _from_mystatic
+    - name: _from_fileo
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _from_fileo
+# CHECK:     content:         [ 2A, 00, 00, 00 ]
+# CHECK:   - name:            _from_mystatic
+# CHECK:     content:         [ 02, 00, 00, 00 ]
+# CHECK: shared-library-atoms:
+# CHECK:   - name:            _from_myshared
+# CHECK:     load-name:       libmyshared.dylib
diff --git a/test/mach-o/library-order.yaml b/test/mach-o/library-order.yaml
new file mode 100644 (file)
index 0000000..f9cd5a6
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
+# RUN:    %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that if library is before object file on command line, it still is used.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/library-rescan.yaml b/test/mach-o/library-rescan.yaml
new file mode 100644 (file)
index 0000000..a8a0ca8
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
+# RUN:    %s -o %t  %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that static libraries are automatically rescanned (bar needs foo).
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _bar
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/libresolve-bizarre-root-override.yaml b/test/mach-o/libresolve-bizarre-root-override.yaml
new file mode 100644 (file)
index 0000000..c65ca31
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/lib/libSystem.dylib \
+# RUN:        -syslibroot /Applications/MySDK \
+# RUN:        -syslibroot / \
+# RUN:        -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# When the last -syslibroot is simply "/", all of them get discarded. So in this
+# case, only /usr/lib should show up.
+
+# CHECK: Library search paths:
+# CHECK:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Unable to find library for -lSystem
diff --git a/test/mach-o/libresolve-multiple-syslibroots.yaml b/test/mach-o/libresolve-multiple-syslibroots.yaml
new file mode 100644 (file)
index 0000000..0b63eb6
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MyFirstSDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySecondSDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MyFirstSDK/usr/local/lib/libSystem.a \
+# RUN:        -path_exists /Applications/MySecondSDK/usr/local/lib/libSystem.a \
+# RUN:        -syslibroot /Applications/MyFirstSDK \
+# RUN:        -syslibroot /Applications/MySecondSDK \
+# RUN:        -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Library search paths:
+# CHECK:     /usr/lib
+# CHECK:     /Applications/MyFirstSDK/usr/local/lib
+# CHECK:     /Applications/MySecondSDK/usr/local/lib
+# CHECK: Found library /Applications/MyFirstSDK/usr/local/lib/libSystem.a
diff --git a/test/mach-o/libresolve-one-syslibroot.yaml b/test/mach-o/libresolve-one-syslibroot.yaml
new file mode 100644 (file)
index 0000000..f9042fc
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib/libSystem.a \
+# RUN:        -path_exists /hasFoo \
+# RUN:        -path_exists /hasFoo/foo.o \
+# RUN:        -syslibroot /Applications/MySDK \
+# RUN:        -L/hasFoo \
+# RUN:        -lSystem -lfoo.o \
+# RUN: 2>&1 | FileCheck %s
+
+# When just one -syslibroot is specified, we apparently want to skip *system*
+# paths that aren't found. User ones should still get added. In this case
+# /usr/lib exists, but not the equivalent in the -syslibroot, so there should be
+# no mention of /usr/lib.
+
+# CHECK: Library search paths:
+# CHECK:     /hasFoo
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK:     /Applications/MySDK/usr/local/lib
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Found library /Applications/MySDK/usr/local/lib/libSystem.a
+# CHECK: Found library /hasFoo/foo.o
diff --git a/test/mach-o/libresolve-simple.yaml b/test/mach-o/libresolve-simple.yaml
new file mode 100644 (file)
index 0000000..ffb045f
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/local/lib \
+# RUN:        -path_exists /usr/lib/libSystem.dylib \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -lSystem -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /hasBar
+# CHECK:     /usr/lib
+# CHECK:     /usr/local/lib
+# CHECK: Found library /usr/lib/libSystem.dylib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-user-paths.yaml b/test/mach-o/libresolve-user-paths.yaml
new file mode 100644 (file)
index 0000000..9fe8856
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -path_exists /SDK/hasFoo \
+# RUN:        -path_exists /SDK/hasFoo/libFoo.dylib \
+# RUN:        -path_exists /SDK/hasBar \
+# RUN:        -path_exists /SDK/hasBar/libBar.dylib \
+# RUN:        -syslibroot /SDK \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /SDK/hasBar
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /SDK/hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-z.yaml b/test/mach-o/libresolve-z.yaml
new file mode 100644 (file)
index 0000000..1df7ece
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/local/lib \
+# RUN:        -path_exists /usr/lib/libSystem.dylib \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -Z \
+# RUN:        -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /hasBar
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/linker-as-ld.yaml b/test/mach-o/linker-as-ld.yaml
new file mode 100644 (file)
index 0000000..f0bf189
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: mkdir -p %t.dir && cp `which lld` %t.dir/ld \
+# RUN:  && %t.dir/ld -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/linker-as-ld.yaml -o %t \
+# RUN:  && llvm-nm %t | FileCheck %s
+#
+# Test linker run as "ld" on darwin works as darwin linker.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:                 T _main
diff --git a/test/mach-o/lit.local.cfg b/test/mach-o/lit.local.cfg
new file mode 100644 (file)
index 0000000..739a099
--- /dev/null
@@ -0,0 +1,4 @@
+
+# mach-o test cases encode input files in yaml and use .yaml extension
+config.suffixes = ['.yaml']  
+config.excludes = ['Inputs']
diff --git a/test/mach-o/mach_header-cpusubtype.yaml b/test/mach-o/mach_header-cpusubtype.yaml
new file mode 100644 (file)
index 0000000..fa9024f
--- /dev/null
@@ -0,0 +1,34 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.4 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_LIB64
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=LIB64
+# RUN: lld -flavor darwin -arch x86_64 -dylib -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=DYLIB
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# NO_LIB64: MH_MAGIC_64  X86_64        ALL 0x00     EXECUTE
+# LIB64: MH_MAGIC_64  X86_64        ALL LIB64     EXECUTE
+# DYLIB: MH_MAGIC_64 X86_64 ALL 0x00 DYLIB
diff --git a/test/mach-o/mh_bundle_header.yaml b/test/mach-o/mh_bundle_header.yaml
new file mode 100644 (file)
index 0000000..e440141
--- /dev/null
@@ -0,0 +1,54 @@
+# RUN: lld -flavor darwin -arch x86_64  %s -bundle -o %t %p/Inputs/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64  %s -bundle -dead_strip -o %t %p/Inputs/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_bundle_header symbol is available for bundles
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __mh_bundle_header
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: __mh_bundle_header
+# CHECK:      _foo
diff --git a/test/mach-o/mh_dylib_header.yaml b/test/mach-o/mh_dylib_header.yaml
new file mode 100644 (file)
index 0000000..96b67aa
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch x86_64  %s -dylib -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_dylib_header symbol is available for dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __mh_dylib_header
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK_NOT:   __mh_dylib_header
+# CHECK:      _foo
diff --git a/test/mach-o/objc-category-list-atom.yaml b/test/mach-o/objc-category-list-atom.yaml
new file mode 100644 (file)
index 0000000..e061171
--- /dev/null
@@ -0,0 +1,70 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_catlist
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    alignment:       8
+    address:         0x00000000000003F8
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+undefined-symbols: 
+  - name:            __category1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __category2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# Make sure we atomize the category list section by pointer sized atoms.
+
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:   
+# CHECK:   - type:            objc-category-list
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     alignment:       8
+# CHECK:     references:      
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __category2
+# CHECK:   - type:            objc-category-list
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     alignment:       8
+# CHECK:     references:      
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __category1
+# CHECK: undefined-atoms: 
+# CHECK:   - name:            __category1
+# CHECK:   - name:            __category2
+# CHECK: ...
diff --git a/test/mach-o/objc-image-info-host-vs-simulator.yaml b/test/mach-o/objc-image-info-host-vs-simulator.yaml
new file mode 100644 (file)
index 0000000..f836a74
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+# The file is built for the host, but the objc image info flags are for
+# the simulator.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: {{.*}} cannot be linked.  It contains ObjC built for the simulator while we are linking a non-simulator target
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-invalid-size.yaml b/test/mach-o/objc-image-info-invalid-size.yaml
new file mode 100644 (file)
index 0000000..47fce88
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} should be 8 bytes in size
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-invalid-version.yaml b/test/mach-o/objc-image-info-invalid-version.yaml
new file mode 100644 (file)
index 0000000..04d62e9
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} should have version=0
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-mismatched-swift-version.yaml b/test/mach-o/objc-image-info-mismatched-swift-version.yaml
new file mode 100644 (file)
index 0000000..efb7c31
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00 ]
+...
+
+# CHECK: different swift versions
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-pass-output.yaml b/test/mach-o/objc-image-info-pass-output.yaml
new file mode 100644 (file)
index 0000000..7fc95a8
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+
+# Make sure that we have an objc image info in the output.  It should have
+# been generated by the objc pass.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 ]
+...
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - scope:           hidden
+# CHECK:     type:            objc-image-info
+# CHECK:     content:         [ 00, 00, 00, 00, 20, 02, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK: ...
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-simulator-vs-host.yaml b/test/mach-o/objc-image-info-simulator-vs-host.yaml
new file mode 100644 (file)
index 0000000..c4f9bd5
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+# The file is built for the simulator, but the objc image info flags are for
+# the host.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: {{.*}} cannot be linked.  It contains ObjC built for a non-simulator target while we are linking a simulator target
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-unsupported-gc.yaml b/test/mach-o/objc-image-info-unsupported-gc.yaml
new file mode 100644 (file)
index 0000000..9f98369
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} uses GC. This is not supported
\ No newline at end of file
diff --git a/test/mach-o/objc_export_list.yaml b/test/mach-o/objc_export_list.yaml
new file mode 100644 (file)
index 0000000..e67a4c7
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t \
+# RUN:     -exported_symbol .objc_class_name_Foo %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that exported objc classes can be specificed using old naming
+# (.e.g .objc_class_name_Foo instead of _OBJC_CLASS_$_Foo)
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __DATA
+    section:         __objc_data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000028
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            '_OBJC_CLASS_$_Foo'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            '_OBJC_METACLASS_$_Foo'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000028
+...
+
+# CHECK:  (__DATA,__objc_data) external _OBJC_CLASS_$_Foo
+# CHECK:  (__DATA,__objc_data) external _OBJC_METACLASS_$_Foo
diff --git a/test/mach-o/order_file-basic.yaml b/test/mach-o/order_file-basic.yaml
new file mode 100644 (file)
index 0000000..3fea9be
--- /dev/null
@@ -0,0 +1,75 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml \
+# RUN:     -order_file %p/Inputs/order_file-basic.order \
+# RUN:     -force_load %p/Inputs/libfoo.a -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test -order_file
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000014
+    content:         [ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+                       0x07, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _data1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _data2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000018
+  - name:            _data3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000001C
+  - name:            _func1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _func3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000002
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000003
+...
+
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func2
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func1
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func3
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data3
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data1
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data2
+
diff --git a/test/mach-o/parse-aliases.yaml b/test/mach-o/parse-aliases.yaml
new file mode 100644 (file)
index 0000000..54da2d6
--- /dev/null
@@ -0,0 +1,90 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test multiple labels to same address parse into aliases.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3 ]
+local-symbols:
+  - name:            _pad
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _myStaticAlias1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myStaticAlias3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myStaticAlias2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+global-symbols:
+  - name:            _myGlobalFunc1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalFunc2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalFunc3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias1
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias2
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias3
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _pad
+# CHECK:     scope:           global
+# CHECK:     content:         [ CC ]
+# CHECK:   - name:            _myStaticAlias1
+# CHECK:   - name:            _myStaticAlias2
+# CHECK:   - name:            _myStaticAlias3
+# CHECK:   - name:            _myHiddenAlias1
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myHiddenAlias2
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myHiddenAlias3
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myGlobalFunc1
+# CHECK:     scope:           global
+# CHECK:   - name:            _myGlobalFunc2
+# CHECK:     scope:           global
+# CHECK:   - name:            _myGlobalFunc3
+# CHECK:     scope:           global
+# CHECK:     content:         [ C3 ]
diff --git a/test/mach-o/parse-arm-relocs.yaml b/test/mach-o/parse-arm-relocs.yaml
new file mode 100644 (file)
index 0000000..abeb3dd
--- /dev/null
@@ -0,0 +1,818 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t   | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing of armv7 relocations.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xF0, 0x4E, 0xF8, 0x00, 0xF0, 0x4E, 0xF8,
+                       0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF,
+                       0xFF, 0xF7, 0xF6, 0xBF, 0x40, 0xF2, 0x72, 0x01,
+                       0xC0, 0xF2, 0x00, 0x01, 0x40, 0xF2, 0x7A, 0x02,
+                       0xC0, 0xF2, 0x00, 0x02, 0x40, 0xF2, 0x29, 0x01,
+                       0xC0, 0xF2, 0x00, 0x01, 0x79, 0x44, 0x40, 0xF2,
+                       0xA0, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+                       0xA8, 0x04, 0xC0, 0xF2, 0x00, 0x04, 0x40, 0xF2,
+                       0x57, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+                       0x00, 0x05, 0xC0, 0xF2, 0x00, 0x05, 0x40, 0xF2,
+                       0x08, 0x06, 0xC0, 0xF2, 0x00, 0x06, 0xC0, 0x46,
+                       0x10, 0x00, 0x00, 0xEB, 0x10, 0x00, 0x00, 0xEB,
+                       0xE6, 0xFF, 0xFF, 0xEB, 0xE6, 0xFF, 0xFF, 0xEB,
+                       0xE4, 0xFF, 0xFF, 0xEA, 0x20, 0x10, 0x00, 0xE3,
+                       0x00, 0x10, 0x40, 0xE3, 0x28, 0x20, 0x00, 0xE3,
+                       0x00, 0x20, 0x40, 0xE3, 0x0F, 0x10, 0x81, 0xE0,
+                       0xA0, 0x30, 0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3,
+                       0xA8, 0x40, 0x00, 0xE3, 0x00, 0x40, 0x40, 0xE3,
+                       0x00, 0x50, 0x00, 0xE3, 0x00, 0x50, 0x40, 0xE3,
+                       0x08, 0x60, 0x00, 0xE3, 0x00, 0x60, 0x40, 0xE3 ]
+    relocations:
+      - offset:          0x0000009C
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000098
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000094
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000090
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000008C
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x000000A8
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000088
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000084
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x000000A0
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000080
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000078
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000074
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000070
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x0000006C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000068
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000064
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000060
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x0000005C
+        scattered:       true
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        value:           0x000000A0
+      - offset:          0x00000058
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000052
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000004E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000004A
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000046
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000042
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000057
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000003E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000003A
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x000000A8
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000036
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000032
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x000000A0
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000002E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000056
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000024
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000056
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x0000007A
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000072
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000014
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000010
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x0000000C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000004
+        scattered:       true
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x00000000000000A0
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0xA4, 0xFF, 0xFF, 0xFF,
+                       0xA4, 0xFF, 0xFF, 0xFF, 0x45, 0xFF, 0xFF, 0xFF,
+                       0x45, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000C0
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000BC
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000058
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000B8
+      - offset:          0x00000014
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000058
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000B4
+      - offset:          0x00000010
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x0000000C
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            _foo_thumb
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    sect:            2
+    value:           0x00000000000000A0
+  - name:            _t1
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000056
+  - name:            _foo_arm
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000058
+undefined-symbols:
+  - name:            _undef
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:  defined-atoms:
+# CHECK:    - name:            _x
+# CHECK:      type:            data
+# CHECK:      references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          4
+# CHECK:          target:          _foo_thumb
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          _foo_thumb
+# CHECK:          addend:          4
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          20
+# CHECK:          target:          _foo_arm
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          24
+# CHECK:          target:          _foo_arm
+# CHECK:          addend:          4
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          28
+# CHECK:          target:          _foo_thumb
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          32
+# CHECK:          target:          _foo_thumb
+# CHECK:          addend:          4
+# CHECK:    - name:            _foo_thumb
+# CHECK:      references:
+# CHECK:        - kind:            modeThumbCode
+# CHECK:          offset:          0
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          0
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          4
+# CHECK:          target:          _x
+# CHECK:          addend:          4
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          8
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            thumb_b22
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          20
+# CHECK:          target:          _x
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          24
+# CHECK:          target:          _x
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          28
+# CHECK:          target:          _x
+# CHECK:          addend:          -38
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          32
+# CHECK:          target:          _x
+# CHECK:          addend:          -38
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          36
+# CHECK:          target:          _t1
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          40
+# CHECK:          target:          _t1
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          46
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          50
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          54
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          58
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          62
+# CHECK:          target:          _t1
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          66
+# CHECK:          target:          _t1
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          70
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          74
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          78
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          82
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:    - name:            _t1
+# CHECK:      content:         [ C0, 46 ]
+# CHECK:      references:
+# CHECK:        - kind:            modeThumbCode
+# CHECK:          offset:          0
+# CHECK:    - name:            _foo_arm
+# CHECK:      references:
+# CHECK-NOT:    - kind:            modeThumbCode
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          0
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          4
+# CHECK:          target:          _x
+# CHECK:          addend:          4
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          8
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            arm_b24
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw_funcRel
+# CHECK:          offset:          20
+# CHECK:          target:          _x
+# CHECK:          addend:          -40
+# CHECK:        - kind:            arm_movt_funcRel
+# CHECK:          offset:          24
+# CHECK:          target:          _x
+# CHECK:          addend:          -40
+# CHECK:        - kind:            arm_movw_funcRel
+# CHECK:          offset:          28
+# CHECK:          target:          _x
+# CHECK:          addend:          -32
+# CHECK:        - kind:            arm_movt_funcRel
+# CHECK:          offset:          32
+# CHECK:          target:          _x
+# CHECK:          addend:          -32
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          40
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          44
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          48
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          52
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          56
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          60
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          64
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          68
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:  undefined-atoms:
+# CHECK:    - name:            _undef
+
+
+
+
+#      .align  2
+#      .code   16
+#  .thumb_func _foo_thumb
+#_foo_thumb:
+#  bl    _x
+#  bl    _x+4
+#  bl    _undef
+#  bl    _undef+4
+#  b     _undef
+#  movw        r1, :lower16:(_x-L1)
+#  movt        r1, :upper16:(_x-L1)
+#  movw        r2, :lower16:(_x+8-L1)
+#  movt        r2, :upper16:(_x+8-L1)
+#  movw        r1, :lower16:(_t1-L1)
+#  movt        r1, :upper16:(_t1-L1)
+#      add     r1, pc
+#L1:
+#      movw    r3, :lower16:_x
+#      movt    r3, :upper16:_x
+#      movw    r4, :lower16:_x+8
+#      movt    r4, :upper16:_x+8
+#      movw    r3, :lower16:_t1
+#      movt    r3, :upper16:_t1
+#      movw    r5, :lower16:_undef
+#      movt    r5, :upper16:_undef
+#      movw    r6, :lower16:_undef+8
+#      movt    r6, :upper16:_undef+8
+#
+#  .thumb_func _t1
+#_t1:
+#  nop
+#
+#
+#      .code   32
+#  .align 2
+#_foo_arm:
+#  bl    _x
+#  bl    _x+4
+#  bl    _undef
+#  bl    _undef+4
+#  b     _undef
+#  movw        r1, :lower16:(_x-L2)
+#  movt        r1, :upper16:(_x-L2)
+#  movw        r2, :lower16:(_x+8-L2)
+#  movt        r2, :upper16:(_x+8-L2)
+#      add     r1, pc
+#L2:
+#      movw    r3, :lower16:_x
+#      movt    r3, :upper16:_x
+#      movw    r4, :lower16:_x+8
+#      movt    r4, :upper16:_x+8
+#      movw    r5, :lower16:_undef
+#      movt    r5, :upper16:_undef
+#      movw    r6, :lower16:_undef+8
+#      movt    r6, :upper16:_undef+8
+#
+#
+#  .data
+#_x:  .long 0
+#    .long _foo_thumb
+#    .long _foo_thumb+4
+#    .long _undef
+#    .long _undef+4
+#    .long _foo_arm - .
+#    .long _foo_arm+4- .
+#    .long _foo_thumb - .
+#    .long _foo_thumb+4 - .
+#
diff --git a/test/mach-o/parse-cfstring32.yaml b/test/mach-o/parse-cfstring32.yaml
new file mode 100644 (file)
index 0000000..8e746f2
--- /dev/null
@@ -0,0 +1,94 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00 ]
+  - segment:         __DATA
+    section:         __cfstring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+                       0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000018
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000010
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+undefined-symbols:
+  - name:            ___CFConstantStringClassReference
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:  - ref-name:        [[STR1:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        [[STR2:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          0
+# CHECK:          target:          ___CFConstantStringClassReference
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          [[STR1]]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          0
+# CHECK:          target:          ___CFConstantStringClassReference
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          [[STR2]]
+# CHECK:undefined-atoms:
+# CHECK:  - name:            ___CFConstantStringClassReference
diff --git a/test/mach-o/parse-cfstring64.yaml b/test/mach-o/parse-cfstring64.yaml
new file mode 100644 (file)
index 0000000..b90277f
--- /dev/null
@@ -0,0 +1,108 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of CFString constants.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00 ]
+  - segment:         __DATA
+    section:         __cfstring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+local-symbols:
+  - name:            Lstr1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            Lstr2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000006
+undefined-symbols:
+  - name:            ___CFConstantStringClassReference
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:defined-atoms:
+# CHECK:  - ref-name:        L000
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        L001
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          ___CFConstantStringClassReference
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          16
+# CHECK:        target:          L000
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          ___CFConstantStringClassReference
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          16
+# CHECK:        target:          L001
+# CHECK:undefined-atoms:
+# CHECK:  - name:            ___CFConstantStringClassReference
+
diff --git a/test/mach-o/parse-compact-unwind32.yaml b/test/mach-o/parse-compact-unwind32.yaml
new file mode 100644 (file)
index 0000000..ff613f0
--- /dev/null
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3, 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00,
+                       0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+                       0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000014
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000A
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 10, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-compact-unwind64.yaml b/test/mach-o/parse-compact-unwind64.yaml
new file mode 100644 (file)
index 0000000..af89674
--- /dev/null
@@ -0,0 +1,76 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+                       0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000020
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK:                        00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 10, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK:                        00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
diff --git a/test/mach-o/parse-data-in-code-armv7.yaml b/test/mach-o/parse-data-in-code-armv7.yaml
new file mode 100644 (file)
index 0000000..720f24d
--- /dev/null
@@ -0,0 +1,157 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/libSystem.yaml \
+# RUN:   && llvm-objdump -macho -private-headers %t3.dylib | FileCheck --check-prefix=CHECK2 %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0xBF,
+                       0x00, 0xF0, 0x20, 0xE3, 0x0A, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3 ]
+local-symbols:
+  - name:            _foo_thumb
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _foo_arm
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000018
+dataInCode:
+  - offset:          0x00000004
+    length:          0x0004
+    kind:            DICE_KIND_DATA
+  - offset:          0x00000008
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x0000000C
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE16
+  - offset:          0x00000010
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE8
+  - offset:          0x0000001C
+    length:          0x0004
+    kind:            DICE_KIND_DATA
+  - offset:          0x00000020
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x00000024
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE16
+  - offset:          0x00000028
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE8
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _foo_thumb
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          4
+# CHECK:         addend:          1
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          8
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          12
+# CHECK:         addend:          3
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          16
+# CHECK:         addend:          2
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          20
+# CHECK:   - name:            _foo_arm
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          4
+# CHECK:         addend:          1
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          8
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          12
+# CHECK:         addend:          3
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          16
+# CHECK:         addend:          2
+# CHECK:       - kind:            modeArmCode
+# CHECK:         offset:          20
+
+
+# CHECK2:      cmd LC_DATA_IN_CODE
+# CHECK2:  cmdsize 16
+# CHECK2: datasize 64
+
+
+#      .code   16
+#  .thumb_func _foo_thumb
+#_foo_thumb:
+# nop
+# nop
+#
+#      .data_region
+#  .long 0
+#      .end_data_region
+#
+#      .data_region jt32
+#  .long 1
+#      .end_data_region
+#
+#      .data_region jt16
+#  .long 2
+#      .end_data_region
+#
+#      .data_region jt8
+#  .long 3
+#      .end_data_region
+#
+#  nop
+#  nop
+#
+#
+#
+#      .code   32
+#  .align 2
+#_foo_arm:
+#  nop
+#
+#      .data_region
+#  .long 10
+#      .end_data_region
+#
+#      .data_region jt32
+#  .long 11
+#      .end_data_region
+#
+#      .data_region jt16
+#  .long 12
+#      .end_data_region
+#
+#      .data_region jt8
+#  .long 13
+#      .end_data_region
+#
+#  nop
+#
diff --git a/test/mach-o/parse-data-in-code-x86.yaml b/test/mach-o/parse-data-in-code-x86.yaml
new file mode 100644 (file)
index 0000000..4393444
--- /dev/null
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x90, 0x90, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
+                       0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x03, 0x00,
+                       0x00, 0x00 ]
+local-symbols:
+  - name:            _func1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func2
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+dataInCode:
+  - offset:          0x00000002
+    length:          0x0008
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x0000000E
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _func1
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          2
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeCode
+# CHECK:         offset:          10
+# CHECK:   - name:            _func2
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          3
+# CHECK:         addend:          4
+# CHECK-NOT:   - kind:            modeData
+
+
+
+
+#
+#_func1:
+#  nop
+#  nop
+#  .data_region jt32
+#  .long 1
+#  .long 2
+#  .end_data_region
+#  nop
+#
+#
+# _func2:
+#  nop
+#  nop
+#  nop
+#  .data_region jt32
+#  .long 3
+#  .end_data_region
+#
diff --git a/test/mach-o/parse-data-relocs-arm64.yaml b/test/mach-o/parse-data-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..0edd646
--- /dev/null
@@ -0,0 +1,244 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 data relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000004
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC0, 0xFF, 0xFF, 0xFF, 0xBE, 0xFF, 0xFF, 0xFF,
+                       0xB0, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000050
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            ARM64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000040
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000038
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000028
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000028
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000018
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000008
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+local-symbols:
+  - name:            _v1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000000C
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        L000
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            _v1
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 08, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00, E0, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, DC, FF, FF, FF, FF, FF, FF, FF,
+# CHECK:                        {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, C0, FF, FF, FF, BE, FF, FF, FF,
+# CHECK:                        {{B0|B8}}, {{..}}, FF, FF ]
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          8
+# CHECK:         target:          _foo
+# CHECK:         addend:          8
+# CHECK:       - kind:            pointer64ToGOT
+# CHECK:         offset:          16
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          24
+# CHECK:         target:          _foo
+# CHECK:         addend:          24
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          32
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          40
+# CHECK:         target:          _foo
+# CHECK:         addend:          4
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          48
+# CHECK:         target:          L000
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          56
+# CHECK:         target:          _foo
+# CHECK:         addend:          4
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          64
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          68
+# CHECK:         target:          _foo
+# CHECK:         addend:          2
+# CHECK:       - kind:            delta32ToGOT
+# CHECK:         offset:          72
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:  - name:            _bar
+# CHECK:    scope:           global
+# CHECK:    content:         [ C0, 03, 5F, D6 ]
+# CHECK:    alignment:       4
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _foo
+
+# .subsections_via_symbols
+# .text
+# .globl_foo
+# .align2
+# _foo:
+# ret
+#  .data
+#Lanon:
+#  .quad     0
+#_v1:
+# .quad   _foo
+# .quad   _foo + 8
+#  .quad   _foo@GOT
+#  .quad   _foo + 24 - .
+#  .quad   _foo - .
+#  .quad   _foo + 4 - .
+#  .quad   Lanon
+#  .quad   Lanon + 4
+#  .long   _foo - .
+#  .long   _foo +2 - .
+# .long   _foo@GOT - .
+
diff --git a/test/mach-o/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..72a256e
--- /dev/null
@@ -0,0 +1,372 @@
+
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \
+# RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2  | FileCheck %s
+#
+# Test parsing and writing of x86_64 data relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_foo:
+#  ret
+#
+#_bar:
+#  ret
+#
+#  .section __DATA,__custom
+#L1:
+#  .quad 0
+#
+#  .data
+#_d:
+#  .quad   _foo
+#  .quad   _foo+4
+#  .quad   _foo - .
+#  .quad   L1
+#  .quad   L1 + 2
+#  .quad   _foo - .
+#  .quad   _foo + 4 - .
+#  .quad   L1 - .
+#  .long   _foo - .
+#  .long   _foo + 4 - .
+#  .long   L1 - .
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3 ]
+  - segment:         __DATA
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000002
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [ 
+#  .quad   _foo
+# No addend is needed here as we are referencing _foo directly and that is
+# encoded entirely in the X86_64_RELOC_UNSIGNED
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo+4
+# Addend of 4 is needed here as we are referencing _foo from the
+# X86_64_RELOC_UNSIGNED, then the addend gives us 4 more.
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -16 because that is the offset from here back
+# to _d.
+                       0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   . - _foo
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -16 because that is the offset from here back
+# to _d.
+                       0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   L1
+# This is a X86_64_RELOC_UNSIGNED without extern set.
+# In this case, we encode the section number for L1 in the relocation, and
+# the addend here is the absolute address of the location in that section
+# we want to reference.
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   L1 + 2
+# This is a X86_64_RELOC_UNSIGNED without extern set.
+# In this case, we encode the section number for L1 in the relocation, and
+# the addend here is the absolute address of the location in that section
+# we want to reference.  We have a 4 because the section is at address 2
+# and we want an offset of 2 from there.
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -40 because that is the offset from here back
+# to _d.
+                       0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   _foo + 4 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -52.  It would have been -56 because that
+# would take us from the address of this relocation back to _d.  But as
+# we also add 4 for the offset, we get -52.
+                       0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   L1 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned does not have extern set, so the relocation
+# number is the section number for L1.
+# Note the addend here is -62. Of that, -64 would be the offset from
+# this location from _d.  The remaining 2 is the absolute address
+# of L1.
+                       0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .long   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -72 because that is the offset from here back
+# to _d.
+                       0xB8, 0xFF, 0xFF, 0xFF,
+#  .long   . - _foo
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -76 because that is the offset from here back
+# to _d.
+                       0xB4, 0xFF, 0xFF, 0xFF,
+#  .long   _foo + 4 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -76.  It would have been -80 because that
+# would take us from the address of this relocation back to _d.  But as
+# we also add 4 for the offset, we get -76.
+                       0xB4, 0xFF, 0xFF, 0xFF,
+#  .long   L1 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned does not have extern set, so the relocation
+# number is the section number for L1.
+# Note the addend here is -82. Of that, -84 would be the offset from
+# this location from _d.  The remaining 2 is the absolute address
+# of L1.
+                       0xAE, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000054
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000054
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000050
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000050
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x0000004C
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x0000004C
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000040
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000040
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000038
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000038
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000030
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000028
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000018
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000018
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+local-symbols:
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _bar
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _d
+    type:            N_SECT
+    sect:            3
+    value:           0x000000000000000A
+page-size:       0x00000000
+...
+
+
+# CHECK:defined-atoms:   
+# CHECK:  - name:            _d
+# CHECK:    type:            data
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
+# CHECK:                       00, 00, 00, 00, F0, FF, FF, FF, FF, FF, FF, FF,
+# CHECK:                       18, 00, 00, 00, 00, 00, 00, 00, {{..}}, {{..}}, 00, 00,
+# CHECK:                       00, 00, 00, 00, {{..}}, {{..}}, 00, 00, 00, 00, 00, 00,
+# CHECK:                       D0, FF, FF, FF, FF, FF, FF, FF, CC, FF, FF, FF,
+# CHECK:                       FF, FF, FF, FF, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                       B8, FF, FF, FF, B4, FF, FF, FF, B4, FF, FF, FF,
+# CHECK:                       {{..}}, {{..}}, {{..}}, {{..}} ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:      
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          _foo
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          8
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          16
+# CHECK:        target:          _foo
+# CHECK:      - kind:            negDelta64
+# CHECK:        offset:          24
+# CHECK:        target:          _foo
+# CHECK:      - kind:            pointer64Anon
+# CHECK:        offset:          32
+# CHECK:        target:          L003
+# CHECK:      - kind:            pointer64Anon
+# CHECK:        offset:          40
+# CHECK:        target:          L003
+# CHECK:        addend:          2
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          48
+# CHECK:        target:          _foo
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          56
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta64Anon
+# CHECK:        offset:          64
+# CHECK:        target:          L003
+# CHECK:      - kind:            delta32
+# CHECK:        offset:          72
+# CHECK:        target:          _foo
+# CHECK:      - kind:            negDelta32
+# CHECK:        offset:          76
+# CHECK:        target:          _foo
+# CHECK:      - kind:            delta32
+# CHECK:        offset:          80
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta32Anon
+# CHECK:        offset:          84
+# CHECK:        target:          L003
+# CHECK:  - name:            _foo
+# CHECK:    content:         [ C3 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - name:            _bar
+# CHECK:    content:         [ C3 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - ref-name:        L003
+# CHECK:    type:            unknown
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    section-choice:  custom-required
+# CHECK:    section-name:    __DATA/__custom
+# CHECK:    dead-strip:      never
+
diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml
new file mode 100644 (file)
index 0000000..3b422e0
--- /dev/null
@@ -0,0 +1,119 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of mach-o data symbols.
+#
+# long a = 0x0807060504030201;
+# int b = 0x14131211;
+# int c = 0x24232221;
+# static int s1;
+# static int s2 = 0x34333231;
+#
+#
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24,
+                       0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44 ]
+  - segment:         __CUST
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000018
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]
+  - segment:         __DATA
+    section:         __bss
+    type:            S_ZEROFILL
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000020
+    size:            4
+local-symbols:
+  - name:            _s1
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000020
+  - name:            _s2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000008
+  - name:            _c
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _cWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000014
+  - name:            _kustom
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000018
+...
+
+# CHECK: defined-atoms:
+
+# CHECK:   - name:            _a
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+
+# CHECK:   - name:            _b
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 11, 12, 13, 14 ]
+
+# CHECK:   - name:            _c
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 21, 22, 23, 24 ]
+
+# CHECK:   - name:            _s2
+# CHECK:     type:            data
+# CHECK:     content:         [ 31, 32, 33, 34 ]
+
+# CHECK:   - name:            _cWeak
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 41, 42, 43, 44 ]
+# CHECK:     merge:           as-weak
+
+# CHECK:   - name:            _s1
+# CHECK:     type:            zero-fill
+# CHECK:     size:            4
+
+# CHECK:   - name:            _kustom
+# CHECK:     scope:           global
+# CHECK:     type:            unknown
+# CHECK:     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __CUST/__custom
+
diff --git a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..b009cbc
--- /dev/null
@@ -0,0 +1,176 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of x86_64 __eh_frame (dwarf unwind) relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
+                       0x00, 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00,
+                       0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x66, 0x2E,
+                       0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
+                       0x00 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x000000000000004C
+    content:         [ 0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
+                       0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
+                       0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000100
+    content:         [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x10, 0x07, 0x9B, 0x04, 0x00, 0x00, 0x00, 0x10,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x2C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0xD8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0xB0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x2C, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+                       0x98, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0xCB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000013
+        type:            X86_64_RELOC_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+local-symbols:
+  - name:            GCC_except_table0
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000004C
+  - name:            GCC_except_table2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+global-symbols:
+  - name:            _catchMyException1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _catchMyException2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000030
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000020
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_begin_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_end_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# Check that LSDA fields are fixed up correctly, even when there are multiple
+# CIEs involved.
+#
+# (1) Check that we can relocate an LSDA at all. Requires correct interpretation
+#     of augmentation data strings in CIEs and augmentation data fields of FDEs.
+#
+# CHECK:       - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L002
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _catchMyException1
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          25
+# CHECK-NEXT:        target:          GCC_except_table0
+#
+# (2) Check that we have an intervening FDE with a different CIE.
+#     If the test fails here then test (3) probably isn't testing what it
+#     should, and this test-case should be updated.
+#
+# CHECK:       - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L001
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _bar
+#
+# (3) Check that we can relocate the LSDA on a second FDE that references the
+#     original CIE from (1). Requires us to match this FDE up with the correct
+#     CIE.
+#
+# CHECK-NEXT:  - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L002
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _catchMyException2
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          25
+# CHECK-NEXT:        target:          GCC_except_table2
diff --git a/test/mach-o/parse-eh-frame-x86-anon.yaml b/test/mach-o/parse-eh-frame-x86-anon.yaml
new file mode 100644 (file)
index 0000000..09b6ba3
--- /dev/null
@@ -0,0 +1,129 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of new __eh_frame (dwarf unwind) section that has no .eh labels
+# and no relocations.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+                       0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+                       0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+                       0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+                       0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+                       0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+                       0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+                       0xBC, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000040
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000035
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000021
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000044
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000015
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 5 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+                       0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+                       0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+                       0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+                       0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000039
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[L0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame-x86-labeled.yaml b/test/mach-o/parse-eh-frame-x86-labeled.yaml
new file mode 100644 (file)
index 0000000..5be5abc
--- /dev/null
@@ -0,0 +1,193 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of old __eh_frame (dwarf unwind) section that has .eh labels
+# and relocations.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+                       0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+                       0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+                       0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+                       0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+                       0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+                       0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+                       0xBC, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000040
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000035
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          7
+      - offset:          0x00000021
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000044
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000015
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 5 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+                       0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+                       0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+                       0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+                       0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000001C
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000064
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000048
+      - offset:          0x00000020
+        scattered:       true
+        type:            GENERIC_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000068
+      - offset:          0x00000038
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000048
+      - offset:          0x0000003C
+        scattered:       true
+        type:            GENERIC_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000039
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000084
+local-symbols:
+  - name:            EH_frame0
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000048
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000039
+  - name:            __Z3barv.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x000000000000007C
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000060
+undefined-symbols:
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[L0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame.yaml b/test/mach-o/parse-eh-frame.yaml
new file mode 100644 (file)
index 0000000..6453474
--- /dev/null
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __eh_frame (dwarf unwind) section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x09, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+                       0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000058
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+                       0x6B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+# CHECK:                        01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, 88, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-function.yaml b/test/mach-o/parse-function.yaml
new file mode 100644 (file)
index 0000000..bfd8e5c
--- /dev/null
@@ -0,0 +1,100 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t
+# RUN: lld -flavor darwin -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0xCC, 0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _myHiddenWeak
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000007
+  - name:            _myStripNot
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000010
+  - name:            _myResolver
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000011
+...
+
+# CHECK-NOT:  name:
+# CHECK:      content:         [ CC ]
+
+# CHECK:      name:   _myGlobal
+# CHECK:      scope:  global
+# CHECK:      content:         [ C3 ]
+
+# CHECK:      name:   _myGlobalWeak
+# CHECK:      scope:  global
+# CHECK:      content:         [ 90, C3 ]
+# CHECK:      merge:  as-weak
+
+# CHECK:      name:   _myHidden
+# CHECK:      scope:  hidden
+# CHECK:      content:         [ 90, 90, C3 ]
+
+# CHECK:      name:   _myHiddenWeak
+# CHECK:      scope:  hidden
+# CHECK:      content:         [ 90, 90, 90, C3 ]
+# CHECK:      merge:  as-weak
+
+# CHECK:      name:   _myStatic
+# CHECK-NOT:   scope:  global
+# CHECK-NOT:   scope:  hidden
+# CHECK:      content:         [ 90, 90, 90, 90, C3 ]
+
+# CHECK:      name:    _myStripNot
+# CHECK:      scope:   global
+# CHECK:      content:         [ CC ]
+# CHECK:      dead-strip:  never
+
+# CHECK:      name:    _myResolver
+# CHECK:      scope:   global
+# CHECK:      type:    resolver
+# CHECK:      content:         [ 31, C0, C3 ]
+
diff --git a/test/mach-o/parse-initializers32.yaml b/test/mach-o/parse-initializers32.yaml
new file mode 100644 (file)
index 0000000..ede7b90
--- /dev/null
@@ -0,0 +1,84 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x89, 0xE5,
+                       0x5D, 0xC3, 0x55, 0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __mod_init_func
+    type:            S_MOD_INIT_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000004
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __DATA
+    section:         __mod_term_func
+    type:            S_MOD_TERM_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000104
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _init
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _init2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000005
+  - name:            _term
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000A
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 05, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - type:            terminator-pointer
+# CHECK:    content:         [ 0A, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - name:            _init
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _init2
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _term
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-initializers64.yaml b/test/mach-o/parse-initializers64.yaml
new file mode 100644 (file)
index 0000000..c55a0ea
--- /dev/null
@@ -0,0 +1,105 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5,
+                       0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __mod_init_func
+    type:            S_MOD_INIT_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+  - segment:         __DATA
+    section:         __mod_term_func
+    type:            S_MOD_TERM_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000108
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _init
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _init2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _term
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _init
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _init2
+# CHECK:  - type:            terminator-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _term
+# CHECK:  - name:            _init
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _init2
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _term
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-literals-error.yaml b/test/mach-o/parse-literals-error.yaml
new file mode 100644 (file)
index 0000000..8daeeca
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t 2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# Test for error if literal section is not correct size mulitple.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __literal8
+    type:            S_8BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       0
+    address:         0x0000000000000120
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D ]
+...
+
+# CHECK:       error:
+
diff --git a/test/mach-o/parse-literals.yaml b/test/mach-o/parse-literals.yaml
new file mode 100644 (file)
index 0000000..7f80ba5
--- /dev/null
@@ -0,0 +1,93 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00, 0x77, 0x6F, 0x72, 0x6C,
+                       0x00 ]
+  - segment:         __TEXT
+    section:         __literal4
+    type:            S_4BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000114
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x13, 0x14,
+                       0x28, 0x29, 0x2A, 0x2B ]
+  - segment:         __TEXT
+    section:         __literal8
+    type:            S_8BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000120
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F ]
+  - segment:         __TEXT
+    section:         __literal16
+    type:            S_16BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000130
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00 ]
+  - segment:         __TEXT
+    section:         __ustring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x68, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00,
+                       0x6F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x68, 0x00,
+                       0x65, 0x00, 0x72, 0x00, 0x00, 0x00 ]
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 77, 6F, 72, 6C, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            utf16-string
+# CHECK:    content:         [ 68, 00, 65, 00, 6C, 00, 6C, 00, 6F, 00, 00, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            utf16-string
+# CHECK:    content:         [ 74, 00, 68, 00, 65, 00, 72, 00, 00, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 01, 02, 03, 04 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 11, 12, 13, 14 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 28, 29, 2A, 2B ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-8-byte
+# CHECK:    content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-8-byte
+# CHECK:    content:         [ 28, 29, 2A, 2B, 2C, 2D, 2E, 2F ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-16-byte
+# CHECK:    content:         [ 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C,
+# CHECK:                       0D, 0E, 0F, 00 ]
+
diff --git a/test/mach-o/parse-non-lazy-pointers.yaml b/test/mach-o/parse-non-lazy-pointers.yaml
new file mode 100644 (file)
index 0000000..0b0ec5c
--- /dev/null
@@ -0,0 +1,98 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of non-lazy-pointer sections.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0x59, 0x8D, 0x81, 0x14, 0x00, 0x00, 0x00, 0x8D,
+                       0x81, 0x18, 0x00, 0x00, 0x00, 0x5D, 0xC3, 0x55,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000011
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000008
+      - offset:          0x0000000B
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000001C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000008
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 2, 2147483648 ]
+local-symbols:
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000017
+global-symbols:
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - ref-name:        [[GOT1:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            got
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        [[GOT2:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            got
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - name:            _get
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, E8, 00, 00, 00, 00, 59, 8D, 81, 14,
+# CHECK:                       00, 00, 00, 8D, 81, 18, 00, 00, 00, 5D, C3 ]
+# CHECK:     references:
+# CHECK:       - kind:            funcRel32
+# CHECK:         offset:          11
+# CHECK:         target:          [[GOT1]]
+# CHECK:       - kind:            funcRel32
+# CHECK:         offset:          17
+# CHECK:         target:          [[GOT2]]
+# CHECK:  - name:            _foo
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+
+
diff --git a/test/mach-o/parse-relocs-x86.yaml b/test/mach-o/parse-relocs-x86.yaml
new file mode 100644 (file)
index 0000000..c7ce80b
--- /dev/null
@@ -0,0 +1,296 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing and writing of x86 relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#  .text
+#_test:
+#      call _undef
+#      call _undef+2
+#      call _foo
+#      call _foo+2
+#   callw _undef
+#      callw _foo
+#      callw _foo+2
+#L1:
+#      movl    _undef, %eax
+#   movl       _x, %eax
+#   movl       _x+4, %eax
+#      movl    _x-L1(%eax), %eax
+#      movl    _x+4-L1(%eax), %eax
+#
+#_foo:
+#    ret
+#
+#  .data
+#_x:
+#  .long _undef
+#  .long _undef+7
+#  .long _foo
+#  .long _foo+3
+#  .long _test - .
+#  .long _test+3 - .
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0xFB, 0xFF, 0xFF, 0xFF, 0xE8, 0xF8, 0xFF,
+                       0xFF, 0xFF, 0xE8, 0x2C, 0x00, 0x00, 0x00, 0xE8,
+                       0x29, 0x00, 0x00, 0x00, 0x66, 0xE8, 0xE8, 0xFF,
+                       0x66, 0xE8, 0x1F, 0x00, 0x66, 0xE8, 0x1D, 0x00,
+                       0xA1, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x3C, 0x00,
+                       0x00, 0x00, 0xA1, 0x40, 0x00, 0x00, 0x00, 0x8B,
+                       0x80, 0x1C, 0x00, 0x00, 0x00, 0x8B, 0x80, 0x20,
+                       0x00, 0x00, 0x00, 0xC3 ]
+    relocations:
+      - offset:          0x00000037
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000031
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x0000002B
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000026
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000021
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x0000001E
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        value:           0x0000003B
+      - offset:          0x0000001A
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        value:           0x0000003B
+      - offset:          0x0000000B
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000006
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000001
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000003C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+                       0x3B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
+                       0xB4, 0xFF, 0xFF, 0xFF, 0xB3, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000014
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000050
+      - offset:          0x00000010
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000004C
+      - offset:          0x0000000C
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x0000003B
+      - offset:          0x00000008
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000004
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            _test
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000003B
+  - name:            _x
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000003C
+undefined-symbols:
+  - name:            _undef
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _x
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _undef
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _undef
+# CHECK:         addend:          7
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          8
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          12
+# CHECK:         target:          _foo
+# CHECK:         addend:          3
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          16
+# CHECK:         target:          _test
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          20
+# CHECK:         target:          _test
+# CHECK:         addend:          3
+# CHECK:  - name:            _test
+# CHECK:    references:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          1
+# CHECK:        target:          _undef
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          6
+# CHECK:        target:          _undef
+# CHECK:        addend:          2
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          11
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          16
+# CHECK:        target:          _foo
+# CHECK:        addend:          2
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          22
+# CHECK:        target:          _undef
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          26
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          30
+# CHECK:        target:          _foo
+# CHECK:        addend:          2
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          33
+# CHECK:        target:          _undef
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          38
+# CHECK:        target:          _x
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          43
+# CHECK:        target:          _x
+# CHECK:        addend:          4
+# CHECK:      - kind:            funcRel32
+# CHECK:        offset:          49
+# CHECK:        target:          _x
+# CHECK:        addend:          -32
+# CHECK:      - kind:            funcRel32
+# CHECK:        offset:          55
+# CHECK:        target:          _x
+# CHECK:        addend:          -28
+
diff --git a/test/mach-o/parse-section-no-symbol.yaml b/test/mach-o/parse-section-no-symbol.yaml
new file mode 100644 (file)
index 0000000..46d005a
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions with no symbols at all.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC ]
+...
+
+# CHECK-NOT:  name:
+# CHECK:      content:         [ CC ]
diff --git a/test/mach-o/parse-tentative-defs.yaml b/test/mach-o/parse-tentative-defs.yaml
new file mode 100644 (file)
index 0000000..1757c8c
--- /dev/null
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of tentative definitions, including size, scope, and alignment.
+#
+#
+# int tent4;
+# long tent8;
+# __attribute__((visibility("hidden"))) int tentHidden;
+# __attribute__((aligned(16))) int tent4_16;
+# __attribute__((aligned(32))) long tent64_32[8];
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __tex
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+undefined-symbols:
+  - name:            _tent4
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0200
+    value:           0x0000000000000004
+  - name:            _tent4_16
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0400
+    value:           0x0000000000000004
+  - name:            _tent64_32
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0500
+    value:           0x0000000000000040
+  - name:            _tent8
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0300
+    value:           0x0000000000000008
+  - name:            _tentHidden
+    type:            N_UNDF
+    scope:           [ N_EXT, N_PEXT ]
+    desc:            0x0200
+    value:           0x0000000000000004
+...
+
+
+# CHECK:    defined-atoms:
+# CHECK:       name:             _tent4
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       4
+
+# CHECK:       name:             _tent4_16
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       16
+
+# CHECK:       name:             _tent64_32
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            64
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       32
+
+# CHECK:       name:             _tent8
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            8
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       8
+
+# CHECK:       name:             _tentHidden
+# CHECK:        scope:           hidden
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       4
diff --git a/test/mach-o/parse-text-relocs-arm64.yaml b/test/mach-o/parse-text-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..38a52e7
--- /dev/null
@@ -0,0 +1,237 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0x39,
+                       0x20, 0x00, 0x40, 0x79, 0x20, 0x00, 0x40, 0xB9,
+                       0x20, 0x00, 0x40, 0xF9, 0x20, 0x00, 0xC0, 0x3D,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xB9,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xF9,
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x40, 0xF9 ]
+    relocations:
+      - offset:          0x00000034
+        type:            ARM64_RELOC_TLVP_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          5
+      - offset:          0x00000030
+        type:            ARM64_RELOC_TLVP_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x0000002C
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000028
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+      - offset:          0x00000024
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16
+      - offset:          0x00000024
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16
+      - offset:          0x00000020
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000018
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000014
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000004
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          8
+      - offset:          0x00000004
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000038
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _v1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000038
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000038
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _tlv
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _v2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _v1
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:   - name:            _func
+# CHECK:     content:         [ 00, 00, 00, 94, 00, 00, 00, 94, 01, 00, 00, 90,
+# CHECK:                        20, 00, 40, 39, 20, 00, 40, 79, 20, 00, 40, B9,
+# CHECK:                        20, 00, 40, F9, 20, 00, C0, 3D, 01, 00, 00, 90,
+# CHECK:                        20, 00, 40, B9, 01, 00, 00, 90, 20, 00, 40, F9,
+# CHECK:                        00, 00, 00, 90, 00, 00, 40, F9 ]
+# CHECK:     references:
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          0
+# CHECK:         target:          _foo
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          4
+# CHECK:         target:          _foo
+# CHECK:         addend:          8
+# CHECK:       - kind:            page21
+# CHECK:         offset:          8
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12
+# CHECK:         offset:          12
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale2
+# CHECK:         offset:          16
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale4
+# CHECK:         offset:          20
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale8
+# CHECK:         offset:          24
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale16
+# CHECK:         offset:          28
+# CHECK:         target:          _v1
+# CHECK:       - kind:            page21
+# CHECK:         offset:          32
+# CHECK:         target:          _v1
+# CHECK:         addend:          16
+# CHECK:       - kind:            offset12scale4
+# CHECK:         offset:          36
+# CHECK:         target:          _v1
+# CHECK:         addend:          16
+# CHECK:       - kind:            gotPage21
+# CHECK:         offset:          40
+# CHECK:         target:          _v2
+# CHECK:       - kind:            gotOffset12
+# CHECK:         offset:          44
+# CHECK:         target:          _v2
+# CHECK:       - kind:            tlvPage21
+# CHECK:         offset:          48
+# CHECK:         target:          _tlv
+# CHECK:       - kind:            tlvOffset12
+# CHECK:         offset:          52
+# CHECK:         target:          _tlv
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _foo
+# CHECK:   - name:            _tlv
+# CHECK:   - name:            _v2
+
diff --git a/test/mach-o/parse-text-relocs-x86_64.yaml b/test/mach-o/parse-text-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..6d0a52f
--- /dev/null
@@ -0,0 +1,204 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+#  call  _foo
+#  call  _foo+4
+#  movq  _foo@GOTPCREL(%rip), %rax
+#  pushq _foo@GOTPCREL(%rip)
+#  movl  _foo(%rip), %eax
+#  movl  _foo+4(%rip), %eax
+#  movb  $0x12, _foo(%rip)
+#  movw  $0x1234, _foo(%rip)
+#  movl  $0x12345678, _foo(%rip)
+#  movl  L2(%rip), %eax
+#  movb  $0x12, L2(%rip)
+#  movw  $0x1234, L2(%rip)
+#  movl  $0x12345678, L2(%rip)
+#
+#  .data
+#L2: .long 0
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x04, 0x00,
+                       0x00, 0x00, 0x48, 0x8B, 0x05, 0x04, 0x00, 0x00,
+                       0x00, 0xFF, 0x35, 0x04, 0x00, 0x00, 0x00, 0x8B,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x05, 0x04,
+                       0x00, 0x00, 0x00, 0xC6, 0x05, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x12, 0x66, 0xC7, 0x05, 0xFE, 0xFF, 0xFF,
+                       0xFF, 0x34, 0x12, 0xC7, 0x05, 0xFC, 0xFF, 0xFF,
+                       0xFF, 0x78, 0x56, 0x34, 0x12, 0x8B, 0x05, 0x1A,
+                       0x00, 0x00, 0x00, 0xc6, 0x05, 0x13, 0x00, 0x00,
+                      0x00, 0x12, 0x66, 0xc7, 0x05, 0x0a, 0x00, 0x00,
+                      0x00, 0x34, 0x12, 0xc7, 0x05, 0x00, 0x00, 0x00,
+                      0x00, 0x78, 0x56, 0x34, 0x12 ]
+    relocations:
+      - offset:          0x00000055
+        type:            X86_64_RELOC_SIGNED_4
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x0000004d
+        type:            X86_64_RELOC_SIGNED_2
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000045
+        type:            X86_64_RELOC_SIGNED_1
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x0000003F
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000035
+        type:            X86_64_RELOC_SIGNED_4
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000002D
+        type:            X86_64_RELOC_SIGNED_2
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000025
+        type:            X86_64_RELOC_SIGNED_1
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000001F
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000019
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000013
+        type:            X86_64_RELOC_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000D
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000006
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000001
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000005D
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            _test
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[LABEL:L[0-9]+]]
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:  - name:            _test
+# CHECK:    references:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          1
+# CHECK:        target:          _foo
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          6
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32GotLoad
+# CHECK:        offset:          13
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32Got
+# CHECK:        offset:          19
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32
+# CHECK:        offset:          25
+# CHECK:        target:          _foo
+# CHECK:      - kind:            ripRel32
+# CHECK:        offset:          31
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32Minus1
+# CHECK:        offset:          37
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus2
+# CHECK:        offset:          45
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus4
+# CHECK:        offset:          53
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Anon
+# CHECK:        offset:          63
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus1Anon
+# CHECK:        offset:          69
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus2Anon
+# CHECK:        offset:          77
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus4Anon
+# CHECK:        offset:          85
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
diff --git a/test/mach-o/parse-tlv-relocs-x86-64.yaml b/test/mach-o/parse-tlv-relocs-x86-64.yaml
new file mode 100644 (file)
index 0000000..78b1784
--- /dev/null
@@ -0,0 +1,100 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing of x86_64 tlv relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x3D, 0x00,
+                       0x00, 0x00, 0x00, 0xFF, 0x17, 0x8B, 0x00, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000007
+        type:            X86_64_RELOC_TLV
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __thread_data
+    type:            S_THREAD_LOCAL_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000014
+    content:         [ 0x07, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __thread_vars
+    type:            S_THREAD_LOCAL_VARIABLES
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            '_x$tlv$init'
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+undefined-symbols:
+  - name:            __tlv_bootstrap
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# CHECK:        - name:            _x
+# CHECK-NEXT:     scope:           global
+# CHECK-NEXT:     type:            tlv-thunk
+# CHECK-NOT:    - name:
+# CHECK:          references:
+# CHECK-NEXT:       - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          __tlv_bootstrap
+# CHECK-NEXT:       - kind:            tlvInitSectionOffset
+# CHECK-NEXT:         offset:          16
+# CHECK-NEXT:         target:          '_x$tlv$init'
+# CHECK:        - name:            _main
+# CHECK-NOT:    - name:
+# CHECK-NEXT:     scope:           global
+# CHECK:          references:
+# CHECK-NEXT:      - kind:            ripRel32Tlv
+# CHECK-NEXT:        offset:          7
+# CHECK-NEXT:        target:          _x
diff --git a/test/mach-o/re-exported-dylib-ordinal.yaml b/test/mach-o/re-exported-dylib-ordinal.yaml
new file mode 100644 (file)
index 0000000..ff4d756
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/re-exported-dylib-ordinal.yaml \
+# RUN: %p/Inputs/re-exported-dylib-ordinal2.yaml \
+# RUN: %p/Inputs/re-exported-dylib-ordinal3.yaml -dylib -o %t \
+# RUN:  && llvm-nm -m %t | FileCheck %s
+#
+# Test that when one dylib A re-exports dylib B that using a symbol from B
+# gets recorded as coming from A.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _test
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external _bar (from libfoo)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/rpath.yaml b/test/mach-o/rpath.yaml
new file mode 100644 (file)
index 0000000..ce1234d
--- /dev/null
@@ -0,0 +1,38 @@
+# Check we handle -rpath correctly:
+# RUN: lld -flavor darwin -arch x86_64 -rpath @loader_path/../Frameworks \
+# RUN:     %p/Inputs/libSystem.yaml %s -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_RPATH
+# CHECK-BINARY-WRITE-NEXT:  cmdsize 40
+# CHECK-BINARY-WRITE-NEXT:  path @loader_path/../Frameworks (offset 12)
diff --git a/test/mach-o/run-tlv-pass-x86-64.yaml b/test/mach-o/run-tlv-pass-x86-64.yaml
new file mode 100644 (file)
index 0000000..0e64845
--- /dev/null
@@ -0,0 +1,144 @@
+# RUN: lld -flavor darwin -macosx_version_min 10.7 -arch x86_64 -print_atoms %s -o %t | FileCheck %s
+# RUN: not lld -flavor darwin -macosx_version_min 10.6 -arch x86_64 -o %t %s 2> %t2
+# RUN: FileCheck < %t2 %s --check-prefix=CHECK-ERROR
+# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s --check-prefix=CHECK-LOADCMDS
+#
+# Test parsing of x86_64 tlv relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:        
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x3D, 0x00, 
+                       0x00, 0x00, 0x00, 0xFF, 0x17, 0x8B, 0x00, 0x5D, 
+                       0xC3 ]
+    relocations:     
+      - offset:          0x00000007
+        type:            X86_64_RELOC_TLV
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __thread_bss
+    type:            S_THREAD_LOCAL_ZEROFILL
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000014
+    size:            4
+  - segment:         __DATA
+    section:         __thread_vars
+    type:            S_THREAD_LOCAL_VARIABLES
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+  - segment:         __DATA
+    section:         __dummy
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x00000000000000C0
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:   
+  - name:            '_x$tlv$init'
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+global-symbols:  
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+  - name:            '__tlv_bootstrap'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000C0
+  - name:            'dyld_stub_binder'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000C8
+  - name:            'start'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000D0
+page-size:       0x00000000
+...
+
+# CHECK:       - name:            _x
+# CHECK-NEXT:    scope:           global
+# CHECK-NEXT:    type:            tlv-thunk
+# CHECK-NOT:   - name:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          __tlv_bootstrap
+# CHECK-NEXT:       - kind:            tlvInitSectionOffset
+# CHECK-NEXT:         offset:          16
+# CHECK-NEXT:         target:          '_x$tlv$init'
+# CHECK:       - name:            '_x$tlv$init'
+# CHECK-NEXT:    type:            tlv-zero-fill
+# CHECK:        - name:            _main
+# CHECK-NOT:    - name:
+# CHECK:          references:
+# CHECK-NEXT:       - kind:            ripRel32
+# CHECK-NEXT:         offset:          7
+# CHECK-NEXT:         target:          L[[ID:[0-9]+]]
+# CHECK:        - ref-name:        L[[ID]]
+# CHECK-NEXT:     scope:           hidden
+# CHECK-NEXT:     type:            tlv-initializer-ptr
+# CHECK-NEXT:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK-NEXT:     alignment:       8
+# CHECK-NEXT:     permissions:     rw-
+# CHECK-NEXT:     references:
+# CHECK-NEXT:       - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          _x
+
+# CHECK-ERROR: targeted OS version does not support use of thread local variables in _main for architecture x86_64
+
+# CHECK-LOADCMDS: sectname __thread_bss
+# CHECK-LOADCMDS:   segname __DATA
+# CHECK-LOADCMDS:      addr 0x{{[0-9A-F]*}}
+# CHECK-LOADCMDS:      size 0x0000000000000004
+# CHECK-LOADCMDS:    offset 0
+# CHECK-LOADCMDS:     align 2^2 (4)
+# CHECK-LOADCMDS:    reloff 0
+# CHECK-LOADCMDS:    nreloc 0
+# CHECK-LOADCMDS:      type S_THREAD_LOCAL_ZEROFILL
diff --git a/test/mach-o/sdk-version-error.yaml b/test/mach-o/sdk-version-error.yaml
new file mode 100644 (file)
index 0000000..2607bb8
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: not lld -flavor darwin -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# ERROR: malformed sdkVersion value
\ No newline at end of file
diff --git a/test/mach-o/sectalign.yaml b/test/mach-o/sectalign.yaml
new file mode 100644 (file)
index 0000000..556fd52
--- /dev/null
@@ -0,0 +1,80 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN:    -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \
+# RUN:    %p/Inputs/libSystem.yaml -o %t \
+# RUN: && llvm-readobj -sections %t | FileCheck %s
+#
+# Test -sectalign option on __text and a custom section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x0000000C
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000006
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000014
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000018
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:  Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0xC00
+
+# CHECK:  Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0x1000
+
+# CHECK:  Name: __custom (5F 5F 63 75 73 74 6F 6D 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0x1800
+
diff --git a/test/mach-o/sectattrs.yaml b/test/mach-o/sectattrs.yaml
new file mode 100644 (file)
index 0000000..800ba55
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN:    %p/Inputs/libSystem.yaml -o %t \
+# RUN: && llvm-objdump -private-headers %t | FileCheck %s
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3 ]
+global-symbols:
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:  PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+
diff --git a/test/mach-o/sectcreate.yaml b/test/mach-o/sectcreate.yaml
new file mode 100644 (file)
index 0000000..51c59dc
--- /dev/null
@@ -0,0 +1,12 @@
+# RUN: lld -flavor darwin -r -arch x86_64 -o %t -sectcreate __DATA __data \
+# RUN:   %p/Inputs/hw.raw_bytes -print_atoms | FileCheck %s
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - scope:           global
+# CHECK:     type:            sectcreate
+# CHECK:     content:         [ 68, 65, 6C, 6C, 6F, 0A ]
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __DATA/__data
+# CHECK:     dead-strip:      never
diff --git a/test/mach-o/seg-protection-arm64.yaml b/test/mach-o/seg-protection-arm64.yaml
new file mode 100644 (file)
index 0000000..f63b33a
--- /dev/null
@@ -0,0 +1,78 @@
+# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# CHECK: Load command 0
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __PAGEZERO
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot ---
+# CHECK:   initprot ---
+# CHECK:    nsects 0
+# CHECK:     flags (none)
+# CHECK: Load command 1
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 152
+# CHECK:   segname __TEXT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot r-x
+# CHECK:   initprot r-x
+# CHECK:    nsects 1
+# CHECK:     flags (none)
+# CHECK: Section
+# CHECK:   sectname __text
+# CHECK:    segname __TEXT
+# CHECK:       addr
+# CHECK:       size
+# CHECK:     offset
+# CHECK:      align 2^0 (1)
+# CHECK:     reloff 0
+# CHECK:     nreloc 0
+# CHECK:       type S_REGULAR
+# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+# CHECK:  reserved1 0
+# CHECK:  reserved2 0
+# CHECK: Load command 2
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __LINKEDIT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot r--
+# CHECK:   initprot r--
+# CHECK:    nsects 0
+# CHECK:     flags (none)
diff --git a/test/mach-o/seg-protection-x86_64.yaml b/test/mach-o/seg-protection-x86_64.yaml
new file mode 100644 (file)
index 0000000..474f72f
--- /dev/null
@@ -0,0 +1,78 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# CHECK: Load command 0
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __PAGEZERO
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot ---
+# CHECK:   initprot ---
+# CHECK:    nsects 0
+# CHECK:     flags (none)
+# CHECK: Load command 1
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 152
+# CHECK:   segname __TEXT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot rwx
+# CHECK:   initprot r-x
+# CHECK:    nsects 1
+# CHECK:     flags (none)
+# CHECK: Section
+# CHECK:   sectname __text
+# CHECK:    segname __TEXT
+# CHECK:       addr
+# CHECK:       size
+# CHECK:     offset
+# CHECK:      align 2^0 (1)
+# CHECK:     reloff 0
+# CHECK:     nreloc 0
+# CHECK:       type S_REGULAR
+# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+# CHECK:  reserved1 0
+# CHECK:  reserved2 0
+# CHECK: Load command 2
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __LINKEDIT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot rwx
+# CHECK:   initprot r--
+# CHECK:    nsects 0
+# CHECK:     flags (none)
diff --git a/test/mach-o/source-version.yaml b/test/mach-o/source-version.yaml
new file mode 100644 (file)
index 0000000..169e975
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not lld -flavor darwin -arch x86_64 -source_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+# RUN: lld -flavor darwin -arch x86_64 -source_version 10.1.2.3.4 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# ERROR: malformed source_version value
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:       cmd LC_SOURCE_VERSION
+# CHECK:   cmdsize 16
+# CHECK:   version 10.1.2.3.4
\ No newline at end of file
diff --git a/test/mach-o/stack-size.yaml b/test/mach-o/stack-size.yaml
new file mode 100644 (file)
index 0000000..0e8edb2
--- /dev/null
@@ -0,0 +1,24 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DEFAULT %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -stack_size 31415926000 %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-EXPLICIT %s
+# RUN: not lld -flavor darwin -arch x86_64 -stack_size 0x31415926530 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED
+# RUN: not lld -flavor darwin -arch x86_64 -stack_size hithere %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         []
+
+# CHECK-DEFAULT:       cmd LC_MAIN
+# CHECK-DEFAULT: stacksize 0
+
+# CHECK-EXPLICIT:       cmd LC_MAIN
+# CHECK-EXPLICIT: stacksize 3384796143616
+
+# CHECK-ERROR-MISPAGED: error: stack_size must be a multiple of page size (0x1000)
+
+# CHECK-ERROR-NOTHEX: error: stack_size expects a hex number
diff --git a/test/mach-o/subsections-via-symbols-default.yaml b/test/mach-o/subsections-via-symbols-default.yaml
new file mode 100644 (file)
index 0000000..93ddbc9
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t
+# RUN: llvm-readobj -file-headers %t | FileCheck %s
+
+# Make sure that we have an objc image info in the output.  It should have
+# been generated by the objc pass.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 ]
+...
+
+# The ObjC pass creates a new image info in a new MachoFile internal to the pass.
+# Make sure that we still have MH_SUBSECTIONS_VIA_SYMBOLS in the output file, even
+# though that file in the ObjCPass didn't get it set from being parsed.
+
+# CHECK: MH_SUBSECTIONS_VIA_SYMBOLS
\ No newline at end of file
diff --git a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml
new file mode 100644 (file)
index 0000000..a39a3e7
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/libSystem.yaml
+#
+# Sanity check '-twolevel_namespace -undefined dynamic_lookup'.
+# This should pass without error, even though '_bar' is undefined.
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
diff --git a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml
new file mode 100644 (file)
index 0000000..eeb01de
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/libSystem.yaml 2>&1 | \
+# RUN:   FileCheck --check-prefix=CHECK-WARNING %s
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined suppress %s -o %t %p/Inputs/libSystem.yaml 2>&1 | \
+# RUN:   FileCheck --check-prefix=CHECK-SUPPRESS %s
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
+
+# Make sure that the driver issues an error diagnostic about this combination
+# being invalid.
+#
+# CHECK-WARNING:  can't use -undefined warning or suppress with -twolevel_namespace
+# CHECK-SUPPRESS: can't use -undefined warning or suppress with -twolevel_namespace
\ No newline at end of file
diff --git a/test/mach-o/unwind-info-simple-arm64.yaml b/test/mach-o/unwind-info-simple-arm64.yaml
new file mode 100644 (file)
index 0000000..2ef6dda
--- /dev/null
@@ -0,0 +1,267 @@
+# RUN: lld -flavor darwin -arch arm64 -o %t %s \
+# RUN: %p/Inputs/unwind-info-simple-arm64.yaml -e _main %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+                       0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+                       0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+                       0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+                       0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+                       0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+                       0x3F, 0x04, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54,
+                       0x00, 0x00, 0x00, 0x94, 0xFD, 0x7B, 0xC1, 0xA8,
+                       0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94,
+                       0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x94 ]
+    relocations:
+      - offset:          0x00000070
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000064
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          7
+      - offset:          0x00000060
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          12
+      - offset:          0x00000058
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          11
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          13
+      - offset:          0x00000048
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x00000044
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+      - offset:          0x00000034
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+      - offset:          0x00000024
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          13
+      - offset:          0x00000020
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000074
+    content:         [ 0xFF, 0x9B, 0xAF, 0x80, 0x00, 0x03, 0x27, 0x00,
+                       0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+                       0x01, 0x28, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0xD0, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000030
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x00000000000000A8
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000040
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000038
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          14
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            ltmp14
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+  - name:            GCC_except_table1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+  - name:            ltmp21
+    type:            N_SECT
+    sect:            3
+    value:           0x00000000000000A8
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000028
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000068
+undefined-symbols:
+  - name:            __Unwind_Resume
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __ZTIl
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_begin_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_end_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: Contents of __unwind_info section:
+# CHECK:   Version:                                   0x1
+# CHECK:   Common encodings array section offset:     0x1c
+# CHECK:   Number of common encodings in array:       0x0
+# CHECK:   Personality function array section offset: 0x1c
+# CHECK:   Number of personality functions in array:  0x1
+# CHECK:   Index array section offset:                0x20
+# CHECK:   Number of indices in array:                0x2
+# CHECK:   Common encodings: (count = 0)
+# CHECK:   Personality functions: (count = 1)
+# CHECK:     personality[1]: 0x00004020
+# CHECK:   Top level indices: (count = 2)
+# CHECK:     [0]: function offset=0x00003e68, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK:     [1]: function offset=0x00003edc, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK:   LSDA descriptors:
+# CHECK:     [0]: function offset=0x00003e90, LSDA offset=0x00003f6c
+# CHECK:   Second level indices:
+# CHECK:     Second level index[0]: offset in section=0x00000040, base function offset=0x00003e68
+# CHECK:       [0]: function offset=0x00003e68, encoding=0x04000000
+# CHECK:       [1]: function offset=0x00003e90, encoding=0x54000000
+# CHECK:       [2]: function offset=0x00003ed0, encoding=0x04000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+
+
diff --git a/test/mach-o/unwind-info-simple-x86_64.yaml b/test/mach-o/unwind-info-simple-x86_64.yaml
new file mode 100644 (file)
index 0000000..7dfae1b
--- /dev/null
@@ -0,0 +1,133 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _main %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+# CHECK: Contents of __unwind_info section:
+# CHECK:   Version:                                   0x1
+# CHECK:   Common encodings array section offset:     0x1c
+# CHECK:   Number of common encodings in array:       0x0
+# CHECK:   Personality function array section offset: 0x1c
+# CHECK:   Number of personality functions in array:  0x1
+# CHECK:   Index array section offset:                0x20
+# CHECK:   Number of indices in array:                0x2
+# CHECK:   Common encodings: (count = 0)
+# CHECK:   Personality functions: (count = 1)
+# CHECK:     personality[1]: 0x00001000
+# CHECK:   Top level indices: (count = 2)
+# CHECK:     [0]: function offset=0x00000efb, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK:     [1]: function offset=0x00000f00, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK:   LSDA descriptors:
+# CHECK:     [0]: function offset=0x00000efb, LSDA offset=0x00000f00
+# CHECK:   Second level indices:
+# CHECK:     Second level index[0]: offset in section=0x00000040, base function offset=0x00000efb
+# CHECK:       [0]: function offset=0x00000efb, encoding=0x51000000
+# CHECK:       [1]: function offset=0x00000efc, encoding=0x01000000
+# CHECK:       [2]: function offset=0x00000efd, encoding=0x04000018
+# CHECK:       [3]: function offset=0x00000efe, encoding=0x04000040
+# CHECK:       [4]: function offset=0x00000eff, encoding=0x00000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+--- !native
+path:            '<linker-internal>'
+defined-atoms:
+  - name:            GCC_except_table1
+    type:            unwind-lsda
+    content:         [ FF, 9B, A2, 80, 80, 00, 03, 1A, 08, 00, 00, 00,
+                       05, 00, 00, 00, 1A, 00, 00, 00, 01, 0D, 00, 00,
+                       00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00,
+                       04, 00, 00, 00 ]
+  - type:            compact-unwind
+    content:         [ 40, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 41, 00, 00, 00, 00, 00, 00, 00, 00,
+                       E0, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          __Z3barv
+      - kind:            pointer64
+        offset:          16
+        target:          ___gxx_personality_v0
+      - kind:            pointer64Anon
+        offset:          24
+        target:          GCC_except_table1
+  - type:            compact-unwind
+    content:         [ C0, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          _main
+  - type:            compact-unwind
+    content:         [ C1, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 04, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          _needsDwarfButNoCompactUnwind
+
+# Generic x86_64 CIE:
+  - name:            LCIE
+    type:            unwind-cfi
+    content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+                       01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _needsDwarfButNoCompactUnwind
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 44, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _needsDwarfSaysCompactUnwind
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 6C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _main
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - name:            __Z3barv
+    scope:           global
+    content:         [ C3 ]
+  - name:            _main
+    scope:           global
+    content:         [ C3 ]
+  - name:            _needsDwarfButNoCompactUnwind
+    scope:           global
+    content:         [ C3 ]
+  - name:            _needsDwarfSaysCompactUnwind
+    scope:           global
+    content:         [ C3 ]
+  - name:            _noUnwindData
+    scope:           global
+    content:         [ C3 ]
+
+shared-library-atoms:
+  - name:            ___gxx_personality_v0
+    load-name:       '/usr/lib/libc++abi.dylib'
+    type:            unknown
diff --git a/test/mach-o/upward-dylib-load-command.yaml b/test/mach-o/upward-dylib-load-command.yaml
new file mode 100644 (file)
index 0000000..1383ad7
--- /dev/null
@@ -0,0 +1,48 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN:     -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library  %t1.dylib \
+# RUN:      -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+#
+# Test upward linking: 1) build libbar.dylib, 2) build libfoo.dylib and upward
+# like with libbar.dylib, 3) dump load commands of libfoo and verify upward link.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:                     cmd LC_LOAD_UPWARD_DYLIB
+# CHECK-NEXT:        cmdsize 48
+# CHECK-NEXT:           name /usr/lib/libbar.dylib (offset 24)
diff --git a/test/mach-o/upward-dylib-paths.yaml b/test/mach-o/upward-dylib-paths.yaml
new file mode 100644 (file)
index 0000000..53ff9fa
--- /dev/null
@@ -0,0 +1,18 @@
+#
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/lib/libfoo.dylib \
+# RUN:        -path_exists /opt/stuff/libstuff.dylib \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -upward_framework Bar \
+# RUN:        -upward-lfoo \
+# RUN:        -upward_library /opt/stuff/libstuff.dylib \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Found upward framework /Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found upward library /usr/lib/libfoo.dylib
+
+
diff --git a/test/mach-o/usage.yaml b/test/mach-o/usage.yaml
new file mode 100644 (file)
index 0000000..20a5062
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: not lld -flavor darwin | FileCheck %s
+#
+# Test that running darwin linker with no option prints out usage message.
+#
+
+
+# CHECK:                 USAGE:
+# CHECK:                 -arch
diff --git a/test/mach-o/use-simple-dylib.yaml b/test/mach-o/use-simple-dylib.yaml
new file mode 100644 (file)
index 0000000..658be16
--- /dev/null
@@ -0,0 +1,73 @@
+# RUN: lld -flavor darwin -arch x86_64 -print_atoms -r %s \
+# RUN: %p/Inputs/use-simple-dylib.yaml -o %t | FileCheck %s
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+                       0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _myGlobal
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myGlobalWeak
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myHidden
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myHiddenWeak
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myResolver
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myStatic
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myVariablePreviouslyKnownAsPrivateExtern
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _myStatic
+# CHECK:   - name:            _myVariablePreviouslyKnownAsPrivateExtern
+# CHECK: shared-library-atoms:
+# CHECK:   - name:            _myGlobal
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myGlobalWeak
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myHidden
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myHiddenWeak
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myResolver
+# CHECK:     load-name:       libspecial.dylib
diff --git a/test/mach-o/version-min-load-command-object.yaml b/test/mach-o/version-min-load-command-object.yaml
new file mode 100644 (file)
index 0000000..33001cc
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# If we are emitting an object file, then we only emit a min version load command if the source object file(s) all have
+# version(s) and either known platforms or contain min version load commands themselves.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+min-os-version-kind: LC_VERSION_MIN_MACOSX
+min-os-version: 10.8
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_VERSION_MIN_MACOSX
+# CHECK:   cmdsize 16
+# CHECK:   version 10.8
+# CHECK:   sdk n/a
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX
\ No newline at end of file
diff --git a/test/mach-o/version-min-load-command.yaml b/test/mach-o/version-min-load-command.yaml
new file mode 100644 (file)
index 0000000..aa378a7
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml 2>&1 | FileCheck %s --check-prefix=WARNING
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -sdk_version 10.9 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_VERSION_MIN_MACOSX
+# CHECK:   cmdsize 16
+# CHECK:   version 10.8
+# CHECK:   sdk 10.8
+
+# SDK_VERSION: Load command {{[0-9]*}}
+# SDK_VERSION:   cmd LC_VERSION_MIN_MACOSX
+# SDK_VERSION:   cmdsize 16
+# SDK_VERSION:   version 10.8
+# SDK_VERSION:   sdk 10.9
+
+# WARNING: warning: -sdk_version is required when emitting min version load command.  Setting sdk version to match provided min version
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX
diff --git a/test/mach-o/write-final-sections.yaml b/test/mach-o/write-final-sections.yaml
new file mode 100644 (file)
index 0000000..4e94acf
--- /dev/null
@@ -0,0 +1,165 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/write-final-sections.yaml \
+# RUN: -o %t -e _foo
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+# For __TEXT, __text (with typeCode)
+  - name:            _foo
+    scope:           global
+    content:         [ 55 ]
+# CHECK: Name: __text
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 55
+# CHECK-NEXT: )
+
+#  For __TEXT, __const (with typeConstant),
+  - type:            constant
+    content:         [ 01, 00, 00, 00 ]
+#  From __TEXT, __literal4, (with typeLiteral4)
+  - scope:           hidden
+    type:            const-4-byte
+    content:         [ 02, 00, 00, 00 ]
+#  From __TEXT, __literal8, (with typeLiteral8)
+  - scope:           hidden
+    type:            const-8-byte
+    content:         [ 03, 00, 00, 00, 00, 00, 00, 00 ]
+#  From __TEXT, __literal16, (with typeLiteral16)
+  - scope:           hidden
+    type:            const-16-byte
+    content:         [ 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 01000000 02000000 03000000 00000000
+# CHECK-NEXT: 0010: 04000000 00000000 00000000 00000000
+# CHECK-NEXT: )
+
+# For __TEXT, __cstring (with typeCString)
+  - scope:           hidden
+    type:            c-string
+    content:         [ 57, 69, 62, 62, 6C, 65, 00 ]
+    merge:           by-content
+# CHECK: Name: __cstring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 57696262 6C6500
+# CHECK-NEXT: )
+
+# For __TEXT, __ustring (with typeUTF16String)
+  - scope:           hidden
+    type:            utf16-string
+    content:         [ 05, 00 ]
+    merge:           by-content
+# CHECK: Name: __ustring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0500
+# CHECK-NEXT: )
+
+#  For __TEXT, __gcc_except_tab, (with typeLSDA)
+  - name:            GCC_except_table0
+    type:            unwind-lsda
+    content:         [ 06, 00 ]
+# CHECK: Name: __gcc_except_tab
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0600
+# CHECK-NEXT: )
+
+#  For __TEXT, __eh_frame, (with typeCFI)
+  - name:            LCIE
+    type:            unwind-cfi
+    content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+                       01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _foo
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+# CHECK: Name: __eh_frame
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT:      0000: 14000000 00000000 017A5200 01781001
+# CHECK-NEXT:      0010: 100C0708 90010000 24000000 1C000000
+# CHECK-NEXT:      0020: 70FFFFFF FFFFFFFF 01000000 00000000
+# CHECK-NEXT:      0030: 00410E10 8602430D 06000000 00000000
+# CHECK-NEXT: )
+
+#  For __DATA, __data, (with typeData)
+  - name:            var
+    type:            data
+    content:         [ 08 ]
+# CHECK: Name: __data
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 08
+# CHECK-NEXT: )
+
+#  For __DATA, __bss (with typeZeroFill)
+# FIXME: Attributes & tags of __bss are mostly broken. Should be at end of
+#        __DATA, should have size, should have S_ZEROFILL flag.
+  - type:            zero-fill
+    size:            8
+# CHECK: Name: __bss
+# CHECK: Segment: __DATA
+
+#  For __DATA, __const, (with typeConstData)
+  - type:            const-data
+    content:         [ 09, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 09000000
+# CHECK-NEXT: )
+
+#  For __DATA, __cfstring, (with typeCFString)
+  - type:            cfstring
+    content:         [ 0A, 00 ]
+# CHECK: Name: __cfstring
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0A00
+# CHECK-NEXT: )
+
+#  For __DATA, __got (with typeGOT)
+  - type:            got
+    content:         [ 0B, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __got
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0B000000 00000000
+# CHECK-NEXT: )
+
+
+#  For __DATA, __mod_init_func (with typeInitializerPtr)
+  - type:            initializer-pointer
+    content:         [ 0C, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_init_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0C000000 00000000
+# CHECK-NEXT: )
+
+#  For __DATA, __mod_term_func (with typeTerminatorPointer)
+  - type:            terminator-pointer
+    content:         [ 0D, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_term_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0D000000 00000000
+# CHECK-NEXT: )
+
+  - type:            compact-unwind
+    content:         [ 0E, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK-NOT: Name: __compact_unwind
diff --git a/test/mach-o/wrong-arch-error.yaml b/test/mach-o/wrong-arch-error.yaml
new file mode 100644 (file)
index 0000000..3b8ef0d
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s \
+# RUN: %p/Inputs/wrong-arch-error.yaml 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xCC ]
+
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+
+# CHECK:       wrong architecture
diff --git a/tools/lld/CMakeLists.txt b/tools/lld/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5951da6
--- /dev/null
@@ -0,0 +1,24 @@
+add_llvm_executable(lld
+  lld.cpp
+  )
+
+target_link_libraries(lld
+  lldDriver
+  lldCOFF
+  lldELF
+  LLVMSupport
+  )
+
+install(TARGETS lld
+  RUNTIME DESTINATION bin)
+
+if(NOT LLD_SYMLINKS_TO_CREATE)
+  set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld)
+endif()
+
+foreach(link ${LLD_SYMLINKS_TO_CREATE})
+  add_llvm_tool_symlink(${link} lld ALWAYS_GENERATE)
+  # Always generate install targets
+  llvm_install_symlink(${link} lld ALWAYS_GENERATE)
+endforeach()
+
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
new file mode 100644 (file)
index 0000000..8805e02
--- /dev/null
@@ -0,0 +1,115 @@
+//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the lld driver. This is a thin wrapper which
+// dispatches to the given platform specific driver.
+//
+// If there is -flavor option, it is dispatched according to the arguments.
+// If the flavor parameter is not present, then it is dispatched according
+// to argv[0].
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+using namespace llvm;
+using namespace llvm::sys;
+
+enum Flavor {
+  Invalid,
+  Gnu,     // -flavor gnu
+  WinLink, // -flavor link
+  Darwin,  // -flavor darwin
+};
+
+LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
+  errs() << S << "\n";
+  exit(1);
+}
+
+static Flavor getFlavor(StringRef S) {
+  return StringSwitch<Flavor>(S)
+      .Case("ld", Gnu)
+      .Case("ld.lld", Gnu)
+      .Case("gnu", Gnu)
+      .Case("link", WinLink)
+      .Case("darwin", Darwin)
+      .Default(Invalid);
+}
+
+static Flavor parseProgname(StringRef Progname) {
+#if __APPLE__
+  // Use Darwin driver for "ld" on Darwin.
+  if (Progname == "ld")
+    return Darwin;
+#endif
+
+#if LLVM_ON_UNIX
+  // Use GNU driver for "ld" on other Unix-like system.
+  if (Progname == "ld")
+    return Gnu;
+#endif
+
+  // Progname may be something like "lld-gnu". Parse it.
+  SmallVector<StringRef, 3> V;
+  Progname.split(V, "-");
+  for (StringRef S : V)
+    if (Flavor F = getFlavor(S))
+      return F;
+  return Invalid;
+}
+
+static Flavor parseFlavor(std::vector<const char *> &V) {
+  // Parse -flavor option.
+  if (V.size() > 1 && V[1] == StringRef("-flavor")) {
+    if (V.size() <= 2)
+      die("missing arg value for '-flavor'");
+    Flavor F = getFlavor(V[2]);
+    if (F == Invalid)
+      die("Unknown flavor: " + StringRef(V[2]));
+    V.erase(V.begin() + 1, V.begin() + 3);
+    return F;
+  }
+
+  // Deduct the flavor from argv[0].
+  StringRef Arg0 = path::filename(V[0]);
+  if (Arg0.endswith_lower(".exe"))
+    Arg0 = Arg0.drop_back(4);
+  return parseProgname(Arg0);
+}
+
+/// Universal linker main(). This linker emulates the gnu, darwin, or
+/// windows linker based on the argv[0] or -flavor option.
+int main(int Argc, const char **Argv) {
+  // Standard set up, so program fails gracefully.
+  sys::PrintStackTraceOnErrorSignal(Argv[0]);
+  PrettyStackTraceProgram StackPrinter(Argc, Argv);
+  llvm_shutdown_obj Shutdown;
+
+  std::vector<const char *> Args(Argv, Argv + Argc);
+  switch (parseFlavor(Args)) {
+  case Gnu:
+    return !elf::link(Args);
+  case WinLink:
+    return !coff::link(Args);
+  case Darwin:
+    return !mach_o::link(Args);
+  default:
+    die("lld is a generic driver.\n"
+        "Invoke ld.lld (Unix), ld (Mac) or lld-link (Windows) instead.");
+  }
+}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bb651b5
--- /dev/null
@@ -0,0 +1,15 @@
+add_custom_target(LLDUnitTests)
+set_target_properties(LLDUnitTests PROPERTIES FOLDER "lld tests")
+
+# add_lld_unittest(test_dirname file1.cpp file2.cpp)
+#
+# Will compile the list of files together and link against lld
+# Produces a binary named 'basename(test_dirname)'.
+function(add_lld_unittest test_dirname)
+  add_unittest(LLDUnitTests ${test_dirname} ${ARGN})
+  target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS})
+endfunction()
+
+add_subdirectory(CoreTests)
+add_subdirectory(DriverTests)
+add_subdirectory(MachOTests)
diff --git a/unittests/CoreTests/CMakeLists.txt b/unittests/CoreTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..98405d5
--- /dev/null
@@ -0,0 +1,7 @@
+add_lld_unittest(CoreTests
+  ParallelTest.cpp
+  )
+
+target_link_libraries(CoreTests
+  ${PTHREAD_LIB}
+  )
diff --git a/unittests/CoreTests/ParallelTest.cpp b/unittests/CoreTests/ParallelTest.cpp
new file mode 100644 (file)
index 0000000..c028243
--- /dev/null
@@ -0,0 +1,31 @@
+//===- lld/unittest/ParallelTest.cpp --------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Parallel.h unit tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "lld/Core/Parallel.h"
+#include <array>
+#include <random>
+
+uint32_t array[1024 * 1024];
+
+TEST(Parallel, sort) {
+  std::mt19937 randEngine;
+  std::uniform_int_distribution<uint32_t> dist;
+
+  for (auto &i : array)
+    i = dist(randEngine);
+
+  lld::parallel_sort(std::begin(array), std::end(array));
+  ASSERT_TRUE(std::is_sorted(std::begin(array), std::end(array)));
+}
diff --git a/unittests/DriverTests/CMakeLists.txt b/unittests/DriverTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..91d22ca
--- /dev/null
@@ -0,0 +1,8 @@
+add_lld_unittest(DriverTests
+  DarwinLdDriverTest.cpp
+  )
+
+target_link_libraries(DriverTests
+  lldDriver
+  lldMachO
+  )
diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp
new file mode 100644 (file)
index 0000000..ea7fcc7
--- /dev/null
@@ -0,0 +1,267 @@
+//===- lld/unittest/DarwinLdDriverTest.cpp --------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Darwin's ld driver tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace lld;
+
+namespace lld {
+namespace mach_o {
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
+           raw_ostream &diagnostics);
+}
+}
+
+namespace {
+class DarwinLdParserTest : public testing::Test {
+protected:
+  int inputFileCount() { return _ctx.getNodes().size(); }
+
+  std::string inputFile(int index) {
+    Node &node = *_ctx.getNodes()[index];
+    if (node.kind() == Node::Kind::File)
+      return cast<FileNode>(&node)->getFile()->path();
+    llvm_unreachable("not handling other types of input files");
+  }
+
+  bool parse(std::vector<const char *> args) {
+    args.insert(args.begin(), "ld");
+    std::string errorMessage;
+    raw_string_ostream os(errorMessage);
+    return mach_o::parse(args, _ctx, os);
+  }
+
+  MachOLinkingContext _ctx;
+};
+}
+
+TEST_F(DarwinLdParserTest, Basic) {
+  EXPECT_TRUE(parse({"foo.o", "bar.o", "-arch", "i386"}));
+  EXPECT_FALSE(_ctx.allowRemainingUndefines());
+  EXPECT_FALSE(_ctx.deadStrip());
+  EXPECT_EQ(2, inputFileCount());
+  EXPECT_EQ("foo.o", inputFile(0));
+  EXPECT_EQ("bar.o", inputFile(1));
+}
+
+TEST_F(DarwinLdParserTest, Output) {
+  EXPECT_TRUE(parse({"-o", "my.out", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ("my.out", _ctx.outputPath());
+}
+
+TEST_F(DarwinLdParserTest, Dylib) {
+  EXPECT_TRUE(parse({"-dylib", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_DYLIB, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Relocatable) {
+  EXPECT_TRUE(parse({"-r", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_OBJECT, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Bundle) {
+  EXPECT_TRUE(parse({"-bundle", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_BUNDLE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Preload) {
+  EXPECT_TRUE(parse({"-preload", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_PRELOAD, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Static) {
+  EXPECT_TRUE(parse({"-static", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_EXECUTE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Entry) {
+  EXPECT_TRUE(parse({"-e", "entryFunc", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ("entryFunc", _ctx.entrySymbolName());
+}
+
+TEST_F(DarwinLdParserTest, DeadStrip) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dead_strip", "foo.o"}));
+  EXPECT_TRUE(_ctx.deadStrip());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExe) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsDylib) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dylib", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsRelocatable) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-r", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicExe) {
+  EXPECT_TRUE(
+      parse({"-arch", "x86_64", "-dead_strip", "-export_dynamic", "foo.o"}));
+  EXPECT_TRUE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicDylib) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dylib", "-dead_strip",
+                     "-export_dynamic", "foo.o"}));
+  EXPECT_TRUE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicRelocatable) {
+  EXPECT_TRUE(parse(
+      {"-arch", "x86_64", "-r", "-dead_strip", "-export_dynamic", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, Arch) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_x86_64, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_X86_64, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_64_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_x86) {
+  EXPECT_TRUE(parse({"-arch", "i386", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_x86, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_I386, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv6) {
+  EXPECT_TRUE(parse({"-arch", "armv6", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv6, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V6, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7) {
+  EXPECT_TRUE(parse({"-arch", "armv7", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv7, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7s) {
+  EXPECT_TRUE(parse({"-arch", "armv7s", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv7s, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7S, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_7) {
+  EXPECT_TRUE(
+      parse({"-macosx_version_min", "10.7", "foo.o", "-arch", "x86_64"}));
+  EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("10.7", ""));
+  EXPECT_FALSE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_8) {
+  EXPECT_TRUE(
+      parse({"-macosx_version_min", "10.8.3", "foo.o", "-arch", "x86_64"}));
+  EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("10.7", ""));
+  EXPECT_TRUE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, iOS5) {
+  EXPECT_TRUE(parse({"-ios_version_min", "5.0", "foo.o", "-arch", "armv7"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS6) {
+  EXPECT_TRUE(parse({"-ios_version_min", "6.0", "foo.o", "-arch", "armv7"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator5) {
+  EXPECT_TRUE(
+      parse({"-ios_simulator_version_min", "5.0", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator6) {
+  EXPECT_TRUE(
+      parse({"-ios_simulator_version_min", "6.0", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersion) {
+  EXPECT_TRUE(parse(
+      {"-dylib", "-compatibility_version", "1.2.3", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.compatibilityVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidType) {
+  EXPECT_FALSE(parse(
+      {"-bundle", "-compatibility_version", "1.2.3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidValue) {
+  EXPECT_FALSE(parse(
+      {"-bundle", "-compatibility_version", "1,2,3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, currentVersion) {
+  EXPECT_TRUE(
+      parse({"-dylib", "-current_version", "1.2.3", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.currentVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidType) {
+  EXPECT_FALSE(
+      parse({"-bundle", "-current_version", "1.2.3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidValue) {
+  EXPECT_FALSE(
+      parse({"-bundle", "-current_version", "1,2,3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, bundleLoader) {
+  EXPECT_TRUE(
+      parse({"-bundle", "-bundle_loader", "/bin/ls", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.bundleLoader(), "/bin/ls");
+}
+
+TEST_F(DarwinLdParserTest, bundleLoaderInvalidType) {
+  EXPECT_FALSE(parse({"-bundle_loader", "/bin/ls", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylib) {
+  EXPECT_TRUE(
+      parse({"-dylib", "-mark_dead_strippable_dylib", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(true, _ctx.deadStrippableDylib());
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylibInvalidType) {
+  EXPECT_FALSE(parse({"-mark_dead_strippable_dylib", "a.o", "-arch", "i386"}));
+}
diff --git a/unittests/MachOTests/CMakeLists.txt b/unittests/MachOTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1a68348
--- /dev/null
@@ -0,0 +1,13 @@
+
+add_lld_unittest(lldMachOTests
+  MachONormalizedFileBinaryReaderTests.cpp
+  MachONormalizedFileBinaryWriterTests.cpp
+  MachONormalizedFileToAtomsTests.cpp
+  MachONormalizedFileYAMLTests.cpp
+  )
+
+target_link_libraries(lldMachOTests
+  lldDriver
+  lldMachO
+  lldYAML
+  )
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
new file mode 100644 (file)
index 0000000..a3c445a
--- /dev/null
@@ -0,0 +1,749 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryReaderTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <memory>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+static std::unique_ptr<NormalizedFile>
+fromBinary(const uint8_t bytes[], unsigned length, StringRef archStr) {
+  StringRef sr((const char*)bytes, length);
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(sr, "", false));
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r =
+      lld::mach_o::normalized::readBinary(
+          mb, lld::MachOLinkingContext::archFromName(archStr));
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+// The Mach-O object reader uses functions such as read32 or read64
+// which don't allow unaligned access. Our in-memory object file
+// needs to be aligned to a larger boundary than uint8_t's.
+#if _MSC_VER
+#define FILEBYTES __declspec(align(64)) const uint8_t fileBytes[]
+#else
+#define FILEBYTES const uint8_t fileBytes[] __attribute__((aligned(64)))
+#endif
+
+TEST(BinaryReaderTest, empty_obj_x86_64) {
+  FILEBYTES = {
+      0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01,
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x19, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_x86) {
+  FILEBYTES = {
+      0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00,
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "i386");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_ppc) {
+  FILEBYTES = {
+      0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c,
+      0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+      0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_armv7) {
+  FILEBYTES = {
+      0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00,
+      0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_x86_64_arm7) {
+  FILEBYTES = {
+#include "empty_obj_x86_armv7.txt"
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+
+  std::unique_ptr<NormalizedFile> f2 =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+  EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f2->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f2->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_TRUE(f2->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, hello_obj_x86_64) {
+  FILEBYTES = {
+    0xCF, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x01,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x19, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0xA4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x9D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0xB4, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0xE4, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x0B, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+    0x48, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00, 0xC7,
+    0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00,
+    0xE8, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x48,
+    0x83, 0xC4, 0x10, 0x5D, 0xC3, 0x68, 0x65, 0x6C,
+    0x6C, 0x6F, 0x0A, 0x00, 0x19, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x2D, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x1D, 0x0F, 0x00, 0x00, 0x00,
+    0x0E, 0x02, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x4C, 0x5F, 0x2E, 0x73, 0x74,
+    0x72, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 45UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x48);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 2UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x19));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 2U);
+  const Relocation& str = text.relocations[1];
+  EXPECT_EQ(str.offset, Hex32(0xB));
+  EXPECT_EQ(str.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(str.length, 2);
+  EXPECT_EQ(str.isExtern, true);
+  EXPECT_EQ(str.symbol, 0U);
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x02D));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& strLabel = f->localSymbols[0];
+  EXPECT_EQ(strLabel.type, N_SECT);
+  EXPECT_EQ(strLabel.sect, 2);
+  EXPECT_EQ(strLabel.value, Hex64(0x2D));
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_x86) {
+  FILEBYTES = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xE5, 0x83,
+    0xEC, 0x18, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x58,
+    0x8D, 0x80, 0x25, 0x00, 0x00, 0x00, 0xC7, 0x45,
+    0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x04, 0x24,
+    0xE8, 0xDF, 0xFF, 0xFF, 0xFF, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x83,
+    0xC4, 0x18, 0x5D, 0xC3, 0x68, 0x65, 0x6C, 0x6C,
+    0x6F, 0x0A, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0xA4,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1,
+    0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "i386");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 48UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x89);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 3UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1D));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& sectDiff = text.relocations[1];
+  EXPECT_EQ(sectDiff.offset, Hex32(0xE));
+  EXPECT_EQ(sectDiff.scattered, true);
+  EXPECT_EQ(sectDiff.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(sectDiff.pcRel, false);
+  EXPECT_EQ(sectDiff.length, 2);
+  EXPECT_EQ(sectDiff.value, 0x30U);
+  const Relocation& pair = text.relocations[2];
+  EXPECT_EQ(pair.offset, Hex32(0x0));
+  EXPECT_EQ(pair.scattered, true);
+  EXPECT_EQ(pair.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pair.pcRel, false);
+  EXPECT_EQ(pair.length, 2);
+  EXPECT_EQ(pair.value, 0x0BU);
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x030));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_armv7) {
+  FILEBYTES = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0xB5, 0x6F, 0x46,
+    0x82, 0xB0, 0x40, 0xF2, 0x18, 0x00, 0xC0, 0xF2,
+    0x00, 0x00, 0x78, 0x44, 0x00, 0x21, 0xC0, 0xF2,
+    0x00, 0x01, 0x01, 0x91, 0xFF, 0xF7, 0xF2, 0xFF,
+    0x00, 0x21, 0xC0, 0xF2, 0x00, 0x01, 0x00, 0x90,
+    0x08, 0x46, 0x02, 0xB0, 0x80, 0xBD, 0x68, 0x65,
+    0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x6D,
+    0x0A, 0x00, 0x00, 0xB9, 0x2A, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0xB1, 0x0E, 0x00, 0x00, 0x00,
+    0x06, 0x00, 0x00, 0xA9, 0x2A, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xA1, 0x0E, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 42UL);
+  EXPECT_EQ((int)(text.content[0]), 0x80);
+  EXPECT_EQ((int)(text.content[1]), 0xB5);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x18));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& movt = text.relocations[1];
+  EXPECT_EQ(movt.offset, Hex32(0xA));
+  EXPECT_EQ(movt.scattered, true);
+  EXPECT_EQ(movt.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt.length, 3);
+  EXPECT_EQ(movt.value, Hex32(0x2A));
+  const Relocation& movtPair = text.relocations[2];
+  EXPECT_EQ(movtPair.offset, Hex32(0x18));
+  EXPECT_EQ(movtPair.scattered, true);
+  EXPECT_EQ(movtPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movtPair.length, 3);
+  EXPECT_EQ(movtPair.value, Hex32(0xE));
+  const Relocation& movw = text.relocations[3];
+  EXPECT_EQ(movw.offset, Hex32(0x6));
+  EXPECT_EQ(movw.scattered, true);
+  EXPECT_EQ(movw.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw.length, 2);
+  EXPECT_EQ(movw.value, Hex32(0x2A));
+  const Relocation& movwPair = text.relocations[4];
+  EXPECT_EQ(movwPair.offset, Hex32(0x0));
+  EXPECT_EQ(movwPair.scattered, true);
+  EXPECT_EQ(movwPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movwPair.length, 2);
+  EXPECT_EQ(movwPair.value, Hex32(0xE));
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x02A));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_ppc) {
+  FILEBYTES = {
+    0xFE, 0xED, 0xFA, 0xCE, 0x00, 0x00, 0x00, 0x12,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x28,
+    0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x90,
+    0x00, 0x00, 0x00, 0x05, 0x80, 0x00, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0xB8,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0xD0,
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0B,
+    0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x02, 0xA6,
+    0xBF, 0xC1, 0xFF, 0xF8, 0x90, 0x01, 0x00, 0x08,
+    0x94, 0x21, 0xFF, 0xB0, 0x7C, 0x3E, 0x0B, 0x78,
+    0x42, 0x9F, 0x00, 0x05, 0x7F, 0xE8, 0x02, 0xA6,
+    0x3C, 0x5F, 0x00, 0x00, 0x38, 0x62, 0x00, 0x2C,
+    0x4B, 0xFF, 0xFF, 0xDD, 0x38, 0x00, 0x00, 0x00,
+    0x7C, 0x03, 0x03, 0x78, 0x80, 0x21, 0x00, 0x00,
+    0x80, 0x01, 0x00, 0x08, 0x7C, 0x08, 0x03, 0xA6,
+    0xBB, 0xC1, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20,
+    0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0xD3,
+    0xAB, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+    0xAC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x18,
+    0x00, 0x00, 0x00, 0x01, 0x0F, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 68UL);
+  EXPECT_EQ((int)(text.content[0]), 0x7C);
+  EXPECT_EQ((int)(text.content[1]), 0x08);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& bl = text.relocations[0];
+  EXPECT_EQ(bl.offset, Hex32(0x24));
+  EXPECT_EQ(bl.type, PPC_RELOC_BR24);
+  EXPECT_EQ(bl.length, 2);
+  EXPECT_EQ(bl.isExtern, true);
+  EXPECT_EQ(bl.symbol, 1U);
+  const Relocation& lo = text.relocations[1];
+  EXPECT_EQ(lo.offset, Hex32(0x20));
+  EXPECT_EQ(lo.scattered, true);
+  EXPECT_EQ(lo.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(lo.length, 2);
+  EXPECT_EQ(lo.value, Hex32(0x44));
+  const Relocation& loPair = text.relocations[2];
+  EXPECT_EQ(loPair.offset, Hex32(0x0));
+  EXPECT_EQ(loPair.scattered, true);
+  EXPECT_EQ(loPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(loPair.length, 2);
+  EXPECT_EQ(loPair.value, Hex32(0x18));
+  const Relocation& ha = text.relocations[3];
+  EXPECT_EQ(ha.offset, Hex32(0x1C));
+  EXPECT_EQ(ha.scattered, true);
+  EXPECT_EQ(ha.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(ha.length, 2);
+  EXPECT_EQ(ha.value, Hex32(0x44));
+  const Relocation& haPair = text.relocations[4];
+  EXPECT_EQ(haPair.offset, Hex32(0x2c));
+  EXPECT_EQ(haPair.scattered, true);
+  EXPECT_EQ(haPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(haPair.length, 2);
+  EXPECT_EQ(haPair.value, Hex32(0x18));
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 4U);
+  EXPECT_EQ(cstring.address, Hex64(0x044));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+
+  auto ec = writeBinary(*f, "/tmp/foo.o");
+  // FIXME: We want to do EXPECT_FALSE(ec) but that fails on some Windows bots,
+  // probably due to /tmp not being available.
+  // For now just consume the error without checking it.
+  consumeError(std::move(ec));
+}
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
new file mode 100644 (file)
index 0000000..f44950a
--- /dev/null
@@ -0,0 +1,692 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryWriterTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MachO.h"
+#include <cassert>
+#include <memory>
+#include <system_error>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::SmallString;
+using llvm::Twine;
+using llvm::ErrorOr;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+// Parses binary mach-o file at specified path and returns
+// ownership of buffer to mb parameter and ownership of
+// Normalized file to nf parameter.
+static void fromBinary(StringRef path, std::unique_ptr<MemoryBuffer> &mb,
+                       std::unique_ptr<NormalizedFile> &nf, StringRef archStr) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path);
+  std::error_code ec = mbOrErr.getError();
+  EXPECT_FALSE(ec);
+  mb = std::move(mbOrErr.get());
+
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r =
+      lld::mach_o::normalized::readBinary(
+          mb, lld::MachOLinkingContext::archFromName(archStr));
+  EXPECT_FALSE(!r);
+  nf.reset(r->release());
+}
+
+static Relocation
+makeReloc(unsigned addr, bool rel, bool ext, RelocationInfoType type,
+                                                              unsigned sym) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = false;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = rel;
+  result.isExtern = ext;
+  result.value = 0;
+  result.symbol = sym;
+  return result;
+}
+
+static Relocation
+makeScatReloc(unsigned addr, RelocationInfoType type, unsigned value) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = true;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = false;
+  result.isExtern = true;
+  result.value = value;
+  result.symbol = 0;
+  return result;
+}
+
+static Symbol
+makeUndefSymbol(StringRef name) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_UNDF;
+  sym.scope = N_EXT;
+  sym.sect = NO_SECT;
+  sym.desc = 0;
+  sym.value = 0;
+  return sym;
+}
+
+
+static Symbol
+makeSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = 0;
+  sym.value = addr;
+  return sym;
+}
+
+static Symbol
+makeThumbSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = N_ARM_THUMB_DEF;
+  sym.value = addr;
+  return sym;
+}
+
+TEST(BinaryWriterTest, obj_relocs_x86_64) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 16;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x05,
+      0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00,
+      0x00, 0x00, 0x8b, 0x05, 0x00, 0x00, 0x00, 0x00,
+      0xc6, 0x05, 0xff, 0xff, 0xff, 0xff, 0x12, 0xc7,
+      0x05, 0xfc, 0xff, 0xff, 0xff, 0x78, 0x56, 0x34,
+      0x12, 0x48, 0x8b, 0x3d, 0x00, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, false, true, X86_64_RELOC_BRANCH, 1));
+    text.relocations.push_back(makeReloc(0x08, false, true, X86_64_RELOC_GOT_LOAD, 1));
+    text.relocations.push_back(makeReloc(0x0E, false, true, X86_64_RELOC_GOT, 1));
+    text.relocations.push_back(makeReloc(0x14, false, true, X86_64_RELOC_SIGNED, 1));
+    text.relocations.push_back(makeReloc(0x1A, false, true, X86_64_RELOC_SIGNED_1, 1));
+    text.relocations.push_back(makeReloc(0x21, false, true, X86_64_RELOC_SIGNED_4, 1));
+    text.relocations.push_back(makeReloc(0x2C, false, true, X86_64_RELOC_TLV, 2));
+
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "x86_64");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86_64, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(48UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& gotLoad = text.relocations[1];
+  EXPECT_EQ(gotLoad.offset, Hex32(0x8));
+  EXPECT_EQ(gotLoad.type, X86_64_RELOC_GOT_LOAD);
+  EXPECT_EQ(gotLoad.length, 2);
+  EXPECT_EQ(gotLoad.isExtern, true);
+  EXPECT_EQ(gotLoad.symbol, 1U);
+  const Relocation& gotUse = text.relocations[2];
+  EXPECT_EQ(gotUse.offset, Hex32(0xE));
+  EXPECT_EQ(gotUse.type, X86_64_RELOC_GOT);
+  EXPECT_EQ(gotUse.length, 2);
+  EXPECT_EQ(gotUse.isExtern, true);
+  EXPECT_EQ(gotUse.symbol, 1U);
+  const Relocation& signed0 = text.relocations[3];
+  EXPECT_EQ(signed0.offset, Hex32(0x14));
+  EXPECT_EQ(signed0.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(signed0.length, 2);
+  EXPECT_EQ(signed0.isExtern, true);
+  EXPECT_EQ(signed0.symbol, 1U);
+  const Relocation& signed1 = text.relocations[4];
+  EXPECT_EQ(signed1.offset, Hex32(0x1A));
+  EXPECT_EQ(signed1.type, X86_64_RELOC_SIGNED_1);
+  EXPECT_EQ(signed1.length, 2);
+  EXPECT_EQ(signed1.isExtern, true);
+  EXPECT_EQ(signed1.symbol, 1U);
+  const Relocation& signed4 = text.relocations[5];
+  EXPECT_EQ(signed4.offset, Hex32(0x21));
+  EXPECT_EQ(signed4.type, X86_64_RELOC_SIGNED_4);
+  EXPECT_EQ(signed4.length, 2);
+  EXPECT_EQ(signed4.isExtern, true);
+  EXPECT_EQ(signed4.symbol, 1U);
+
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_x86) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 16;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+       0xe8, 0xfb, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00,
+       0x00, 0x00, 0x8b, 0xb0, 0xfb, 0xff, 0xff, 0xff,
+       0x8b, 0x80, 0x11, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, true, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeReloc(0x06, false, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeScatReloc(0x0c, GENERIC_RELOC_LOCAL_SECTDIFF, 0));
+    text.relocations.push_back(makeScatReloc(0x0, GENERIC_RELOC_PAIR, 5));
+    text.relocations.push_back(makeReloc(0x12, true, true, GENERIC_RELOC_TLV, 1));
+
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "i386");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(22UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 0U);
+  const Relocation& absLoad = text.relocations[1];
+  EXPECT_EQ(absLoad.offset, Hex32(0x6));
+  EXPECT_EQ(absLoad.scattered, false);
+  EXPECT_EQ(absLoad.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(absLoad.pcRel, false);
+  EXPECT_EQ(absLoad.length, 2);
+  EXPECT_EQ(absLoad.isExtern, true);
+  EXPECT_EQ(absLoad.symbol,0U);
+  const Relocation& pic1 = text.relocations[2];
+  EXPECT_EQ(pic1.offset, Hex32(0xc));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic1.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(pic1.length, 2);
+  EXPECT_EQ(pic1.value, 0U);
+  const Relocation& pic2 = text.relocations[3];
+  EXPECT_EQ(pic2.offset, Hex32(0x0));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic2.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pic2.length, 2);
+  EXPECT_EQ(pic2.value, 5U);
+  const Relocation& tlv = text.relocations[4];
+  EXPECT_EQ(tlv.offset, Hex32(0x12));
+  EXPECT_EQ(tlv.type, GENERIC_RELOC_TLV);
+  EXPECT_EQ(tlv.length, 2);
+  EXPECT_EQ(tlv.isExtern, true);
+  EXPECT_EQ(tlv.symbol, 1U);
+
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_armv7) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_armv7;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xff, 0xf7, 0xfe, 0xef, 0x40, 0xf2, 0x05, 0x01,
+      0xc0, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0xbf };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true,
+                                        ARM_THUMB_RELOC_BR22, 2));
+    text.relocations.push_back(makeScatReloc(0x04,
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeScatReloc(0x08,
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeReloc(0x0C, false, true,
+                                        ARM_RELOC_VANILLA, 2));
+
+    f.globalSymbols.push_back(makeThumbSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeThumbSymbol("_foo2", 0x10));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "armv7");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_armv7, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(18UL, text.content.size());
+  const Relocation& blx = text.relocations[0];
+  EXPECT_EQ(blx.offset, Hex32(0x0));
+  EXPECT_EQ(blx.scattered, false);
+  EXPECT_EQ(blx.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(blx.pcRel, true);
+  EXPECT_EQ(blx.length, 2);
+  EXPECT_EQ(blx.isExtern, true);
+  EXPECT_EQ(blx.symbol, 2U);
+  const Relocation& movw1 = text.relocations[1];
+  EXPECT_EQ(movw1.offset, Hex32(0x4));
+  EXPECT_EQ(movw1.scattered, true);
+  EXPECT_EQ(movw1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw1.length, 2);
+  EXPECT_EQ(movw1.value, 0x10U);
+  const Relocation& movw2 = text.relocations[2];
+  EXPECT_EQ(movw2.offset, Hex32(0x0));
+  EXPECT_EQ(movw2.scattered, true);
+  EXPECT_EQ(movw2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movw2.length, 2);
+  EXPECT_EQ(movw2.value, Hex32(0xC));
+   const Relocation& movt1 = text.relocations[3];
+  EXPECT_EQ(movt1.offset, Hex32(0x8));
+  EXPECT_EQ(movt1.scattered, true);
+  EXPECT_EQ(movt1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt1.length, 2);
+  EXPECT_EQ(movt1.value, Hex32(0x10));
+  const Relocation& movt2 = text.relocations[4];
+  EXPECT_EQ(movt2.offset, Hex32(0x0));
+  EXPECT_EQ(movt2.scattered, true);
+  EXPECT_EQ(movt2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movt2.length, 2);
+  EXPECT_EQ(movt2.value, Hex32(0xC));
+ const Relocation& absPointer = text.relocations[5];
+  EXPECT_EQ(absPointer.offset, Hex32(0xC));
+  EXPECT_EQ(absPointer.type, ARM_RELOC_VANILLA);
+  EXPECT_EQ(absPointer.length, 2);
+  EXPECT_EQ(absPointer.isExtern, true);
+  EXPECT_EQ(absPointer.symbol, 2U);
+
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_ppc) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_ppc;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0x48, 0x00, 0x00, 0x01, 0x40, 0x82, 0xff, 0xfc,
+      0x3c, 0x62, 0x00, 0x00, 0x3c, 0x62, 0x00, 0x00,
+      0x80, 0x63, 0x00, 0x24, 0x80, 0x63, 0x00, 0x24,
+      0x3c, 0x40, 0x00, 0x00, 0x3c, 0x60, 0x00, 0x00,
+      0x80, 0x42, 0x00, 0x28, 0x80, 0x63, 0x00, 0x28,
+      0x60, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true,
+                                        PPC_RELOC_BR24, 2));
+    text.relocations.push_back(makeReloc(0x04, true, true,
+                                        PPC_RELOC_BR14, 2));
+    text.relocations.push_back(makeScatReloc(0x08,
+                                        PPC_RELOC_HI16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x0C,
+                                        PPC_RELOC_HA16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x10,
+                                        PPC_RELOC_LO16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x14,
+                                        PPC_RELOC_LO14_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeReloc(0x18, false, false,
+                                        PPC_RELOC_HI16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x1C, false, false,
+                                        PPC_RELOC_HA16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x20, false, false,
+                                        PPC_RELOC_LO16, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x24, false, false,
+                                        PPC_RELOC_LO14, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+
+    f.globalSymbols.push_back(makeSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeSymbol("_foo2", 0x28));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "ppc");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_ppc, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(44UL, text.content.size());
+  const Relocation& br24 = text.relocations[0];
+  EXPECT_EQ(br24.offset, Hex32(0x0));
+  EXPECT_EQ(br24.scattered, false);
+  EXPECT_EQ(br24.type, PPC_RELOC_BR24);
+  EXPECT_EQ(br24.pcRel, true);
+  EXPECT_EQ(br24.length, 2);
+  EXPECT_EQ(br24.isExtern, true);
+  EXPECT_EQ(br24.symbol, 2U);
+  const Relocation& br14 = text.relocations[1];
+  EXPECT_EQ(br14.offset, Hex32(0x4));
+  EXPECT_EQ(br14.scattered, false);
+  EXPECT_EQ(br14.type, PPC_RELOC_BR14);
+  EXPECT_EQ(br14.pcRel, true);
+  EXPECT_EQ(br14.length, 2);
+  EXPECT_EQ(br14.isExtern, true);
+  EXPECT_EQ(br14.symbol, 2U);
+  const Relocation& pichi1 = text.relocations[2];
+  EXPECT_EQ(pichi1.offset, Hex32(0x8));
+  EXPECT_EQ(pichi1.scattered, true);
+  EXPECT_EQ(pichi1.type, PPC_RELOC_HI16_SECTDIFF);
+  EXPECT_EQ(pichi1.length, 2);
+  EXPECT_EQ(pichi1.value, 0x28U);
+  const Relocation& pichi2 = text.relocations[3];
+  EXPECT_EQ(pichi2.offset, Hex32(0x24));
+  EXPECT_EQ(pichi2.scattered, true);
+  EXPECT_EQ(pichi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(pichi2.length, 2);
+  EXPECT_EQ(pichi2.value, 0x4U);
+  const Relocation& picha1 = text.relocations[4];
+  EXPECT_EQ(picha1.offset, Hex32(0xC));
+  EXPECT_EQ(picha1.scattered, true);
+  EXPECT_EQ(picha1.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(picha1.length, 2);
+  EXPECT_EQ(picha1.value, 0x28U);
+  const Relocation& picha2 = text.relocations[5];
+  EXPECT_EQ(picha2.offset, Hex32(0x24));
+  EXPECT_EQ(picha2.scattered, true);
+  EXPECT_EQ(picha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picha2.length, 2);
+  EXPECT_EQ(picha2.value, 0x4U);
+  const Relocation& piclo1 = text.relocations[6];
+  EXPECT_EQ(piclo1.offset, Hex32(0x10));
+  EXPECT_EQ(piclo1.scattered, true);
+  EXPECT_EQ(piclo1.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(piclo1.length, 2);
+  EXPECT_EQ(piclo1.value, 0x28U);
+  const Relocation& piclo2 = text.relocations[7];
+  EXPECT_EQ(piclo2.offset, Hex32(0x0));
+  EXPECT_EQ(piclo2.scattered, true);
+  EXPECT_EQ(piclo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(piclo2.length, 2);
+  EXPECT_EQ(piclo2.value, 0x4U);
+  const Relocation& picloa1 = text.relocations[8];
+  EXPECT_EQ(picloa1.offset, Hex32(0x14));
+  EXPECT_EQ(picloa1.scattered, true);
+  EXPECT_EQ(picloa1.type, PPC_RELOC_LO14_SECTDIFF);
+  EXPECT_EQ(picloa1.length, 2);
+  EXPECT_EQ(picloa1.value, 0x28U);
+  const Relocation& picloa2 = text.relocations[9];
+  EXPECT_EQ(picloa2.offset, Hex32(0x0));
+  EXPECT_EQ(picloa2.scattered, true);
+  EXPECT_EQ(picloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picloa2.length, 2);
+  EXPECT_EQ(picloa2.value, 0x4U);
+  const Relocation& abshi1 = text.relocations[10];
+  EXPECT_EQ(abshi1.offset, Hex32(0x18));
+  EXPECT_EQ(abshi1.scattered, false);
+  EXPECT_EQ(abshi1.type, PPC_RELOC_HI16);
+  EXPECT_EQ(abshi1.length, 2);
+  EXPECT_EQ(abshi1.symbol, 1U);
+  const Relocation& abshi2 = text.relocations[11];
+  EXPECT_EQ(abshi2.offset, Hex32(0x28));
+  EXPECT_EQ(abshi2.scattered, false);
+  EXPECT_EQ(abshi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abshi2.length, 2);
+  EXPECT_EQ(abshi2.symbol, 0U);
+  const Relocation& absha1 = text.relocations[12];
+  EXPECT_EQ(absha1.offset, Hex32(0x1C));
+  EXPECT_EQ(absha1.scattered, false);
+  EXPECT_EQ(absha1.type, PPC_RELOC_HA16);
+  EXPECT_EQ(absha1.length, 2);
+  EXPECT_EQ(absha1.symbol, 1U);
+  const Relocation& absha2 = text.relocations[13];
+  EXPECT_EQ(absha2.offset, Hex32(0x28));
+  EXPECT_EQ(absha2.scattered, false);
+  EXPECT_EQ(absha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absha2.length, 2);
+  EXPECT_EQ(absha2.symbol, 0U);
+  const Relocation& abslo1 = text.relocations[14];
+  EXPECT_EQ(abslo1.offset, Hex32(0x20));
+  EXPECT_EQ(abslo1.scattered, false);
+  EXPECT_EQ(abslo1.type, PPC_RELOC_LO16);
+  EXPECT_EQ(abslo1.length, 2);
+  EXPECT_EQ(abslo1.symbol, 1U);
+  const Relocation& abslo2 = text.relocations[15];
+  EXPECT_EQ(abslo2.offset, Hex32(0x00));
+  EXPECT_EQ(abslo2.scattered, false);
+  EXPECT_EQ(abslo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abslo2.length, 2);
+  EXPECT_EQ(abslo2.symbol, 0U);
+  const Relocation& absloa1 = text.relocations[16];
+  EXPECT_EQ(absloa1.offset, Hex32(0x24));
+  EXPECT_EQ(absloa1.scattered, false);
+  EXPECT_EQ(absloa1.type, PPC_RELOC_LO14);
+  EXPECT_EQ(absloa1.length, 2);
+  EXPECT_EQ(absloa1.symbol, 1U);
+  const Relocation& absloa2 = text.relocations[17];
+  EXPECT_EQ(absloa2.offset, Hex32(0x00));
+  EXPECT_EQ(absloa2.scattered, false);
+  EXPECT_EQ(absloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absloa2.length, 2);
+  EXPECT_EQ(absloa2.symbol, 0U);
+
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
diff --git a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp
new file mode 100644 (file)
index 0000000..8205ea9
--- /dev/null
@@ -0,0 +1,100 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileToAtomsTests.cpp --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <memory>
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+TEST(ToAtomsTest, empty_obj_x86_64) {
+  NormalizedFile f;
+  f.arch = lld::MachOLinkingContext::arch_x86_64;
+  llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
+      normalizedToAtoms(f, "", false);
+  EXPECT_FALSE(!atom_f);
+  EXPECT_EQ(0U, (*atom_f)->defined().size());
+}
+
+TEST(ToAtomsTest, basic_obj_x86_64) {
+  NormalizedFile f;
+  f.arch = lld::MachOLinkingContext::arch_x86_64;
+  Section textSection;
+  static const uint8_t contentBytes[] = { 0x90, 0xC3, 0xC3, 0xC4 };
+  const unsigned contentSize = sizeof(contentBytes) / sizeof(contentBytes[0]);
+  textSection.content = llvm::makeArrayRef(contentBytes, contentSize);
+  f.sections.push_back(textSection);
+  Symbol fooSymbol;
+  fooSymbol.name = "_foo";
+  fooSymbol.type = N_SECT;
+  fooSymbol.scope = N_EXT;
+  fooSymbol.sect = 1;
+  fooSymbol.value = 0;
+  f.globalSymbols.push_back(fooSymbol);
+  Symbol barSymbol;
+  barSymbol.name = "_bar";
+  barSymbol.type = N_SECT;
+  barSymbol.scope = N_EXT;
+  barSymbol.sect = 1;
+  barSymbol.value = 2;
+  f.globalSymbols.push_back(barSymbol);
+  Symbol undefSym;
+  undefSym.name = "_undef";
+  undefSym.type = N_UNDF;
+  f.undefinedSymbols.push_back(undefSym);
+  Symbol bazSymbol;
+  bazSymbol.name = "_baz";
+  bazSymbol.type = N_SECT;
+  bazSymbol.scope = N_EXT | N_PEXT;
+  bazSymbol.sect = 1;
+  bazSymbol.value = 3;
+  f.localSymbols.push_back(bazSymbol);
+
+  llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
+      normalizedToAtoms(f, "", false);
+  EXPECT_FALSE(!atom_f);
+  const lld::File &file = **atom_f;
+  EXPECT_EQ(3U, file.defined().size());
+  auto it = file.defined().begin();
+  const lld::DefinedAtom *atom1 = *it;
+  ++it;
+  const lld::DefinedAtom *atom2 = *it;
+  ++it;
+  const lld::DefinedAtom *atom3 = *it;
+  const lld::UndefinedAtom *atom4 = *file.undefined().begin();
+  EXPECT_TRUE(atom1->name().equals("_foo"));
+  EXPECT_EQ(2U, atom1->rawContent().size());
+  EXPECT_EQ(0x90, atom1->rawContent()[0]);
+  EXPECT_EQ(0xC3, atom1->rawContent()[1]);
+  EXPECT_EQ(lld::Atom::scopeGlobal, atom1->scope());
+
+  EXPECT_TRUE(atom2->name().equals("_bar"));
+  EXPECT_EQ(1U, atom2->rawContent().size());
+  EXPECT_EQ(0xC3, atom2->rawContent()[0]);
+  EXPECT_EQ(lld::Atom::scopeGlobal, atom2->scope());
+
+  EXPECT_TRUE(atom3->name().equals("_baz"));
+  EXPECT_EQ(1U, atom3->rawContent().size());
+  EXPECT_EQ(0xC4, atom3->rawContent()[0]);
+  EXPECT_EQ(lld::Atom::scopeLinkageUnit, atom3->scope());
+
+  EXPECT_TRUE(atom4->name().equals("_undef"));
+  EXPECT_EQ(lld::Atom::definitionUndefined, atom4->definition());
+}
diff --git a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp
new file mode 100644 (file)
index 0000000..e41b7ec
--- /dev/null
@@ -0,0 +1,763 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileYAMLTests.cpp -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <memory>
+#include <system_error>
+#include <string>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using lld::mach_o::normalized::NormalizedFile;
+using lld::mach_o::normalized::Symbol;
+using lld::mach_o::normalized::Section;
+using lld::mach_o::normalized::Relocation;
+
+static std::unique_ptr<NormalizedFile> fromYAML(StringRef str) {
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(str));
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r
+                                    = lld::mach_o::normalized::readYaml(mb);
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+static void toYAML(const NormalizedFile &f, std::string &out) {
+  llvm::raw_string_ostream ostr(out);
+  std::error_code ec = lld::mach_o::normalized::writeYaml(f, ostr);
+  EXPECT_TRUE(!ec);
+}
+
+// ppc is no longer supported, but it is here to test endianness handling.
+TEST(ObjectFileYAML, empty_ppc) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      ppc\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7s) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7s\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7s);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, roundTrip) {
+  std::string intermediate;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = llvm::MachO::MH_OBJECT;
+    f.flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    toYAML(f, intermediate);
+  }
+  {
+    std::unique_ptr<NormalizedFile> f2 = fromYAML(intermediate);
+    EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_x86_64);
+    EXPECT_EQ((int)(f2->fileType), llvm::MachO::MH_OBJECT);
+    EXPECT_EQ((int)(f2->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+    EXPECT_TRUE(f2->sections.empty());
+    EXPECT_TRUE(f2->localSymbols.empty());
+    EXPECT_TRUE(f2->globalSymbols.empty());
+    EXPECT_TRUE(f2->undefinedSymbols.empty());
+  }
+}
+
+TEST(ObjectFileYAML, oneSymbol) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ ]\n"
+    "    value:  0x100\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym = f->globalSymbols[0];
+  EXPECT_TRUE(sym.name.equals("_main"));
+  EXPECT_EQ((int)(sym.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym.sect, 1);
+  EXPECT_EQ((int)(sym.desc), 0);
+  EXPECT_EQ((uint64_t)sym.value, 0x100ULL);
+}
+
+TEST(ObjectFileYAML, oneSection) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS ]\n"
+    "    alignment:   2\n"
+    "    address:     0x12345678\n"
+    "    content:     [ 0x90, 0x90 ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->sections.size(), 1UL);
+  const Section& sect = f->sections[0];
+  EXPECT_TRUE(sect.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect.alignment, 2U);
+  EXPECT_EQ((uint64_t)sect.address, 0x12345678ULL);
+  EXPECT_EQ(sect.content.size(), 2UL);
+  EXPECT_EQ((int)(sect.content[0]), 0x90);
+  EXPECT_EQ((int)(sect.content[1]), 0x90);
+}
+
+TEST(ObjectFileYAML, hello_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   1\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x48, 0x89, 0xe5, 0x48, 0x8d, 0x3d, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x30, 0xc0, 0xe8, 0x00, 0x00,\n"
+    "                   0x00, 0x00, 0x31, 0xc0, 0x5d, 0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       X86_64_RELOC_BRANCH\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     2\n"
+    "     - offset:     0x07\n"
+    "       type:       X86_64_RELOC_SIGNED\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "local-symbols:\n"
+    "  - name:   L_.str\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ ]\n"
+    "    sect:   2\n"
+    "    value:  0x16\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x48);
+  EXPECT_EQ(sect1.relocations.size(), 2UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::X86_64_RELOC_BRANCH);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 2U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x07U);
+  EXPECT_FALSE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::X86_64_RELOC_SIGNED);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_TRUE(reloc2.pcRel);
+  EXPECT_TRUE(reloc2.isExtern);
+  EXPECT_EQ(reloc2.symbol, 1U);
+  EXPECT_EQ((int)(reloc2.value), 0);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& sym2 = f->localSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("L_.str"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 2);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x16ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym3 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym3.name.equals("_printf"));
+  EXPECT_EQ((int)(sym3.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym3.scope), 0);
+  EXPECT_EQ(sym3.sect, 0);
+  EXPECT_EQ((int)(sym3.desc), 0);
+  EXPECT_EQ((uint64_t)sym3.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   1\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08, 0xe8, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x58, 0x8d, 0x80, 0x16, 0x00,\n"
+    "                   0x00, 0x00, 0x89, 0x04, 0x24, 0xe8, 0xe6, 0xff,\n"
+    "                   0xff, 0xff, 0x31, 0xc0, 0x83, 0xc4, 0x08, 0x5d,\n"
+    "                   0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x16\n"
+    "       type:       GENERIC_RELOC_VANILLA\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x0e\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_LOCAL_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x21\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xb\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0021\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 33UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x89);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x16U);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0eU);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x21);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::GENERIC_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xb);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x021ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   4\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0x40, 0x2d, 0xe9, 0x10, 0x00, 0x9f, 0xe5,\n"
+    "                   0x0d, 0x70, 0xa0, 0xe1, 0x00, 0x00, 0x8f, 0xe0,\n"
+    "                   0xfa, 0xff, 0xff, 0xeb, 0x00, 0x00, 0xa0, 0xe3,\n"
+    "                   0x80, 0x80, 0xbd, 0xe8, 0x0c, 0x00, 0x00, 0x00 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x1c\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x20\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x10\n"
+    "       type:       ARM_RELOC_BR24\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0020\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 4U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 32UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0x40);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x1cU);
+  EXPECT_TRUE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_RELOC_SECTDIFF);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_FALSE(reloc1.pcRel);
+  EXPECT_EQ(reloc1.symbol, 0U);
+  EXPECT_EQ((int)(reloc1.value), 0x20);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0xc);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x10U);
+  EXPECT_FALSE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_BR24);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_TRUE(reloc3.pcRel);
+  EXPECT_TRUE(reloc3.isExtern);
+  EXPECT_EQ(reloc3.symbol, 1U);
+  EXPECT_EQ((int)(reloc3.value), 0);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x020ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   2\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0xb5, 0x40, 0xf2, 0x06, 0x00, 0x6f, 0x46,\n"
+    "                   0xc0, 0xf2, 0x00, 0x00, 0x78, 0x44, 0xff, 0xf7,\n"
+    "                   0xf8, 0xef, 0x00, 0x20, 0x80, 0xbd ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       ARM_THUMB_RELOC_BR22\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x08\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x06\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x02\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ N_ARM_THUMB_DEF ]\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 2U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0xb5);
+  EXPECT_EQ(sect1.relocations.size(), 5UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x8U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 3);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x16);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x6U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 3);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xc);
+   const Relocation& reloc4 = sect1.relocations[3];
+  EXPECT_EQ(reloc4.offset, 0x2U);
+  EXPECT_TRUE(reloc4.scattered);
+  EXPECT_EQ((int)reloc4.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc4.length, 2);
+  EXPECT_FALSE(reloc4.pcRel);
+  EXPECT_EQ(reloc4.symbol, 0U);
+  EXPECT_EQ((int)(reloc4.value), 0x16);
+  const Relocation& reloc5 = sect1.relocations[4];
+  EXPECT_EQ(reloc5.offset, 0x0U);
+  EXPECT_TRUE(reloc5.scattered);
+  EXPECT_EQ((int)reloc5.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc5.length, 2);
+  EXPECT_FALSE(reloc5.pcRel);
+  EXPECT_EQ(reloc5.symbol, 0U);
+  EXPECT_EQ((int)(reloc5.value), 0xc);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), (int)(llvm::MachO::N_ARM_THUMB_DEF));
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
diff --git a/unittests/MachOTests/empty_obj_x86_armv7.txt b/unittests/MachOTests/empty_obj_x86_armv7.txt
new file mode 100644 (file)
index 0000000..9d340cb
--- /dev/null
@@ -0,0 +1,1272 @@
+0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00,
+0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00, 0x09,
+0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00,
+0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74,
+0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00