aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:08:33 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:08:33 +0000
commit20d35e67e67f106f617c939725101223211659f0 (patch)
tree64eb963cbf5ba58765e0a6b64a440965d66a7a4d
parentae1a339de31cf4065777531959a11e55a2e5fa00 (diff)
Vendor import of lld trunk r338150:vendor/lld/lld-trunk-r338150
Notes
Notes: svn path=/vendor/lld/dist/; revision=336821 svn path=/vendor/lld/lld-trunk-r338150/; revision=336822; tag=vendor/lld/lld-trunk-r338150
-rw-r--r--COFF/CMakeLists.txt1
-rw-r--r--COFF/Chunks.cpp175
-rw-r--r--COFF/Chunks.h92
-rw-r--r--COFF/Config.h30
-rw-r--r--COFF/DLL.cpp2
-rw-r--r--COFF/DLL.h5
-rw-r--r--COFF/Driver.cpp430
-rw-r--r--COFF/Driver.h21
-rw-r--r--COFF/DriverUtils.cpp144
-rw-r--r--COFF/ICF.cpp90
-rw-r--r--COFF/ICF.h (renamed from COFF/Strings.h)21
-rw-r--r--COFF/InputFiles.cpp92
-rw-r--r--COFF/InputFiles.h51
-rw-r--r--COFF/LTO.cpp70
-rw-r--r--COFF/LTO.h2
-rw-r--r--COFF/MapFile.cpp12
-rw-r--r--COFF/MarkLive.cpp7
-rw-r--r--COFF/MarkLive.h24
-rw-r--r--COFF/MinGW.cpp2
-rw-r--r--COFF/Options.td30
-rw-r--r--COFF/PDB.cpp577
-rw-r--r--COFF/PDB.h4
-rw-r--r--COFF/Strings.cpp35
-rw-r--r--COFF/SymbolTable.cpp96
-rw-r--r--COFF/SymbolTable.h6
-rw-r--r--COFF/Symbols.cpp8
-rw-r--r--COFF/Symbols.h11
-rw-r--r--COFF/Writer.cpp825
-rw-r--r--COFF/Writer.h16
-rw-r--r--Common/Args.cpp18
-rw-r--r--Common/CMakeLists.txt1
-rw-r--r--Common/ErrorHandler.cpp27
-rw-r--r--Common/Strings.cpp77
-rw-r--r--Common/TargetOptionsCommandFlags.cpp8
-rw-r--r--Common/Timer.cpp80
-rw-r--r--ELF/AArch64ErrataFix.cpp17
-rw-r--r--ELF/AArch64ErrataFix.h1
-rw-r--r--ELF/Arch/AArch64.cpp57
-rw-r--r--ELF/Arch/AMDGPU.cpp2
-rw-r--r--ELF/Arch/ARM.cpp30
-rw-r--r--ELF/Arch/Hexagon.cpp97
-rw-r--r--ELF/Arch/Mips.cpp175
-rw-r--r--ELF/Arch/MipsArchTree.cpp37
-rw-r--r--ELF/Arch/PPC.cpp7
-rw-r--r--ELF/Arch/PPC64.cpp423
-rw-r--r--ELF/Arch/SPARCV9.cpp12
-rw-r--r--ELF/Arch/X86.cpp168
-rw-r--r--ELF/Arch/X86_64.cpp215
-rw-r--r--ELF/CMakeLists.txt4
-rw-r--r--ELF/CallGraphSort.cpp249
-rw-r--r--ELF/CallGraphSort.h23
-rw-r--r--ELF/Config.h55
-rw-r--r--ELF/Driver.cpp590
-rw-r--r--ELF/Driver.h6
-rw-r--r--ELF/DriverUtils.cpp55
-rw-r--r--ELF/EhFrame.cpp8
-rw-r--r--ELF/Filesystem.cpp2
-rw-r--r--ELF/GdbIndex.cpp2
-rw-r--r--ELF/GdbIndex.h1
-rw-r--r--ELF/ICF.cpp116
-rw-r--r--ELF/ICF.h4
-rw-r--r--ELF/InputFiles.cpp608
-rw-r--r--ELF/InputFiles.h83
-rw-r--r--ELF/InputSection.cpp477
-rw-r--r--ELF/InputSection.h65
-rw-r--r--ELF/LTO.cpp214
-rw-r--r--ELF/LTO.h6
-rw-r--r--ELF/LinkerScript.cpp413
-rw-r--r--ELF/LinkerScript.h63
-rw-r--r--ELF/MapFile.cpp213
-rw-r--r--ELF/MapFile.h1
-rw-r--r--ELF/MarkLive.cpp38
-rw-r--r--ELF/MarkLive.h21
-rw-r--r--ELF/Options.td520
-rw-r--r--ELF/OutputSections.cpp90
-rw-r--r--ELF/OutputSections.h19
-rw-r--r--ELF/Relocations.cpp812
-rw-r--r--ELF/Relocations.h21
-rw-r--r--ELF/ScriptLexer.cpp10
-rw-r--r--ELF/ScriptParser.cpp304
-rw-r--r--ELF/Strings.cpp62
-rw-r--r--ELF/Strings.h75
-rw-r--r--ELF/SymbolTable.cpp300
-rw-r--r--ELF/SymbolTable.h11
-rw-r--r--ELF/Symbols.cpp95
-rw-r--r--ELF/Symbols.h159
-rw-r--r--ELF/SyntheticSections.cpp1475
-rw-r--r--ELF/SyntheticSections.h335
-rw-r--r--ELF/Target.cpp28
-rw-r--r--ELF/Target.h113
-rw-r--r--ELF/Thunks.cpp390
-rw-r--r--ELF/Thunks.h20
-rw-r--r--ELF/Writer.cpp754
-rw-r--r--ELF/Writer.h5
-rw-r--r--LICENSE.TXT2
-rw-r--r--MinGW/Driver.cpp15
-rw-r--r--MinGW/Options.td9
-rw-r--r--cmake/modules/AddLLD.cmake2
-rw-r--r--docs/ReleaseNotes.rst10
-rw-r--r--docs/WebAssembly.rst2
-rw-r--r--docs/conf.py4
-rw-r--r--docs/ld.lld.1547
-rw-r--r--docs/windows_support.rst5
-rw-r--r--include/lld/Common/Driver.h2
-rw-r--r--include/lld/Common/ErrorHandler.h70
-rw-r--r--include/lld/Common/Strings.h26
-rw-r--r--include/lld/Common/TargetOptionsCommandFlags.h1
-rw-r--r--include/lld/Common/Timer.h59
-rw-r--r--include/lld/Common/Version.h2
-rw-r--r--include/lld/Core/DefinedAtom.h44
-rw-r--r--include/lld/Core/File.h24
-rw-r--r--include/lld/Core/Instrumentation.h14
-rw-r--r--include/lld/Core/LinkingContext.h9
-rw-r--r--include/lld/Core/PassManager.h4
-rw-r--r--include/lld/Core/Reader.h6
-rw-r--r--include/lld/Core/Resolver.h6
-rw-r--r--include/lld/Core/Simple.h2
-rw-r--r--include/lld/Core/SymbolTable.h22
-rw-r--r--include/lld/Core/TODO.txt3
-rw-r--r--include/lld/Core/Writer.h6
-rw-r--r--include/lld/ReaderWriter/MachOLinkingContext.h28
-rw-r--r--lib/Core/LinkingContext.cpp4
-rw-r--r--lib/Driver/CMakeLists.txt1
-rw-r--r--lib/Driver/DarwinLdDriver.cpp312
-rw-r--r--lib/Driver/DarwinLdOptions.td8
-rw-r--r--lib/ReaderWriter/FileArchive.cpp6
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp4
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt1
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp43
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp31
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp14
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp6
-rw-r--r--test/CMakeLists.txt12
-rw-r--r--test/COFF/Inputs/far-arm64-abs.s6
-rw-r--r--test/COFF/Inputs/generic.yaml282
-rw-r--r--test/COFF/Inputs/globals-dia-func-collision3.objbin0 -> 5392 bytes
-rw-r--r--test/COFF/Inputs/globals-dia-vfunc-collision.objbin0 -> 8794 bytes
-rw-r--r--test/COFF/Inputs/globals-dia-vfunc-collision2.objbin0 -> 3660 bytes
-rw-r--r--test/COFF/Inputs/globals-dia-vfunc-simple.objbin0 -> 4575 bytes
-rw-r--r--test/COFF/Inputs/guardcf-align-foobar.yaml51
-rw-r--r--test/COFF/Inputs/loadconfig-cfg-x64.s11
-rw-r--r--test/COFF/Inputs/natvis-1.natvis1
-rw-r--r--test/COFF/Inputs/natvis-2.natvis1
-rw-r--r--test/COFF/Inputs/natvis-3.natvis1
-rw-r--r--test/COFF/Inputs/order.yaml76
-rw-r--r--test/COFF/Inputs/otherFunc.s7
-rw-r--r--test/COFF/Inputs/pdb-file-statics-a.yaml1866
-rw-r--r--test/COFF/Inputs/pdb-file-statics-b.yaml1552
-rw-r--r--test/COFF/Inputs/pdb-globals.yaml10
-rw-r--r--test/COFF/Inputs/pdb-hashes-1.yaml224
-rw-r--r--test/COFF/Inputs/pdb-hashes-2-missing.yaml104
-rw-r--r--test/COFF/Inputs/pdb-hashes-2.yaml146
-rw-r--r--test/COFF/Inputs/pdb-scopes-a.yaml8
-rw-r--r--test/COFF/Inputs/pdb-scopes-b.yaml6
-rw-r--r--test/COFF/Inputs/pdb-type-server-simple-a.yaml2
-rw-r--r--test/COFF/Inputs/pdb-type-server-simple-b.yaml2
-rw-r--r--test/COFF/Inputs/pdb_lines_1_relative.yaml401
-rw-r--r--test/COFF/Inputs/pdb_lines_2_relative.yaml190
-rw-r--r--test/COFF/arm64-branch-range.test16
-rw-r--r--test/COFF/arm64-relocs-imports.test113
-rw-r--r--test/COFF/armnt-movt32t.test2
-rw-r--r--test/COFF/associative-comdat.s10
-rw-r--r--test/COFF/baserel.test16
-rw-r--r--test/COFF/combined-resources.test218
-rw-r--r--test/COFF/common-alignment.test20
-rw-r--r--test/COFF/common.test26
-rw-r--r--test/COFF/crt-chars.test32
-rw-r--r--test/COFF/ctors_dtors_priority.s8
-rw-r--r--test/COFF/debug-reloc.s58
-rw-r--r--test/COFF/def-export-stdcall.s39
-rw-r--r--test/COFF/default-alignment.test21
-rw-r--r--test/COFF/delayimports-armnt.yaml34
-rw-r--r--test/COFF/delayimports.test18
-rw-r--r--test/COFF/delayimports32.test60
-rw-r--r--test/COFF/dll.test3
-rw-r--r--test/COFF/dllexport-mingw.s2
-rw-r--r--test/COFF/dllexport.s58
-rw-r--r--test/COFF/driver.test11
-rw-r--r--test/COFF/duplicate.test1
-rw-r--r--test/COFF/entry-inference3.test35
-rw-r--r--test/COFF/error-limit.test14
-rw-r--r--test/COFF/export-all.s2
-rw-r--r--test/COFF/export-armnt.yaml8
-rw-r--r--test/COFF/export.test4
-rw-r--r--test/COFF/export32.test10
-rw-r--r--test/COFF/filename-casing.s6
-rw-r--r--test/COFF/fixed.test24
-rw-r--r--test/COFF/force.test6
-rw-r--r--test/COFF/gfids-corrupt.s84
-rw-r--r--test/COFF/gfids-fallback.s97
-rw-r--r--test/COFF/gfids-gc.s131
-rw-r--r--test/COFF/gfids-icf.s88
-rw-r--r--test/COFF/guard-longjmp.s104
-rw-r--r--test/COFF/guardcf-align.s45
-rw-r--r--test/COFF/guardcf-lto.ll40
-rw-r--r--test/COFF/hello32.test28
-rw-r--r--test/COFF/icf-different-align.test13
-rw-r--r--test/COFF/icf-executable.s1
-rw-r--r--test/COFF/icf-pdata.s98
-rw-r--r--test/COFF/icf-simple.test5
-rw-r--r--test/COFF/icf-vtables.s28
-rw-r--r--test/COFF/icf-xdata.s23
-rw-r--r--test/COFF/implib-name.test1
-rw-r--r--test/COFF/imports.test8
-rw-r--r--test/COFF/incremental.test100
-rw-r--r--test/COFF/invalid-section-number.test34
-rw-r--r--test/COFF/largeaddressaware.test2
-rw-r--r--test/COFF/loadcfg.ll3
-rw-r--r--test/COFF/loadcfg.test2
-rw-r--r--test/COFF/loadcfg32.test2
-rw-r--r--test/COFF/lto-chkstk.ll1
-rw-r--r--test/COFF/lto-comdat.ll16
-rw-r--r--test/COFF/lto-icf.ll27
-rw-r--r--test/COFF/lto-lazy-reference.ll1
-rw-r--r--test/COFF/lto-linker-opts.ll1
-rw-r--r--test/COFF/lto-new-symbol.ll1
-rw-r--r--test/COFF/lto-opt-level.ll1
-rw-r--r--test/COFF/lto-parallel.ll5
-rw-r--r--test/COFF/lto-reloc-model.ll1
-rw-r--r--test/COFF/lto.ll5
-rw-r--r--test/COFF/manifestinput-error.test2
-rw-r--r--test/COFF/manifestinput.test4
-rw-r--r--test/COFF/merge.test26
-rw-r--r--test/COFF/nodefaultlib.test3
-rw-r--r--test/COFF/opt.test24
-rw-r--r--test/COFF/options.test14
-rw-r--r--test/COFF/order-i386.test69
-rw-r--r--test/COFF/order.test136
-rw-r--r--test/COFF/output-chars.test109
-rw-r--r--test/COFF/pdata-arm64.yaml2
-rw-r--r--test/COFF/pdb-comdat.test10
-rw-r--r--test/COFF/pdb-diff.test215
-rw-r--r--test/COFF/pdb-exe-path-dots.test10
-rw-r--r--test/COFF/pdb-file-static.test51
-rw-r--r--test/COFF/pdb-global-gc.yaml1
-rw-r--r--test/COFF/pdb-global-hashes.test2
-rw-r--r--test/COFF/pdb-globals-dia-func-collision3.test81
-rw-r--r--test/COFF/pdb-globals-dia-vfunc-collision.test42
-rw-r--r--test/COFF/pdb-globals-dia-vfunc-collision2.test25
-rw-r--r--test/COFF/pdb-globals-dia-vfunc-simple.test26
-rw-r--r--test/COFF/pdb-globals.test12
-rw-r--r--test/COFF/pdb-heapsite.yaml2
-rw-r--r--test/COFF/pdb-lib.s6
-rw-r--r--test/COFF/pdb-linker-module.test5
-rw-r--r--test/COFF/pdb-natvis.test26
-rw-r--r--test/COFF/pdb-procid-remapping.test4
-rw-r--r--test/COFF/pdb-publics-import.test9
-rw-r--r--test/COFF/pdb-relative-source-lines.test45
-rw-r--r--test/COFF/pdb-same-name.test4
-rw-r--r--test/COFF/pdb-scopes.test14
-rw-r--r--test/COFF/pdb-source-lines.test26
-rw-r--r--test/COFF/pdb-symbol-types.yaml4
-rw-r--r--test/COFF/pdb-thunk.yaml12
-rw-r--r--test/COFF/pdb-type-server-missing.yaml7
-rw-r--r--test/COFF/pdb-type-server-simple.test6
-rw-r--r--test/COFF/pdb.test162
-rw-r--r--test/COFF/pending-comdat.s21
-rw-r--r--test/COFF/reloc-arm.test16
-rw-r--r--test/COFF/reloc-discarded-dwarf.s1
-rw-r--r--test/COFF/reloc-discarded-early.s1
-rw-r--r--test/COFF/reloc-discarded-early2.s1
-rw-r--r--test/COFF/reloc-discarded.s1
-rw-r--r--test/COFF/reloc-x64.test1
-rw-r--r--test/COFF/reloc-x86.test1
-rw-r--r--test/COFF/resource.test14
-rw-r--r--test/COFF/rsds.test16
-rw-r--r--test/COFF/safeseh-md.s1
-rw-r--r--test/COFF/safeseh-notable.s44
-rw-r--r--test/COFF/safeseh.s19
-rw-r--r--test/COFF/secidx-absolute.s11
-rw-r--r--test/COFF/secrel-absolute.s1
-rw-r--r--test/COFF/secrel-common.s23
-rw-r--r--test/COFF/section-order.test15
-rw-r--r--test/COFF/section-size.s2
-rw-r--r--test/COFF/section.test4
-rw-r--r--test/COFF/sort-debug.test15
-rw-r--r--test/COFF/string-tail-merge.s106
-rw-r--r--test/COFF/symtab-gc.s27
-rw-r--r--test/COFF/symtab.test18
-rw-r--r--test/COFF/thunk-replace.s15
-rw-r--r--test/COFF/timestamp.test18
-rw-r--r--test/COFF/undefined-symbol-cv.s62
-rw-r--r--test/COFF/undefined-symbol.s30
-rw-r--r--test/COFF/unwind.test42
-rw-r--r--test/COFF/weak-external.test2
-rw-r--r--test/COFF/weak-external2.test1
-rw-r--r--test/COFF/weak-external3.test2
-rw-r--r--test/COFF/wholearchive.s10
-rw-r--r--test/ELF/Inputs/amdgpu-kernel-2.obin408 -> 0 bytes
-rw-r--r--test/ELF/Inputs/arm-long-thunk-converge.lds4
-rw-r--r--test/ELF/Inputs/as-needed-lazy.s3
-rw-r--r--test/ELF/Inputs/comdat-discarded-reloc.s6
-rw-r--r--test/ELF/Inputs/compress-debug.s5
-rw-r--r--test/ELF/Inputs/conflict-debug.s21
-rw-r--r--test/ELF/Inputs/copy-rel-version.s11
-rw-r--r--test/ELF/Inputs/copy-relocation-zero-abs-addr.s7
-rw-r--r--test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s7
-rw-r--r--test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script3
-rw-r--r--test/ELF/Inputs/eh-frame-pcrel-overflow.s25
-rw-r--r--test/ELF/Inputs/exclude-libs.ll3
-rw-r--r--test/ELF/Inputs/exclude-libs.s2
-rw-r--r--test/ELF/Inputs/far-long-arm-abs.s13
-rw-r--r--test/ELF/Inputs/gdb-index.s8
-rw-r--r--test/ELF/Inputs/hexagon.s6
-rw-r--r--test/ELF/Inputs/hidden-shared-err.s2
-rw-r--r--test/ELF/Inputs/hidden-shared-err2.s1
-rw-r--r--test/ELF/Inputs/i386-pic-plt.s4
-rw-r--r--test/ELF/Inputs/icf-safe.s9
-rw-r--r--test/ELF/Inputs/map-file2.s2
-rw-r--r--test/ELF/Inputs/mips-64-got-load.s8
-rw-r--r--test/ELF/Inputs/mips-gp-dips-corrupt-ver.s14
-rwxr-xr-xtest/ELF/Inputs/mips-gp-dips-corrupt-ver.sobin0 -> 2160 bytes
-rw-r--r--test/ELF/Inputs/mips-mgot-1.s10
-rw-r--r--test/ELF/Inputs/mips-mgot-2.s17
-rw-r--r--test/ELF/Inputs/mips-micro-gp0-non-zero.obin0 -> 1344 bytes
-rw-r--r--test/ELF/Inputs/mips-n32-rels.obin1092 -> 0 bytes
-rw-r--r--test/ELF/Inputs/mips-n64-gp0-non-zero.obin0 -> 1128 bytes
-rw-r--r--test/ELF/Inputs/multiple-cu.s24
-rw-r--r--test/ELF/Inputs/ppc64-func-global-entry.s35
-rw-r--r--test/ELF/Inputs/ppc64-func-local-entry.s16
-rw-r--r--test/ELF/Inputs/ppc64-func.s14
-rw-r--r--test/ELF/Inputs/ppc64-tls.s20
-rw-r--r--test/ELF/Inputs/print-icf.s9
-rw-r--r--test/ELF/Inputs/protected-data-access.s7
-rw-r--r--test/ELF/Inputs/protected-function-access.s5
-rw-r--r--test/ELF/Inputs/shared-ppc64.s21
-rw-r--r--test/ELF/Inputs/shlib-undefined-ref.s4
-rw-r--r--test/ELF/Inputs/symbol-ordering-file-warnings1.s19
-rw-r--r--test/ELF/Inputs/symbol-ordering-file-warnings2.s6
-rw-r--r--test/ELF/Inputs/undef-bad-debug.s134
-rw-r--r--test/ELF/Inputs/undef-debug.s21
-rw-r--r--test/ELF/Inputs/undef-shared2.s2
-rw-r--r--test/ELF/Inputs/versiondef.s9
-rw-r--r--test/ELF/Inputs/weak-and-strong-undef.s1
-rw-r--r--test/ELF/Inputs/x86-64-split-stack-main.s16
-rw-r--r--test/ELF/Inputs/ztext.s (renamed from test/ELF/Inputs/ztext-text-notext.s)0
-rw-r--r--test/ELF/aarch64-call26-thunk.s2
-rw-r--r--test/ELF/aarch64-condb-reloc.s2
-rw-r--r--test/ELF/aarch64-copy.s4
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-address.s3
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-cli.s2
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-nopatch.s2
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-recognize.s205
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-thunk.s3
-rw-r--r--test/ELF/aarch64-data-relocs.s2
-rw-r--r--test/ELF/aarch64-fpic-abs16.s4
-rw-r--r--test/ELF/aarch64-fpic-add_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-adr_prel_lo21.s4
-rw-r--r--test/ELF/aarch64-fpic-adr_prel_pg_hi21.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-prel16.s4
-rw-r--r--test/ELF/aarch64-fpic-prel32.s4
-rw-r--r--test/ELF/aarch64-fpic-prel64.s4
-rw-r--r--test/ELF/aarch64-gnu-ifunc-nosym.s2
-rw-r--r--test/ELF/aarch64-gnu-ifunc-plt.s2
-rw-r--r--test/ELF/aarch64-gnu-ifunc.s2
-rw-r--r--test/ELF/aarch64-hi21-error.s4
-rw-r--r--test/ELF/aarch64-jump26-thunk.s2
-rw-r--r--test/ELF/aarch64-ldprel-lo19-invalid.s2
-rw-r--r--test/ELF/aarch64-lo12-alignment.s2
-rw-r--r--test/ELF/aarch64-lo21-error.s4
-rw-r--r--test/ELF/aarch64-load-alignment.s2
-rw-r--r--test/ELF/aarch64-relocs.s2
-rw-r--r--test/ELF/aarch64-thunk-pi.s58
-rw-r--r--test/ELF/aarch64-thunk-script.s2
-rw-r--r--test/ELF/aarch64-thunk-section-location.s2
-rw-r--r--test/ELF/aarch64-tls-gdle.s2
-rw-r--r--test/ELF/aarch64-tls-ie.s2
-rw-r--r--test/ELF/aarch64-tls-iele.s2
-rw-r--r--test/ELF/aarch64-tls-le.s2
-rw-r--r--test/ELF/aarch64-tlsld-ldst.s85
-rw-r--r--test/ELF/aarch64-tstbr14-reloc.s2
-rw-r--r--test/ELF/aarch64-undefined-weak.s2
-rw-r--r--test/ELF/abs-conflict.s2
-rw-r--r--test/ELF/allow-multiple-definition.s9
-rw-r--r--test/ELF/amdgpu-elf-flags-err.s9
-rw-r--r--test/ELF/amdgpu-elf-flags.s7
-rw-r--r--test/ELF/amdgpu-globals.s3
-rw-r--r--test/ELF/amdgpu-kernels.s3
-rw-r--r--test/ELF/amdgpu-relocs.s15
-rw-r--r--test/ELF/archive.s25
-rw-r--r--test/ELF/arm-attributes.s2
-rw-r--r--test/ELF/arm-bl-v6.s4
-rw-r--r--test/ELF/arm-blx-v4t.s4
-rw-r--r--test/ELF/arm-blx.s2
-rw-r--r--test/ELF/arm-branch-rangethunk.s53
-rw-r--r--test/ELF/arm-branch-undef-weak-plt-thunk.s2
-rw-r--r--test/ELF/arm-branch.s2
-rw-r--r--test/ELF/arm-copy.s6
-rw-r--r--test/ELF/arm-data-prel.s2
-rw-r--r--test/ELF/arm-data-relocs.s2
-rw-r--r--test/ELF/arm-eabi-version.s2
-rw-r--r--test/ELF/arm-execute-only.s40
-rw-r--r--test/ELF/arm-exidx-canunwind.s2
-rw-r--r--test/ELF/arm-exidx-dedup.s2
-rw-r--r--test/ELF/arm-exidx-discard.s14
-rw-r--r--test/ELF/arm-exidx-gc.s2
-rw-r--r--test/ELF/arm-exidx-order.s38
-rw-r--r--test/ELF/arm-exidx-output.s2
-rw-r--r--test/ELF/arm-exidx-relocatable.s2
-rw-r--r--test/ELF/arm-exidx-sentinel-norelocatable.s2
-rw-r--r--test/ELF/arm-exidx-sentinel-orphan.s4
-rw-r--r--test/ELF/arm-exidx-shared.s8
-rw-r--r--test/ELF/arm-gnu-ifunc-nosym.s2
-rw-r--r--test/ELF/arm-gnu-ifunc-plt.s2
-rw-r--r--test/ELF/arm-gnu-ifunc.s2
-rw-r--r--test/ELF/arm-gotoff.s2
-rw-r--r--test/ELF/arm-long-thunk-converge.s29
-rw-r--r--test/ELF/arm-mov-relocs.s2
-rw-r--r--test/ELF/arm-pie-relative.s2
-rw-r--r--test/ELF/arm-plt-reloc.s10
-rw-r--r--test/ELF/arm-sbrel32.s2
-rw-r--r--test/ELF/arm-static-defines.s2
-rw-r--r--test/ELF/arm-symbol-ordering-file.s32
-rw-r--r--test/ELF/arm-target1.s2
-rw-r--r--test/ELF/arm-target2.s14
-rw-r--r--test/ELF/arm-thumb-blx.s2
-rw-r--r--test/ELF/arm-thumb-branch-rangethunk.s2
-rw-r--r--test/ELF/arm-thumb-branch.s2
-rw-r--r--test/ELF/arm-thumb-condbranch-thunk.s24
-rw-r--r--test/ELF/arm-thumb-interwork-shared.s2
-rw-r--r--test/ELF/arm-thumb-interwork-thunk-range.s2
-rw-r--r--test/ELF/arm-thumb-interwork-thunk.s20
-rw-r--r--test/ELF/arm-thumb-mix-range-thunk-os.s22
-rw-r--r--test/ELF/arm-thumb-narrow-branch-check.s2
-rw-r--r--test/ELF/arm-thumb-no-undefined-thunk.s2
-rw-r--r--test/ELF/arm-thumb-plt-range-thunk-os.s110
-rw-r--r--test/ELF/arm-thumb-plt-reloc.s2
-rw-r--r--test/ELF/arm-thumb-range-thunk-os.s62
-rw-r--r--test/ELF/arm-thumb-thunk-empty-pass.s14
-rw-r--r--test/ELF/arm-thumb-thunk-symbols.s2
-rw-r--r--test/ELF/arm-thumb-undefined-weak.s2
-rw-r--r--test/ELF/arm-thunk-largesection.s22
-rw-r--r--test/ELF/arm-thunk-linkerscript-dotexpr.s2
-rw-r--r--test/ELF/arm-thunk-linkerscript-large.s4
-rw-r--r--test/ELF/arm-thunk-linkerscript-sort.s4
-rw-r--r--test/ELF/arm-thunk-linkerscript.s2
-rw-r--r--test/ELF/arm-thunk-multipass.s20
-rw-r--r--test/ELF/arm-thunk-nosuitable.s33
-rw-r--r--test/ELF/arm-thunk-section-too-large.s21
-rw-r--r--test/ELF/arm-thunk-toolargesection.s4
-rw-r--r--test/ELF/arm-tls-gd-nonpreemptible.s2
-rw-r--r--test/ELF/arm-tls-gd32.s2
-rw-r--r--test/ELF/arm-tls-ie32.s2
-rw-r--r--test/ELF/arm-tls-ldm32.s2
-rw-r--r--test/ELF/arm-tls-le32.s2
-rw-r--r--test/ELF/arm-tls-norelax-gd-ie.s2
-rw-r--r--test/ELF/arm-tls-norelax-gd-le.s2
-rw-r--r--test/ELF/arm-tls-norelax-ie-le.s2
-rw-r--r--test/ELF/arm-tls-norelax-ld-le.s2
-rw-r--r--test/ELF/arm-undefined-weak.s2
-rw-r--r--test/ELF/arm-use-r-output.s2
-rw-r--r--test/ELF/as-needed-lazy.s14
-rw-r--r--test/ELF/as-needed-weak.s22
-rw-r--r--test/ELF/as-needed.s2
-rw-r--r--test/ELF/auxiliary.s2
-rw-r--r--test/ELF/basic-aarch64.s2
-rw-r--r--test/ELF/basic-freebsd.s2
-rw-r--r--test/ELF/basic-mips.s5
-rw-r--r--test/ELF/basic-ppc.s12
-rw-r--r--test/ELF/basic-ppc64.s323
-rw-r--r--test/ELF/basic-sparcv9.s2
-rw-r--r--test/ELF/basic32.s2
-rw-r--r--test/ELF/basic64be.s273
-rw-r--r--test/ELF/bss.s2
-rw-r--r--test/ELF/bsymbolic-undef.s1
-rw-r--r--test/ELF/bsymbolic.s1
-rw-r--r--test/ELF/build-id.s2
-rw-r--r--test/ELF/cgprofile-bad-clusters.s70
-rw-r--r--test/ELF/cgprofile-err.s13
-rw-r--r--test/ELF/cgprofile-icf.s53
-rw-r--r--test/ELF/cgprofile-txt.s185
-rw-r--r--test/ELF/cgprofile-warn.s36
-rw-r--r--test/ELF/color-diagnostics.test3
-rw-r--r--test/ELF/combrelocs.s3
-rw-r--r--test/ELF/comdat-discarded-reloc.s17
-rw-r--r--test/ELF/comdat-linkonce.s1
-rw-r--r--test/ELF/comdat.s10
-rw-r--r--test/ELF/common.s2
-rw-r--r--test/ELF/compatible-section-types.s1
-rw-r--r--test/ELF/compress-debug-sections-reloc.s26
-rw-r--r--test/ELF/compressed-debug-conflict.s33
-rw-r--r--test/ELF/compressed-debug-input-err.s11
-rw-r--r--test/ELF/conflict-debug-variable-file-index.s103
-rw-r--r--test/ELF/conflict-debug-variable.s36
-rw-r--r--test/ELF/conflict-debug-variable2.s3
-rw-r--r--test/ELF/conflict-variable-linkage-name.s176
-rw-r--r--test/ELF/conflict.s2
-rw-r--r--test/ELF/copy-errors.s15
-rw-r--r--test/ELF/copy-in-shared.s4
-rw-r--r--test/ELF/copy-rel-corrupted.s5
-rw-r--r--test/ELF/copy-rel-pie-error.s7
-rw-r--r--test/ELF/copy-rel-pie.s7
-rw-r--r--test/ELF/copy-rel-version.s15
-rw-r--r--test/ELF/copy-relocation-zero-abs-addr.s44
-rw-r--r--test/ELF/copy-relocation-zero-nonabs-addr.s29
-rw-r--r--test/ELF/corrupted-version-reference.s4
-rw-r--r--test/ELF/cref.s33
-rw-r--r--test/ELF/ctors_dtors_priority.s2
-rw-r--r--test/ELF/defined-tls_get_addr.s3
-rw-r--r--test/ELF/defsym-reserved-syms.s30
-rw-r--r--test/ELF/discard-locals.s2
-rw-r--r--test/ELF/discard-merge-locals.s2
-rw-r--r--test/ELF/discard-none.s2
-rw-r--r--test/ELF/dont-export-hidden.s1
-rw-r--r--test/ELF/driver.test30
-rw-r--r--test/ELF/dt_flags.s15
-rw-r--r--test/ELF/duplicated-synthetic-sym.s22
-rw-r--r--test/ELF/dynamic-got-rela.s57
-rw-r--r--test/ELF/dynamic-got.s27
-rw-r--r--test/ELF/dynamic-linker.s24
-rw-r--r--test/ELF/dynamic-list-archive.s17
-rw-r--r--test/ELF/dynamic-list-extern.s12
-rw-r--r--test/ELF/dynamic-no-rosegment.s4
-rw-r--r--test/ELF/dynamic-reloc-in-ro.s4
-rw-r--r--test/ELF/dynamic-reloc-index.s1
-rw-r--r--test/ELF/dynamic-reloc-weak.s2
-rw-r--r--test/ELF/dynamic-reloc.s2
-rw-r--r--test/ELF/dynstr-no-rosegment.s2
-rw-r--r--test/ELF/edata-etext.s8
-rw-r--r--test/ELF/eh-frame-dyn-rel.s4
-rw-r--r--test/ELF/eh-frame-hdr-abs-fde.s3
-rw-r--r--test/ELF/eh-frame-hdr-augmentation.s2
-rw-r--r--test/ELF/eh-frame-hdr-icf-fde.s4
-rw-r--r--test/ELF/eh-frame-hdr.s7
-rw-r--r--test/ELF/eh-frame-marker.s1
-rw-r--r--test/ELF/eh-frame-merge.s3
-rw-r--r--test/ELF/eh-frame-multilpe-cie.s3
-rw-r--r--test/ELF/eh-frame-negative-pcrel-sdata2.s85
-rw-r--r--test/ELF/eh-frame-negative-pcrel-sdata4.s85
-rw-r--r--test/ELF/eh-frame-negative-pcrel-sdata8.s85
-rw-r--r--test/ELF/eh-frame-padding-no-rosegment.s8
-rw-r--r--test/ELF/eh-frame-pcrel-overflow.s33
-rw-r--r--test/ELF/eh-frame-rel.s2
-rw-r--r--test/ELF/eh-frame-value-format1.s35
-rw-r--r--test/ELF/eh-frame-value-format2.s35
-rw-r--r--test/ELF/eh-frame-value-format3.s28
-rw-r--r--test/ELF/eh-frame-value-format4.s28
-rw-r--r--test/ELF/eh-frame-value-format5.s35
-rw-r--r--test/ELF/eh-frame-value-format6.s35
-rw-r--r--test/ELF/eh-frame-value-format7.s75
-rw-r--r--test/ELF/eh-frame-value-format8.s74
-rw-r--r--test/ELF/eh-frame-value-format9.s28
-rw-r--r--test/ELF/ehframe-relocation.s2
-rw-r--r--test/ELF/elf-header.s18
-rw-r--r--test/ELF/emit-relocs-eh-frame.s16
-rw-r--r--test/ELF/emit-relocs-gc.s4
-rw-r--r--test/ELF/emit-relocs-icf.s33
-rw-r--r--test/ELF/emit-relocs-shared.s4
-rw-r--r--test/ELF/emit-relocs.s2
-rw-r--r--test/ELF/empty-archive.s3
-rw-r--r--test/ELF/empty-ver2.s20
-rw-r--r--test/ELF/emulation.s48
-rw-r--r--test/ELF/end-preserve.s2
-rw-r--r--test/ELF/end-update.s2
-rw-r--r--test/ELF/end.s2
-rw-r--r--test/ELF/entry.s1
-rw-r--r--test/ELF/exclude-libs.s13
-rw-r--r--test/ELF/executable-undefined-protected-ignoreall.s2
-rw-r--r--test/ELF/export-dynamic-symbol.s18
-rw-r--r--test/ELF/fatal-warnings.s4
-rw-r--r--test/ELF/file-sym.s12
-rw-r--r--test/ELF/fill-trap-ppc.s31
-rw-r--r--test/ELF/filter.s3
-rw-r--r--test/ELF/format-binary-non-ascii.s6
-rw-r--r--test/ELF/gc-absolute.s2
-rw-r--r--test/ELF/gc-debuginfo-tls.s1
-rw-r--r--test/ELF/gc-merge-local-sym.s3
-rw-r--r--test/ELF/gc-sections-local-sym.s2
-rw-r--r--test/ELF/gc-sections-merge-addend.s1
-rw-r--r--test/ELF/gc-sections-merge-implicit-addend.s1
-rw-r--r--test/ELF/gc-sections-merge.s1
-rw-r--r--test/ELF/gc-sections-metadata-startstop.s2
-rw-r--r--test/ELF/gc-sections-no-undef-error.s19
-rw-r--r--test/ELF/gc-sections-print.s4
-rw-r--r--test/ELF/gc-sections-protected.s1
-rw-r--r--test/ELF/gc-sections-shared.s80
-rw-r--r--test/ELF/gdb-index-dup-types.s60
-rw-r--r--test/ELF/gdb-index-noranges.s2
-rw-r--r--test/ELF/gdb-index-tls.s2
-rw-r--r--test/ELF/gdb-index.s56
-rw-r--r--test/ELF/global-offset-table-position-aarch64.s6
-rw-r--r--test/ELF/global-offset-table-position-arm.s2
-rw-r--r--test/ELF/global-offset-table-position-i386.s9
-rw-r--r--test/ELF/global-offset-table-position-mips.s3
-rw-r--r--test/ELF/global-offset-table-position.s9
-rw-r--r--test/ELF/global_offset_table.s3
-rw-r--r--test/ELF/global_offset_table_shared.s5
-rw-r--r--test/ELF/gnu-hash-table.s24
-rw-r--r--test/ELF/gnu-ifunc-dynsym.s6
-rw-r--r--test/ELF/gnu-ifunc-dyntags.s41
-rw-r--r--test/ELF/gnu-ifunc-i386.s2
-rw-r--r--test/ELF/gnu-ifunc-nosym-i386.s2
-rw-r--r--test/ELF/gnu-ifunc-nosym.s2
-rw-r--r--test/ELF/gnu-ifunc-plt-i386.s10
-rw-r--r--test/ELF/gnu-ifunc-plt.s2
-rw-r--r--test/ELF/gnu-ifunc-relative.s2
-rw-r--r--test/ELF/gnu-ifunc.s2
-rw-r--r--test/ELF/gnu-unique.s2
-rw-r--r--test/ELF/gnustack.s5
-rw-r--r--test/ELF/got-aarch64.s2
-rw-r--r--test/ELF/got-i386.s2
-rw-r--r--test/ELF/got-plt-header.s1
-rw-r--r--test/ELF/got.s2
-rw-r--r--test/ELF/got32-i386-pie-rw.s4
-rw-r--r--test/ELF/got32-i386.s2
-rw-r--r--test/ELF/got32x-i386.s10
-rw-r--r--test/ELF/gotpcrelx.s1
-rw-r--r--test/ELF/help.s4
-rw-r--r--test/ELF/hexagon.s24
-rw-r--r--test/ELF/hidden-shared-err.s19
-rw-r--r--test/ELF/i386-debug-noabs.test2
-rw-r--r--test/ELF/i386-got-and-copy.s1
-rw-r--r--test/ELF/i386-got-value.s1
-rw-r--r--test/ELF/i386-gotpc.s14
-rw-r--r--test/ELF/i386-merge.s7
-rw-r--r--test/ELF/i386-pic-plt.s12
-rw-r--r--test/ELF/i386-reloc-16-large-addend.s12
-rw-r--r--test/ELF/i386-reloc-16.s7
-rw-r--r--test/ELF/i386-reloc-8-large-addend.s12
-rw-r--r--test/ELF/i386-reloc-8.s7
-rw-r--r--test/ELF/i386-reloc-range.s2
-rw-r--r--test/ELF/i386-retpoline-nopic-linkerscript.s67
-rw-r--r--test/ELF/i386-retpoline-nopic.s65
-rw-r--r--test/ELF/i386-retpoline-pic-linkerscript.s64
-rw-r--r--test/ELF/i386-retpoline-pic.s62
-rw-r--r--test/ELF/i386-tls-got.s2
-rw-r--r--test/ELF/i386-tls-ie-shared.s1
-rw-r--r--test/ELF/icf-absolute.s6
-rw-r--r--test/ELF/icf-c-identifier.s9
-rw-r--r--test/ELF/icf-comdat.s6
-rw-r--r--test/ELF/icf-different-output-sections.s9
-rw-r--r--test/ELF/icf-i386.s8
-rw-r--r--test/ELF/icf-keep-unique.s43
-rw-r--r--test/ELF/icf-link-order.s18
-rw-r--r--test/ELF/icf-many-sections.s62
-rw-r--r--test/ELF/icf-merge-sec.s6
-rw-r--r--test/ELF/icf-merge.s12
-rw-r--r--test/ELF/icf-merge2.s23
-rw-r--r--test/ELF/icf-merged-sections.s37
-rw-r--r--test/ELF/icf-non-mergeable.s6
-rw-r--r--test/ELF/icf-none.s4
-rw-r--r--test/ELF/icf-relro.s13
-rw-r--r--test/ELF/icf-safe.s182
-rw-r--r--test/ELF/icf1.s6
-rw-r--r--test/ELF/icf10.test40
-rw-r--r--test/ELF/icf11.test52
-rw-r--r--test/ELF/icf12.s20
-rw-r--r--test/ELF/icf13.s20
-rw-r--r--test/ELF/icf14.s26
-rw-r--r--test/ELF/icf15.s23
-rw-r--r--test/ELF/icf16.s23
-rw-r--r--test/ELF/icf2.s6
-rw-r--r--test/ELF/icf3.s6
-rw-r--r--test/ELF/icf4.s6
-rw-r--r--test/ELF/icf5.s6
-rw-r--r--test/ELF/icf6.s6
-rw-r--r--test/ELF/icf7.s6
-rw-r--r--test/ELF/icf9.s13
-rw-r--r--test/ELF/ignore-plugin.test2
-rw-r--r--test/ELF/incompatible-ar-first.s4
-rw-r--r--test/ELF/incompatible-section-flags.s3
-rw-r--r--test/ELF/incompatible-section-types2.s3
-rw-r--r--test/ELF/incompatible.s4
-rw-r--r--test/ELF/init_fini_priority.s2
-rw-r--r--test/ELF/invalid-cie-length.s2
-rw-r--r--test/ELF/invalid-cie-length2.s2
-rw-r--r--test/ELF/invalid-cie-length3.s2
-rw-r--r--test/ELF/invalid-cie-length4.s2
-rw-r--r--test/ELF/invalid-cie-length5.s2
-rw-r--r--test/ELF/invalid-cie-reference.s2
-rw-r--r--test/ELF/invalid-eh-frame.s17
-rw-r--r--test/ELF/invalid-eh-frame2.s22
-rw-r--r--test/ELF/invalid-eh-frame3.s21
-rw-r--r--test/ELF/invalid-eh-frame4.s28
-rw-r--r--test/ELF/invalid-eh-frame5.s28
-rw-r--r--test/ELF/invalid-eh-frame6.s31
-rw-r--r--test/ELF/invalid-eh-frame7.s30
-rw-r--r--test/ELF/invalid-eh-frame8.s30
-rw-r--r--test/ELF/invalid-eh-frame9.s15
-rw-r--r--test/ELF/invalid-fde-rel.s2
-rw-r--r--test/ELF/invalid-relocations.test2
-rw-r--r--test/ELF/invalid-undef-section-symbol.test2
-rw-r--r--test/ELF/invalid-z.s9
-rw-r--r--test/ELF/invalid/Inputs/cie-version2.elfbin1128 -> 0 bytes
-rw-r--r--test/ELF/invalid/Inputs/too-short.elfbin44 -> 0 bytes
-rw-r--r--test/ELF/invalid/dynamic-section-size.s2
-rw-r--r--test/ELF/invalid/eh-frame-hdr-no-out.s21
-rw-r--r--test/ELF/invalid/executable.s9
-rw-r--r--test/ELF/invalid/invalid-e_shnum.s2
-rw-r--r--test/ELF/invalid/invalid-elf.test1
-rw-r--r--test/ELF/invalid/merge-invalid-size.s4
-rw-r--r--test/ELF/invalid/mips-invalid-options-descriptor.s2
-rw-r--r--test/ELF/invalid/reloc-section-reordered.test30
-rw-r--r--test/ELF/invalid/section-alignment2.s2
-rw-r--r--test/ELF/invalid/sht-group.s2
-rw-r--r--test/ELF/invalid/symbol-index.s2
-rw-r--r--test/ELF/invalid/symbol-name.s2
-rw-r--r--test/ELF/invalid/tls-symbol.s2
-rw-r--r--test/ELF/invalid/too-short.s5
-rw-r--r--test/ELF/just-symbols-cref.s20
-rw-r--r--test/ELF/just-symbols.s20
-rw-r--r--test/ELF/libsearch.s2
-rw-r--r--test/ELF/linkerscript/Inputs/addr.s12
-rw-r--r--test/ELF/linkerscript/Inputs/align.s13
-rw-r--r--test/ELF/linkerscript/Inputs/alignof.s15
-rw-r--r--test/ELF/linkerscript/Inputs/at2.s14
-rw-r--r--test/ELF/linkerscript/Inputs/at3.s8
-rw-r--r--test/ELF/linkerscript/Inputs/data-commands.s35
-rw-r--r--test/ELF/linkerscript/Inputs/data-segment-relro.s11
-rw-r--r--test/ELF/linkerscript/Inputs/define.s8
-rw-r--r--test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s11
-rw-r--r--test/ELF/linkerscript/Inputs/extend-pt-load.s3
-rw-r--r--test/ELF/linkerscript/Inputs/fill.s11
-rw-r--r--test/ELF/linkerscript/Inputs/implicit-program-header.script12
-rw-r--r--test/ELF/linkerscript/Inputs/insert-after.s11
-rw-r--r--test/ELF/linkerscript/Inputs/insert-after.script4
-rw-r--r--test/ELF/linkerscript/Inputs/map-file2.s19
-rw-r--r--test/ELF/linkerscript/Inputs/provide-shared2.s3
-rw-r--r--test/ELF/linkerscript/Inputs/sections-va-overflow.s6
-rw-r--r--test/ELF/linkerscript/Inputs/synthetic-symbols.s16
-rw-r--r--test/ELF/linkerscript/absolute-expr.test (renamed from test/ELF/linkerscript/absolute-expr.s)28
-rw-r--r--test/ELF/linkerscript/addr-zero.test (renamed from test/ELF/linkerscript/addr-zero.s)11
-rw-r--r--test/ELF/linkerscript/addr.s32
-rw-r--r--test/ELF/linkerscript/addr.test20
-rw-r--r--test/ELF/linkerscript/address-expr-symbols.s15
-rw-r--r--test/ELF/linkerscript/align-empty.s18
-rw-r--r--test/ELF/linkerscript/align-empty.test22
-rw-r--r--test/ELF/linkerscript/align-r.test21
-rw-r--r--test/ELF/linkerscript/align-section-offset.s11
-rw-r--r--test/ELF/linkerscript/align-section-offset.test12
-rw-r--r--test/ELF/linkerscript/align-section.s6
-rw-r--r--test/ELF/linkerscript/align-section.test7
-rw-r--r--test/ELF/linkerscript/align.s125
-rw-r--r--test/ELF/linkerscript/align1.test44
-rw-r--r--test/ELF/linkerscript/align2.test20
-rw-r--r--test/ELF/linkerscript/align3.test18
-rw-r--r--test/ELF/linkerscript/align4.test25
-rw-r--r--test/ELF/linkerscript/align5.test23
-rw-r--r--test/ELF/linkerscript/alignof.s41
-rw-r--r--test/ELF/linkerscript/alignof.test24
-rw-r--r--test/ELF/linkerscript/arm-exidx-order.s19
-rw-r--r--test/ELF/linkerscript/arm-exidx-order.test19
-rw-r--r--test/ELF/linkerscript/arm-exidx-phdrs.s16
-rw-r--r--test/ELF/linkerscript/arm-exidx-phdrs.test13
-rw-r--r--test/ELF/linkerscript/arm-lscript.s9
-rw-r--r--test/ELF/linkerscript/arm-lscript.test11
-rw-r--r--test/ELF/linkerscript/assert.s9
-rw-r--r--test/ELF/linkerscript/at-self-reference.s63
-rw-r--r--test/ELF/linkerscript/at2.test58
-rw-r--r--test/ELF/linkerscript/at3.test31
-rw-r--r--test/ELF/linkerscript/at4.s36
-rw-r--r--test/ELF/linkerscript/at5.test14
-rw-r--r--test/ELF/linkerscript/broken-memory-declaration.s13
-rw-r--r--test/ELF/linkerscript/bss-fill.s7
-rw-r--r--test/ELF/linkerscript/bss-fill.test13
-rw-r--r--test/ELF/linkerscript/common-filespec.test (renamed from test/ELF/linkerscript/common-filespec.s)19
-rw-r--r--test/ELF/linkerscript/compress-debug-sections-custom.s35
-rw-r--r--test/ELF/linkerscript/constructor.test (renamed from test/ELF/linkerscript/constructor.s)14
-rw-r--r--test/ELF/linkerscript/copy-rel-symbol-value-err.s2
-rw-r--r--test/ELF/linkerscript/data-commands-gc.s2
-rw-r--r--test/ELF/linkerscript/data-commands.s117
-rw-r--r--test/ELF/linkerscript/data-commands1.test45
-rw-r--r--test/ELF/linkerscript/data-commands2.test40
-rw-r--r--test/ELF/linkerscript/data-segment-relro.test (renamed from test/ELF/linkerscript/data-segment-relro.s)54
-rw-r--r--test/ELF/linkerscript/define.s25
-rw-r--r--test/ELF/linkerscript/define.test15
-rw-r--r--test/ELF/linkerscript/defsym.s19
-rw-r--r--test/ELF/linkerscript/diag1.test15
-rw-r--r--test/ELF/linkerscript/diag2.test13
-rw-r--r--test/ELF/linkerscript/diag3.test13
-rw-r--r--test/ELF/linkerscript/diag4.test14
-rw-r--r--test/ELF/linkerscript/diag5.test14
-rw-r--r--test/ELF/linkerscript/diag6.test7
-rw-r--r--test/ELF/linkerscript/diagnostic.s106
-rw-r--r--test/ELF/linkerscript/discard-gnu-hash.s23
-rw-r--r--test/ELF/linkerscript/discard-interp.s12
-rw-r--r--test/ELF/linkerscript/discard-interp.test14
-rw-r--r--test/ELF/linkerscript/discard-print-gc.s4
-rw-r--r--test/ELF/linkerscript/discard-section-err.s10
-rw-r--r--test/ELF/linkerscript/dot-is-not-abs.s4
-rw-r--r--test/ELF/linkerscript/double-bss.s21
-rw-r--r--test/ELF/linkerscript/double-bss.test14
-rw-r--r--test/ELF/linkerscript/edata-etext.s2
-rw-r--r--test/ELF/linkerscript/eh-frame-emit-relocs.s13
-rw-r--r--test/ELF/linkerscript/eh-frame-hdr.s7
-rw-r--r--test/ELF/linkerscript/eh-frame-reloc-out-of-range.s27
-rw-r--r--test/ELF/linkerscript/eh-frame-reloc-out-of-range.test13
-rw-r--r--test/ELF/linkerscript/eh-frame.s4
-rw-r--r--test/ELF/linkerscript/emit-reloc-section-names.s3
-rw-r--r--test/ELF/linkerscript/emit-reloc.s4
-rw-r--r--test/ELF/linkerscript/empty-link-order.test21
-rw-r--r--test/ELF/linkerscript/empty-load.s2
-rw-r--r--test/ELF/linkerscript/empty-section-size.test17
-rw-r--r--test/ELF/linkerscript/empty-sections-expressions.s18
-rw-r--r--test/ELF/linkerscript/empty-synthetic-removed-flags.s36
-rw-r--r--test/ELF/linkerscript/empty-tls.s14
-rw-r--r--test/ELF/linkerscript/empty-tls.test17
-rw-r--r--test/ELF/linkerscript/exidx-crash.s7
-rw-r--r--test/ELF/linkerscript/exidx-crash.test10
-rw-r--r--test/ELF/linkerscript/expr-invalid-sec.s6
-rw-r--r--test/ELF/linkerscript/expr-invalid-sec.test9
-rw-r--r--test/ELF/linkerscript/expr-sections.s22
-rw-r--r--test/ELF/linkerscript/expr-sections.test23
-rw-r--r--test/ELF/linkerscript/extend-pt-load.s68
-rw-r--r--test/ELF/linkerscript/extend-pt-load1.test23
-rw-r--r--test/ELF/linkerscript/extend-pt-load2.test24
-rw-r--r--test/ELF/linkerscript/extend-pt-load3.test24
-rw-r--r--test/ELF/linkerscript/filename-spec.s70
-rw-r--r--test/ELF/linkerscript/fill.s31
-rw-r--r--test/ELF/linkerscript/fill.test20
-rw-r--r--test/ELF/linkerscript/header-addr.test (renamed from test/ELF/linkerscript/header-addr.s)18
-rw-r--r--test/ELF/linkerscript/header-phdr.s13
-rw-r--r--test/ELF/linkerscript/header-phdr.test15
-rw-r--r--test/ELF/linkerscript/header-phdr2.s11
-rw-r--r--test/ELF/linkerscript/huge-temporary-file.s2
-rw-r--r--test/ELF/linkerscript/i386-sections-max-va-overflow.s13
-rw-r--r--test/ELF/linkerscript/implicit-program-header.s13
-rw-r--r--test/ELF/linkerscript/implicit-program-header.test22
-rw-r--r--test/ELF/linkerscript/info-section-type.s33
-rw-r--r--test/ELF/linkerscript/insert-after.test29
-rw-r--r--test/ELF/linkerscript/insert-before.test29
-rw-r--r--test/ELF/linkerscript/insert-broken.test6
-rw-r--r--test/ELF/linkerscript/lazy-symbols.test (renamed from test/ELF/linkerscript/lazy-symbols.s)7
-rw-r--r--test/ELF/linkerscript/linker-script-in-search-path.s10
-rw-r--r--test/ELF/linkerscript/linkerscript.s12
-rw-r--r--test/ELF/linkerscript/lma-overflow.test16
-rw-r--r--test/ELF/linkerscript/locationcountererr.s11
-rw-r--r--test/ELF/linkerscript/locationcountererr.test11
-rw-r--r--test/ELF/linkerscript/locationcountererr2.s6
-rw-r--r--test/ELF/linkerscript/map-file.test60
-rw-r--r--test/ELF/linkerscript/map-file2.test44
-rw-r--r--test/ELF/linkerscript/memory-at.test (renamed from test/ELF/linkerscript/memory-at.s)31
-rw-r--r--test/ELF/linkerscript/memory-data-commands.test22
-rw-r--r--test/ELF/linkerscript/memory-loc-counter.test37
-rw-r--r--test/ELF/linkerscript/memory-region-alignment.test58
-rw-r--r--test/ELF/linkerscript/memory.s6
-rw-r--r--test/ELF/linkerscript/memory2.s2
-rw-r--r--test/ELF/linkerscript/memory4.test19
-rw-r--r--test/ELF/linkerscript/memory5.test19
-rw-r--r--test/ELF/linkerscript/merge-header-load.s21
-rw-r--r--test/ELF/linkerscript/merge-sections-syms.s4
-rw-r--r--test/ELF/linkerscript/merge-sections.s3
-rw-r--r--test/ELF/linkerscript/no-pt-load.s5
-rw-r--r--test/ELF/linkerscript/no-pt-load.test11
-rw-r--r--test/ELF/linkerscript/no-space.s10
-rw-r--r--test/ELF/linkerscript/nobits-offset.s18
-rw-r--r--test/ELF/linkerscript/noload.s29
-rw-r--r--test/ELF/linkerscript/non-absolute.s6
-rw-r--r--test/ELF/linkerscript/non-absolute2.s12
-rw-r--r--test/ELF/linkerscript/non-absolute2.test17
-rw-r--r--test/ELF/linkerscript/non-alloc-segment.s2
-rw-r--r--test/ELF/linkerscript/non-alloc.s8
-rw-r--r--test/ELF/linkerscript/numbers.s23
-rw-r--r--test/ELF/linkerscript/openbsd-bootdata.s7
-rw-r--r--test/ELF/linkerscript/openbsd-bootdata.test9
-rw-r--r--test/ELF/linkerscript/openbsd-randomize.s1
-rw-r--r--test/ELF/linkerscript/openbsd-wxneeded.test (renamed from test/ELF/linkerscript/openbsd-wxneeded.s)8
-rw-r--r--test/ELF/linkerscript/operators.test (renamed from test/ELF/linkerscript/operators.s)105
-rw-r--r--test/ELF/linkerscript/orphan-first-cmd.s20
-rw-r--r--test/ELF/linkerscript/orphan-first-cmd.test20
-rw-r--r--test/ELF/linkerscript/orphan-phdrs.s3
-rw-r--r--test/ELF/linkerscript/orphan.s2
-rw-r--r--test/ELF/linkerscript/out-of-order.s30
-rw-r--r--test/ELF/linkerscript/output-too-large.s2
-rw-r--r--test/ELF/linkerscript/outputarch.s4
-rw-r--r--test/ELF/linkerscript/outputarch.test5
-rw-r--r--test/ELF/linkerscript/overlapping-sections.s113
-rw-r--r--test/ELF/linkerscript/overlay-reject.test13
-rw-r--r--test/ELF/linkerscript/overlay-reject2.test17
-rw-r--r--test/ELF/linkerscript/overlay.test30
-rw-r--r--test/ELF/linkerscript/page-size-align.s22
-rw-r--r--test/ELF/linkerscript/page-size-align.test21
-rw-r--r--test/ELF/linkerscript/parse-section-in-addr.test10
-rw-r--r--test/ELF/linkerscript/provide-empty-section.s30
-rw-r--r--test/ELF/linkerscript/provide-shared2.s13
-rw-r--r--test/ELF/linkerscript/pt-interp.test21
-rw-r--r--test/ELF/linkerscript/pt_gnu_eh_frame.s2
-rw-r--r--test/ELF/linkerscript/region-alias.s4
-rw-r--r--test/ELF/linkerscript/rosegment.test (renamed from test/ELF/linkerscript/rosegment.s)8
-rw-r--r--test/ELF/linkerscript/section-metadata.s8
-rw-r--r--test/ELF/linkerscript/section-metadata2.s37
-rw-r--r--test/ELF/linkerscript/sections-keep.s36
-rw-r--r--test/ELF/linkerscript/sections-max-va-overflow.s13
-rw-r--r--test/ELF/linkerscript/sections-sort.s10
-rw-r--r--test/ELF/linkerscript/sections-va-overflow.test22
-rw-r--r--test/ELF/linkerscript/sections.s8
-rw-r--r--test/ELF/linkerscript/segment-none.s4
-rw-r--r--test/ELF/linkerscript/segment-start.s2
-rw-r--r--test/ELF/linkerscript/sort-constructors.s5
-rw-r--r--test/ELF/linkerscript/sort-constructors.test8
-rw-r--r--test/ELF/linkerscript/sort-non-script.s10
-rw-r--r--test/ELF/linkerscript/start-end.s16
-rw-r--r--test/ELF/linkerscript/start-end.test12
-rw-r--r--test/ELF/linkerscript/subalign.s2
-rw-r--r--test/ELF/linkerscript/symbol-assignexpr.s2
-rw-r--r--test/ELF/linkerscript/symbol-memoryexpr.s2
-rw-r--r--test/ELF/linkerscript/symbol-only-flags.test (renamed from test/ELF/linkerscript/symbol-only-flags.s)17
-rw-r--r--test/ELF/linkerscript/symbol-only.s21
-rw-r--r--test/ELF/linkerscript/symbol-only.test21
-rw-r--r--test/ELF/linkerscript/symbol-ordering-file.s10
-rw-r--r--test/ELF/linkerscript/symbol-ordering-file2.s16
-rw-r--r--test/ELF/linkerscript/symbols-non-alloc.s19
-rw-r--r--test/ELF/linkerscript/symbols-non-alloc.test18
-rw-r--r--test/ELF/linkerscript/symbols-synthetic.s98
-rw-r--r--test/ELF/linkerscript/synthetic-relsec-layout.s16
-rw-r--r--test/ELF/linkerscript/synthetic-symbols1.test56
-rw-r--r--test/ELF/linkerscript/synthetic-symbols2.test13
-rw-r--r--test/ELF/linkerscript/synthetic-symbols3.test11
-rw-r--r--test/ELF/linkerscript/synthetic-symbols4.test14
-rw-r--r--test/ELF/linkerscript/unused-synthetic.s6
-rw-r--r--test/ELF/linkerscript/unused-synthetic2.test12
-rw-r--r--test/ELF/linkerscript/va.s8
-rw-r--r--test/ELF/linkerscript/version-script.s57
-rw-r--r--test/ELF/llvm33-rela-outside-group.s2
-rw-r--r--test/ELF/local-dynamic.s2
-rw-r--r--test/ELF/local-got-pie.s1
-rw-r--r--test/ELF/local-got-shared.s1
-rw-r--r--test/ELF/local-got.s1
-rw-r--r--test/ELF/local-symbols-order.s37
-rw-r--r--test/ELF/local.s2
-rw-r--r--test/ELF/lto-plugin-ignore.s9
-rw-r--r--test/ELF/lto/Inputs/absolute.s2
-rw-r--r--test/ELF/lto/Inputs/archive-3.ll1
-rw-r--r--test/ELF/lto/Inputs/asmundef.ll4
-rw-r--r--test/ELF/lto/Inputs/common3.ll1
-rw-r--r--test/ELF/lto/Inputs/i386-empty.ll2
-rw-r--r--test/ELF/lto/Inputs/lazy-internal.ll6
-rw-r--r--test/ELF/lto/Inputs/sample-profile.prof1
-rw-r--r--test/ELF/lto/Inputs/thinlto_empty.ll2
-rw-r--r--test/ELF/lto/Inputs/weakodr-visibility.ll6
-rw-r--r--test/ELF/lto/abs-resol.ll17
-rw-r--r--test/ELF/lto/archive-2.ll4
-rw-r--r--test/ELF/lto/archive-3.ll4
-rw-r--r--test/ELF/lto/archive-no-index.ll4
-rw-r--r--test/ELF/lto/archive.ll4
-rw-r--r--test/ELF/lto/asmundef.ll5
-rw-r--r--test/ELF/lto/available-externally.ll2
-rw-r--r--test/ELF/lto/bitcode-nodatalayout.ll2
-rw-r--r--test/ELF/lto/cache.ll2
-rw-r--r--test/ELF/lto/codemodel.ll4
-rw-r--r--test/ELF/lto/combined-lto-object-name.ll2
-rw-r--r--test/ELF/lto/comdat.ll2
-rw-r--r--test/ELF/lto/comdat2.ll4
-rw-r--r--test/ELF/lto/common2.ll2
-rw-r--r--test/ELF/lto/common3.ll2
-rw-r--r--test/ELF/lto/cpu-string.ll25
-rw-r--r--test/ELF/lto/ctors.ll2
-rw-r--r--test/ELF/lto/data-ordering-lto.s13
-rw-r--r--test/ELF/lto/debugger-tune.ll35
-rw-r--r--test/ELF/lto/defsym.ll10
-rw-r--r--test/ELF/lto/discard-value-names.ll2
-rw-r--r--test/ELF/lto/drop-debug-info.ll4
-rw-r--r--test/ELF/lto/drop-linkage.ll6
-rw-r--r--test/ELF/lto/duplicated.ll2
-rw-r--r--test/ELF/lto/dynamic-list.ll2
-rw-r--r--test/ELF/lto/dynsym.ll6
-rw-r--r--test/ELF/lto/inline-asm.ll2
-rw-r--r--test/ELF/lto/internalize-basic.ll4
-rw-r--r--test/ELF/lto/internalize-exportdyn.ll10
-rw-r--r--test/ELF/lto/internalize-llvmused.ll2
-rw-r--r--test/ELF/lto/internalize-undef.ll2
-rw-r--r--test/ELF/lto/internalize-version-script.ll2
-rw-r--r--test/ELF/lto/irmover-error.ll2
-rw-r--r--test/ELF/lto/keep-undefined.ll2
-rw-r--r--test/ELF/lto/lazy-internal.ll19
-rw-r--r--test/ELF/lto/linkage.ll2
-rw-r--r--test/ELF/lto/linker-script-symbols-assign.ll15
-rw-r--r--test/ELF/lto/linker-script-symbols-ipo.ll8
-rw-r--r--test/ELF/lto/linker-script-symbols.ll2
-rw-r--r--test/ELF/lto/lto-start.ll2
-rw-r--r--test/ELF/lto/ltopasses-basic.ll2
-rw-r--r--test/ELF/lto/ltopasses-custom.ll4
-rw-r--r--test/ELF/lto/metadata.ll2
-rw-r--r--test/ELF/lto/mix-platforms2.ll9
-rw-r--r--test/ELF/lto/module-asm.ll2
-rw-r--r--test/ELF/lto/new-pass-manager.ll14
-rw-r--r--test/ELF/lto/opt-level.ll22
-rw-r--r--test/ELF/lto/parallel-internalize.ll20
-rw-r--r--test/ELF/lto/parallel.ll2
-rw-r--r--test/ELF/lto/relax-relocs.ll2
-rw-r--r--test/ELF/lto/relocatable.ll9
-rw-r--r--test/ELF/lto/sample-profile.ll25
-rw-r--r--test/ELF/lto/save-temps.ll2
-rw-r--r--test/ELF/lto/setting-dso-local.ll15
-rw-r--r--test/ELF/lto/start-lib.ll6
-rw-r--r--test/ELF/lto/symbol-ordering-lto.s11
-rw-r--r--test/ELF/lto/thinlto-cant-write-index.ll23
-rw-r--r--test/ELF/lto/thinlto-debug-fission.ll21
-rw-r--r--test/ELF/lto/thinlto-emit-imports.ll55
-rw-r--r--test/ELF/lto/thinlto-index-file.ll24
-rw-r--r--test/ELF/lto/thinlto-index-only.ll89
-rw-r--r--test/ELF/lto/thinlto-no-index.ll24
-rw-r--r--test/ELF/lto/thinlto-obj-path.ll23
-rw-r--r--test/ELF/lto/thinlto-object-suffix-replace.ll50
-rw-r--r--test/ELF/lto/thinlto-prefix-replace.ll23
-rw-r--r--test/ELF/lto/thinlto.ll31
-rw-r--r--test/ELF/lto/timepasses.ll7
-rw-r--r--test/ELF/lto/tls-mixed.ll2
-rw-r--r--test/ELF/lto/tls-preserve.ll2
-rw-r--r--test/ELF/lto/type-merge.ll2
-rw-r--r--test/ELF/lto/type-merge2.ll2
-rw-r--r--test/ELF/lto/undef-weak.ll5
-rw-r--r--test/ELF/lto/undef.ll2
-rw-r--r--test/ELF/lto/undefined-puts.ll2
-rw-r--r--test/ELF/lto/unnamed-addr-comdat.ll2
-rw-r--r--test/ELF/lto/unnamed-addr-drop.ll2
-rw-r--r--test/ELF/lto/unnamed-addr-lib.ll2
-rw-r--r--test/ELF/lto/unnamed-addr.ll2
-rw-r--r--test/ELF/lto/verify-invalid.ll6
-rw-r--r--test/ELF/lto/version-script.ll2
-rw-r--r--test/ELF/lto/version-script2.ll15
-rw-r--r--test/ELF/lto/visibility.ll5
-rw-r--r--test/ELF/lto/weak.ll2
-rw-r--r--test/ELF/lto/weakodr-visibility.ll40
-rw-r--r--test/ELF/lto/wrap-1.ll4
-rw-r--r--test/ELF/map-file-i686.s21
-rw-r--r--test/ELF/map-file.s120
-rw-r--r--test/ELF/map-gc-sections.s3
-rw-r--r--test/ELF/merge-gc-piece.s38
-rw-r--r--test/ELF/merge-gc-piece2.s27
-rw-r--r--test/ELF/merge-reloc-O0.s48
-rw-r--r--test/ELF/merge-shared-str.s4
-rw-r--r--test/ELF/merge-shared.s4
-rw-r--r--test/ELF/merge-string-empty.s4
-rw-r--r--test/ELF/merge-string-error.s2
-rw-r--r--test/ELF/merge-string-no-null.s2
-rw-r--r--test/ELF/merge-string.s22
-rw-r--r--test/ELF/merge-sym.s4
-rw-r--r--test/ELF/merge-to-non-alloc.s33
-rw-r--r--test/ELF/mips-26-mask.s3
-rw-r--r--test/ELF/mips-26-n32-n64.s13
-rw-r--r--test/ELF/mips-26.s3
-rw-r--r--test/ELF/mips-32.s3
-rw-r--r--test/ELF/mips-64-disp.s3
-rw-r--r--test/ELF/mips-64-got-overflow.s80
-rw-r--r--test/ELF/mips-64-got.s3
-rw-r--r--test/ELF/mips-64-gprel-so.s3
-rw-r--r--test/ELF/mips-64-rels.s3
-rw-r--r--test/ELF/mips-64.s14
-rw-r--r--test/ELF/mips-abs-got.s36
-rw-r--r--test/ELF/mips-align-err.s2
-rw-r--r--test/ELF/mips-call-hilo.s3
-rw-r--r--test/ELF/mips-call16.s3
-rw-r--r--test/ELF/mips-dynamic.s49
-rw-r--r--test/ELF/mips-dynsym-sort.s3
-rw-r--r--test/ELF/mips-elf-abi.s22
-rw-r--r--test/ELF/mips-elf-flags-err.s33
-rw-r--r--test/ELF/mips-elf-flags-err.test89
-rw-r--r--test/ELF/mips-elf-flags.s3
-rw-r--r--test/ELF/mips-fp-flags-err.test162
-rw-r--r--test/ELF/mips-gnu-hash.s7
-rw-r--r--test/ELF/mips-got-and-copy.s8
-rw-r--r--test/ELF/mips-got-extsym.s3
-rw-r--r--test/ELF/mips-got-hilo.s3
-rw-r--r--test/ELF/mips-got-page-script.s3
-rw-r--r--test/ELF/mips-got-page.s3
-rw-r--r--test/ELF/mips-got-redundant.s3
-rw-r--r--test/ELF/mips-got-relocs.s3
-rw-r--r--test/ELF/mips-got-script.s13
-rw-r--r--test/ELF/mips-got-string.s5
-rw-r--r--test/ELF/mips-got-weak.s160
-rw-r--r--test/ELF/mips-got16-relocatable.s3
-rw-r--r--test/ELF/mips-got16.s3
-rw-r--r--test/ELF/mips-gp-disp-ver.s14
-rw-r--r--test/ELF/mips-gp-disp.s3
-rw-r--r--test/ELF/mips-gp-ext.s41
-rw-r--r--test/ELF/mips-gp-local.s3
-rw-r--r--test/ELF/mips-gp-lowest.s11
-rw-r--r--test/ELF/mips-gprel-sec.s3
-rw-r--r--test/ELF/mips-gprel32-relocs-gp0.s12
-rw-r--r--test/ELF/mips-gprel32-relocs.s3
-rw-r--r--test/ELF/mips-higher-highest.s3
-rw-r--r--test/ELF/mips-hilo-gp-disp.s3
-rw-r--r--test/ELF/mips-hilo-hi-only.s3
-rw-r--r--test/ELF/mips-hilo.s3
-rw-r--r--test/ELF/mips-lo16-not-relative.s3
-rw-r--r--test/ELF/mips-merge-abiflags.s2
-rw-r--r--test/ELF/mips-mgot.s117
-rw-r--r--test/ELF/mips-micro-got.s3
-rw-r--r--test/ELF/mips-micro-got64.s48
-rw-r--r--test/ELF/mips-micro-jal.s3
-rw-r--r--test/ELF/mips-micro-plt.s37
-rw-r--r--test/ELF/mips-micro-relocs.s3
-rw-r--r--test/ELF/mips-micro-thunks.s85
-rw-r--r--test/ELF/mips-micror6-relocs.s38
-rw-r--r--test/ELF/mips-n32-emul.s5
-rw-r--r--test/ELF/mips-n32-rels.s46
-rw-r--r--test/ELF/mips-non-zero-gp0.s54
-rw-r--r--test/ELF/mips-nonalloc.s3
-rw-r--r--test/ELF/mips-options.s3
-rw-r--r--test/ELF/mips-out-of-bounds-call16-reloc.s4
-rw-r--r--test/ELF/mips-pc-relocs.s3
-rw-r--r--test/ELF/mips-plt-copy.s11
-rw-r--r--test/ELF/mips-plt-n32.s43
-rw-r--r--test/ELF/mips-plt-r6.s14
-rw-r--r--test/ELF/mips-reginfo.s3
-rw-r--r--test/ELF/mips-relocatable.s3
-rw-r--r--test/ELF/mips-sto-pic-flag.s3
-rw-r--r--test/ELF/mips-sto-plt.s11
-rw-r--r--test/ELF/mips-tls-64-pic-local-variable.s49
-rw-r--r--test/ELF/mips-tls-64.s79
-rw-r--r--test/ELF/mips-tls-hilo.s3
-rw-r--r--test/ELF/mips-tls-static-64.s3
-rw-r--r--test/ELF/mips-tls-static.s7
-rw-r--r--test/ELF/mips-tls.s73
-rw-r--r--test/ELF/mips-xgot-order.s3
-rw-r--r--test/ELF/mips64-eh-abs-reloc.s6
-rw-r--r--test/ELF/multiple-cu.s38
-rw-r--r--test/ELF/new-dtags.test6
-rw-r--r--test/ELF/no-augmentation.s5
-rw-r--r--test/ELF/no-dynamic-linker.s12
-rw-r--r--test/ELF/no-inhibit-exec.s2
-rw-r--r--test/ELF/no-line-parser-errors-if-empty-section.s21
-rw-r--r--test/ELF/no-line-parser-errors-if-no-section.s19
-rw-r--r--test/ELF/no-obj.s2
-rw-r--r--test/ELF/no-symtab.s2
-rw-r--r--test/ELF/no-undefined.s4
-rw-r--r--test/ELF/non-abs-reloc.s18
-rw-r--r--test/ELF/non-alloc-link-order-gc.s34
-rw-r--r--test/ELF/note-contiguous.s36
-rw-r--r--test/ELF/note-loadaddr.s (renamed from test/ELF/note-loadaddr.c)0
-rw-r--r--test/ELF/note-noalloc.s38
-rw-r--r--test/ELF/note-noalloc2.s11
-rw-r--r--test/ELF/oformat-binary.s2
-rw-r--r--test/ELF/output-section.s2
-rw-r--r--test/ELF/pack-dyn-relocs.s361
-rw-r--r--test/ELF/pack-dyn-relocs2.s85
-rw-r--r--test/ELF/pie.s4
-rw-r--r--test/ELF/plt-aarch64.s3
-rw-r--r--test/ELF/plt-i686.s2
-rw-r--r--test/ELF/plt.s3
-rw-r--r--test/ELF/ppc-rela.s11
-rw-r--r--test/ELF/ppc-relocs.s2
-rw-r--r--test/ELF/ppc64-abi-version.s11
-rw-r--r--test/ELF/ppc64-addr16-error.s9
-rw-r--r--test/ELF/ppc64-dtprel.s204
-rw-r--r--test/ELF/ppc64-dynamic-relocations.s50
-rw-r--r--test/ELF/ppc64-error-toc-restore.s20
-rw-r--r--test/ELF/ppc64-error-toc-tail-call.s20
-rw-r--r--test/ELF/ppc64-func-entry-points.s80
-rw-r--r--test/ELF/ppc64-gd-to-ie.s104
-rw-r--r--test/ELF/ppc64-general-dynamic-tls.s112
-rw-r--r--test/ELF/ppc64-got-indirect.s115
-rw-r--r--test/ELF/ppc64-ifunc.s87
-rw-r--r--test/ELF/ppc64-initial-exec-tls.s102
-rw-r--r--test/ELF/ppc64-local-dynamic.s128
-rw-r--r--test/ELF/ppc64-local-exec-tls.s163
-rw-r--r--test/ELF/ppc64-plt-stub.s42
-rw-r--r--test/ELF/ppc64-rel-calls.s34
-rw-r--r--test/ELF/ppc64-rel-so-local-calls.s87
-rw-r--r--test/ELF/ppc64-relocs.s103
-rw-r--r--test/ELF/ppc64-shared-rel-toc.s27
-rw-r--r--test/ELF/ppc64-tls-gd-le.s83
-rw-r--r--test/ELF/ppc64-tls-ld-le.s84
-rw-r--r--test/ELF/ppc64-toc-rel.s90
-rw-r--r--test/ELF/ppc64-toc-restore.s94
-rw-r--r--test/ELF/ppc64-weak-undef-call-shared.s9
-rw-r--r--test/ELF/ppc64-weak-undef-call.s19
-rw-r--r--test/ELF/ppc64_entry_point.s50
-rw-r--r--test/ELF/pr34660.s2
-rw-r--r--test/ELF/pr34872.s3
-rw-r--r--test/ELF/pr36475.s30
-rw-r--r--test/ELF/pr37735.s12
-rw-r--r--test/ELF/pre_init_fini_array.s2
-rw-r--r--test/ELF/pre_init_fini_array_missing.s39
-rw-r--r--test/ELF/print-icf.s48
-rw-r--r--test/ELF/program-header-layout.s2
-rw-r--r--test/ELF/protected-data-access.s27
-rw-r--r--test/ELF/protected-function-access.s27
-rw-r--r--test/ELF/push-state.s36
-rw-r--r--test/ELF/rel-addend-with-rela-input.s43
-rw-r--r--test/ELF/relative-dynamic-reloc-ppc64.s6
-rw-r--r--test/ELF/relocatable-build-id.s12
-rw-r--r--test/ELF/relocatable-comdat-multiple.s4
-rw-r--r--test/ELF/relocatable-comdat.s2
-rw-r--r--test/ELF/relocatable-comdat2.s4
-rw-r--r--test/ELF/relocatable-eh-frame.s2
-rw-r--r--test/ELF/relocatable-many-sections.s92
-rw-r--r--test/ELF/relocatable-symbols.s36
-rw-r--r--test/ELF/relocatable-versioned.s9
-rw-r--r--test/ELF/relocation-absolute.s2
-rw-r--r--test/ELF/relocation-common.s2
-rw-r--r--test/ELF/relocation-dtrace.test2
-rw-r--r--test/ELF/relocation-i686.s2
-rw-r--r--test/ELF/relocation-local.s2
-rw-r--r--test/ELF/relocation-nocopy.s2
-rw-r--r--test/ELF/relocation-non-alloc.s56
-rw-r--r--test/ELF/relocation-none-aarch64.test2
-rw-r--r--test/ELF/relocation-none-i686.test2
-rw-r--r--test/ELF/relocation-past-merge-end.s2
-rw-r--r--test/ELF/relocation-relative-absolute.s2
-rw-r--r--test/ELF/relocation-shared.s6
-rw-r--r--test/ELF/relocation-size-err.s12
-rw-r--r--test/ELF/relocation-size-shared.s1
-rw-r--r--test/ELF/relocation-size.s1
-rw-r--r--test/ELF/relocation-undefined-weak.s2
-rw-r--r--test/ELF/relocation.s11
-rw-r--r--test/ELF/relro-non-contiguous.s2
-rw-r--r--test/ELF/relro-omagic.s5
-rw-r--r--test/ELF/relro-script.s2
-rw-r--r--test/ELF/relro.s10
-rw-r--r--test/ELF/reproduce-backslash.s6
-rw-r--r--test/ELF/reproduce-error.s2
-rw-r--r--test/ELF/reproduce.s2
-rw-r--r--test/ELF/resolution-end.s2
-rw-r--r--test/ELF/resolution-shared.s2
-rw-r--r--test/ELF/resolution.s2
-rw-r--r--test/ELF/rodynamic.s1
-rw-r--r--test/ELF/section-align-0.test2
-rw-r--r--test/ELF/section-layout.s7
-rw-r--r--test/ELF/section-metadata-err.s6
-rw-r--r--test/ELF/section-metadata-err2.s17
-rw-r--r--test/ELF/section-metadata-err3.s17
-rw-r--r--test/ELF/section-name.s2
-rw-r--r--test/ELF/section-symbol.s1
-rw-r--r--test/ELF/section-symbols.test2
-rw-r--r--test/ELF/sectionstart-noallochdr.s2
-rw-r--r--test/ELF/sectionstart.s8
-rw-r--r--test/ELF/shared-lazy.s1
-rw-r--r--test/ELF/shared-ppc64.s (renamed from test/ELF/shared-be.s)9
-rw-r--r--test/ELF/shared.s9
-rw-r--r--test/ELF/shlib-undefined-archive.s19
-rw-r--r--test/ELF/shlib-undefined-local.s19
-rw-r--r--test/ELF/shlib-undefined-shared.s15
-rw-r--r--test/ELF/sht-group-gold-r.test1
-rw-r--r--test/ELF/silent-ignore.test1
-rw-r--r--test/ELF/soname.s1
-rw-r--r--test/ELF/soname2.s1
-rw-r--r--test/ELF/sort-norosegment.s10
-rw-r--r--test/ELF/splitstacks.s11
-rw-r--r--test/ELF/start-lib.s9
-rw-r--r--test/ELF/startstop-shared.s22
-rw-r--r--test/ELF/startstop.s15
-rw-r--r--test/ELF/static-with-export-dynamic.s2
-rw-r--r--test/ELF/string-gc.s1
-rw-r--r--test/ELF/string-table.s2
-rw-r--r--test/ELF/symbol-ordering-file-icf.s32
-rw-r--r--test/ELF/symbol-ordering-file-warnings.s165
-rw-r--r--test/ELF/symbol-ordering-file.s16
-rw-r--r--test/ELF/symbol-override.s1
-rw-r--r--test/ELF/symbols.s2
-rw-r--r--test/ELF/symver-archive.s2
-rw-r--r--test/ELF/sysroot.s2
-rw-r--r--test/ELF/sysv-hash-no-rosegment.s13
-rw-r--r--test/ELF/text-section-prefix.s39
-rw-r--r--test/ELF/tls-archive.s2
-rw-r--r--test/ELF/tls-error.s2
-rw-r--r--test/ELF/tls-got.s9
-rw-r--r--test/ELF/tls-in-archive.s2
-rw-r--r--test/ELF/tls-mismatch.s2
-rw-r--r--test/ELF/tls-opt-gdie.s1
-rw-r--r--test/ELF/tls-opt-gdiele-i686.s1
-rw-r--r--test/ELF/tls-opt-i686.s5
-rw-r--r--test/ELF/tls-opt-iele-i686-nopic.s1
-rw-r--r--test/ELF/tls-opt-local.s1
-rw-r--r--test/ELF/tls-opt-no-plt.s1
-rw-r--r--test/ELF/tls-opt.s1
-rw-r--r--test/ELF/tls-static.s2
-rw-r--r--test/ELF/trace-symbols.s8
-rw-r--r--test/ELF/typed-undef.s2
-rw-r--r--test/ELF/undef-broken-debug.test23
-rw-r--r--test/ELF/undef-shared.s3
-rw-r--r--test/ELF/undef-shared2.s11
-rw-r--r--test/ELF/undef-start.s6
-rw-r--r--test/ELF/undef-version-script.s1
-rw-r--r--test/ELF/undef.s18
-rw-r--r--test/ELF/undefined-opt.s2
-rw-r--r--test/ELF/unresolved-symbols.s10
-rw-r--r--test/ELF/user_def_init_array_start.s3
-rw-r--r--test/ELF/verdef-defaultver.s6
-rw-r--r--test/ELF/verneed-local.s2
-rw-r--r--test/ELF/verneed.s124
-rw-r--r--test/ELF/version-exclude-libs.s30
-rw-r--r--test/ELF/version-script-complex-wildcards.s2
-rw-r--r--test/ELF/version-script-extern-undefined.s19
-rw-r--r--test/ELF/version-script-extern.s2
-rw-r--r--test/ELF/version-script-extern2.s22
-rw-r--r--test/ELF/version-script-glob.s2
-rw-r--r--test/ELF/version-script-in-search-path.s10
-rw-r--r--test/ELF/version-script-missing.s2
-rw-r--r--test/ELF/version-script-no-warn.s2
-rw-r--r--test/ELF/version-script-no-warn2.s3
-rw-r--r--test/ELF/version-script-noundef.s2
-rw-r--r--test/ELF/version-script-symver.s2
-rw-r--r--test/ELF/version-script.s9
-rw-r--r--test/ELF/version-symbol-error.s2
-rw-r--r--test/ELF/version-undef-sym.s2
-rw-r--r--test/ELF/visibility.s2
-rw-r--r--test/ELF/warn-backrefs.s48
-rw-r--r--test/ELF/warn-common.s4
-rw-r--r--test/ELF/warn-unresolved-symbols-hidden.s2
-rw-r--r--test/ELF/warn-unresolved-symbols.s14
-rw-r--r--test/ELF/weak-and-strong-undef.s2
-rw-r--r--test/ELF/weak-shared-gc.s21
-rw-r--r--test/ELF/weak-undef-lazy.s2
-rw-r--r--test/ELF/weak-undef-lib.s19
-rw-r--r--test/ELF/weak-undef-rw.s12
-rw-r--r--test/ELF/whole-archive-name.s15
-rw-r--r--test/ELF/wrap.s2
-rw-r--r--test/ELF/writable-merge.s2
-rw-r--r--test/ELF/writable-sec-plt-reloc.s2
-rw-r--r--test/ELF/x86-64-dyn-rel-error.s6
-rw-r--r--test/ELF/x86-64-dyn-rel-error2.s4
-rw-r--r--test/ELF/x86-64-dyn-rel-error3.s16
-rw-r--r--test/ELF/x86-64-plt-high-addr.s24
-rw-r--r--test/ELF/x86-64-reloc-16.s4
-rw-r--r--test/ELF/x86-64-reloc-32-fpic.s4
-rw-r--r--test/ELF/x86-64-reloc-8.s4
-rw-r--r--test/ELF/x86-64-reloc-debug-overflow.s9
-rw-r--r--test/ELF/x86-64-reloc-error-reporting.s19
-rw-r--r--test/ELF/x86-64-reloc-error.s4
-rw-r--r--test/ELF/x86-64-reloc-error2.s14
-rw-r--r--test/ELF/x86-64-reloc-gotoff64.s32
-rw-r--r--test/ELF/x86-64-reloc-gotpc64.s14
-rw-r--r--test/ELF/x86-64-reloc-pc32-fpic.s7
-rw-r--r--test/ELF/x86-64-reloc-range-debug-loc.s36
-rw-r--r--test/ELF/x86-64-reloc-range.s3
-rw-r--r--test/ELF/x86-64-reloc-tpoff32-fpic.s4
-rw-r--r--test/ELF/x86-64-retpoline-linkerscript.s67
-rw-r--r--test/ELF/x86-64-retpoline-znow-linkerscript.s54
-rw-r--r--test/ELF/x86-64-retpoline-znow.s53
-rw-r--r--test/ELF/x86-64-retpoline.s66
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-fail.s31
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-silent.s32
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-success.s124
-rw-r--r--test/ELF/x86-64-tls-ld-local.s29
-rw-r--r--test/ELF/zdefs.s1
-rw-r--r--test/ELF/znotext-plt-relocations-protected.s4
-rw-r--r--test/ELF/znotext-weak-undef.s2
-rw-r--r--test/ELF/ztext.s (renamed from test/ELF/ztext-text-notext.s)37
-rw-r--r--test/MinGW/driver.test21
-rw-r--r--test/darwin/cmdline-lto_library.objtxt11
-rw-r--r--test/darwin/cmdline-objc_gc.objtxt2
-rw-r--r--test/darwin/cmdline-objc_gc_compaction.objtxt2
-rw-r--r--test/darwin/cmdline-objc_gc_only.objtxt2
-rw-r--r--test/darwin/native-and-mach-o.objtxt2
-rw-r--r--test/lit.cfg.py12
-rw-r--r--test/lit.site.cfg.py.in3
-rw-r--r--test/mach-o/Inputs/swift-version-1.yaml2
-rw-r--r--test/mach-o/Inputs/wrong-arch-error.yaml2
-rw-r--r--test/mach-o/PIE.yaml6
-rw-r--r--test/mach-o/align_text.yaml4
-rw-r--r--test/mach-o/arm-interworking-movw.yaml4
-rw-r--r--test/mach-o/arm-interworking.yaml4
-rw-r--r--test/mach-o/arm-shims.yaml2
-rw-r--r--test/mach-o/arm-subsections-via-symbols.yaml2
-rw-r--r--test/mach-o/arm64-reloc-negDelta32-fixup.yaml4
-rw-r--r--test/mach-o/arm64-relocs-errors-delta64-offset.yaml2
-rw-r--r--test/mach-o/arm64-section-order.yaml4
-rw-r--r--test/mach-o/bind-opcodes.yaml2
-rw-r--r--test/mach-o/cstring-sections.yaml2
-rw-r--r--test/mach-o/data-in-code-load-command.yaml16
-rw-r--r--test/mach-o/data-only-dylib.yaml2
-rw-r--r--test/mach-o/dead-strip-globals.yaml8
-rw-r--r--test/mach-o/debug-syms.yaml2
-rw-r--r--test/mach-o/demangle.yaml4
-rw-r--r--test/mach-o/dependency_info.yaml4
-rw-r--r--test/mach-o/do-not-emit-unwind-fde-arm64.yaml4
-rw-r--r--test/mach-o/dso_handle.yaml8
-rw-r--r--test/mach-o/dylib-install-names.yaml8
-rw-r--r--test/mach-o/eh-frame-relocs-arm64.yaml4
-rw-r--r--test/mach-o/error-simulator-vs-macosx.yaml4
-rw-r--r--test/mach-o/exe-offsets.yaml2
-rw-r--r--test/mach-o/exe-segment-overlap.yaml2
-rw-r--r--test/mach-o/executable-exports.yaml2
-rw-r--r--test/mach-o/export-trie-order.yaml2
-rw-r--r--test/mach-o/exported_symbols_list-dylib.yaml8
-rw-r--r--test/mach-o/exported_symbols_list-obj.yaml6
-rw-r--r--test/mach-o/exported_symbols_list-undef.yaml2
-rw-r--r--test/mach-o/fat-archive.yaml2
-rw-r--r--test/mach-o/filelist.yaml4
-rw-r--r--test/mach-o/flat_namespace_undef_error.yaml2
-rw-r--r--test/mach-o/flat_namespace_undef_suppress.yaml2
-rw-r--r--test/mach-o/force_load-dylib.yaml4
-rw-r--r--test/mach-o/force_load-x86_64.yaml4
-rw-r--r--test/mach-o/framework-user-paths.yaml2
-rw-r--r--test/mach-o/function-starts-load-command.yaml10
-rw-r--r--test/mach-o/gcc_except_tab-got-arm64.yaml2
-rw-r--r--test/mach-o/got-order.yaml2
-rw-r--r--test/mach-o/hello-world-arm64.yaml2
-rw-r--r--test/mach-o/hello-world-armv6.yaml2
-rw-r--r--test/mach-o/hello-world-armv7.yaml2
-rw-r--r--test/mach-o/hello-world-x86.yaml2
-rw-r--r--test/mach-o/hello-world-x86_64.yaml4
-rw-r--r--test/mach-o/image-base.yaml8
-rw-r--r--test/mach-o/infer-arch.yaml4
-rw-r--r--test/mach-o/interposing-section.yaml4
-rw-r--r--test/mach-o/keep_private_externs.yaml4
-rw-r--r--test/mach-o/lazy-bind-x86_64.yaml2
-rw-r--r--test/mach-o/lc_segment_filesize.yaml2
-rw-r--r--test/mach-o/lib-search-paths.yaml2
-rw-r--r--test/mach-o/library-order.yaml2
-rw-r--r--test/mach-o/library-rescan.yaml2
-rw-r--r--test/mach-o/libresolve-bizarre-root-override.yaml2
-rw-r--r--test/mach-o/libresolve-multiple-syslibroots.yaml2
-rw-r--r--test/mach-o/libresolve-one-syslibroot.yaml2
-rw-r--r--test/mach-o/libresolve-simple.yaml2
-rw-r--r--test/mach-o/libresolve-user-paths.yaml2
-rw-r--r--test/mach-o/libresolve-z.yaml2
-rw-r--r--test/mach-o/mach_header-cpusubtype.yaml6
-rw-r--r--test/mach-o/mh_bundle_header.yaml4
-rw-r--r--test/mach-o/mh_dylib_header.yaml2
-rw-r--r--test/mach-o/objc-category-list-atom.yaml4
-rw-r--r--test/mach-o/objc-image-info-host-vs-simulator.yaml2
-rw-r--r--test/mach-o/objc-image-info-invalid-size.yaml2
-rw-r--r--test/mach-o/objc-image-info-invalid-version.yaml2
-rw-r--r--test/mach-o/objc-image-info-mismatched-swift-version.yaml2
-rw-r--r--test/mach-o/objc-image-info-pass-output.yaml2
-rw-r--r--test/mach-o/objc-image-info-simulator-vs-host.yaml2
-rw-r--r--test/mach-o/objc-image-info-unsupported-gc.yaml2
-rw-r--r--test/mach-o/objc_export_list.yaml2
-rw-r--r--test/mach-o/order_file-basic.yaml2
-rw-r--r--test/mach-o/parse-aliases.yaml2
-rw-r--r--test/mach-o/parse-arm-relocs.yaml4
-rw-r--r--test/mach-o/parse-cfstring32.yaml2
-rw-r--r--test/mach-o/parse-cfstring64.yaml2
-rw-r--r--test/mach-o/parse-compact-unwind32.yaml2
-rw-r--r--test/mach-o/parse-compact-unwind64.yaml2
-rw-r--r--test/mach-o/parse-data-in-code-armv7.yaml6
-rw-r--r--test/mach-o/parse-data-in-code-x86.yaml4
-rw-r--r--test/mach-o/parse-data-relocs-arm64.yaml4
-rw-r--r--test/mach-o/parse-data-relocs-x86_64.yaml4
-rw-r--r--test/mach-o/parse-data.yaml2
-rw-r--r--test/mach-o/parse-eh-frame-relocs-x86_64.yaml2
-rw-r--r--test/mach-o/parse-eh-frame-x86-anon.yaml2
-rw-r--r--test/mach-o/parse-eh-frame-x86-labeled.yaml2
-rw-r--r--test/mach-o/parse-eh-frame.yaml2
-rw-r--r--test/mach-o/parse-function.yaml4
-rw-r--r--test/mach-o/parse-initializers32.yaml2
-rw-r--r--test/mach-o/parse-initializers64.yaml2
-rw-r--r--test/mach-o/parse-literals-error.yaml2
-rw-r--r--test/mach-o/parse-literals.yaml2
-rw-r--r--test/mach-o/parse-non-lazy-pointers.yaml2
-rw-r--r--test/mach-o/parse-relocs-x86.yaml4
-rw-r--r--test/mach-o/parse-section-no-symbol.yaml2
-rw-r--r--test/mach-o/parse-tentative-defs.yaml2
-rw-r--r--test/mach-o/parse-text-relocs-arm64.yaml4
-rw-r--r--test/mach-o/parse-text-relocs-x86_64.yaml4
-rw-r--r--test/mach-o/parse-tlv-relocs-x86-64.yaml4
-rw-r--r--test/mach-o/re-exported-dylib-ordinal.yaml2
-rw-r--r--test/mach-o/rpath.yaml2
-rw-r--r--test/mach-o/run-tlv-pass-x86-64.yaml4
-rw-r--r--test/mach-o/sdk-version-error.yaml2
-rw-r--r--test/mach-o/sectalign.yaml2
-rw-r--r--test/mach-o/sectattrs.yaml2
-rw-r--r--test/mach-o/sectcreate.yaml2
-rw-r--r--test/mach-o/seg-protection-arm64.yaml2
-rw-r--r--test/mach-o/seg-protection-x86_64.yaml2
-rw-r--r--test/mach-o/source-version.yaml4
-rw-r--r--test/mach-o/stack-size.yaml8
-rw-r--r--test/mach-o/string-table.yaml2
-rw-r--r--test/mach-o/subsections-via-symbols-default.yaml2
-rw-r--r--test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml2
-rw-r--r--test/mach-o/twolevel_namespace_undef_warning_suppress.yaml4
-rw-r--r--test/mach-o/unwind-info-simple-arm64.yaml2
-rw-r--r--test/mach-o/unwind-info-simple-x86_64.yaml2
-rw-r--r--test/mach-o/upward-dylib-load-command.yaml4
-rw-r--r--test/mach-o/upward-dylib-paths.yaml2
-rw-r--r--test/mach-o/usage.yaml2
-rw-r--r--test/mach-o/use-dylib.yaml2
-rw-r--r--test/mach-o/use-simple-dylib.yaml2
-rw-r--r--test/mach-o/version-min-load-command-object.yaml6
-rw-r--r--test/mach-o/version-min-load-command.yaml14
-rw-r--r--test/mach-o/write-final-sections.yaml2
-rw-r--r--test/mach-o/wrong-arch-error.yaml2
-rw-r--r--test/wasm/Inputs/archive1.ll2
-rw-r--r--test/wasm/Inputs/archive2.ll7
-rw-r--r--test/wasm/Inputs/archive3.ll11
-rw-r--r--test/wasm/Inputs/call-indirect.ll13
-rw-r--r--test/wasm/Inputs/comdat1.ll13
-rw-r--r--test/wasm/Inputs/comdat2.ll13
-rw-r--r--test/wasm/Inputs/custom.ll6
-rw-r--r--test/wasm/Inputs/debuginfo1.ll68
-rw-r--r--test/wasm/Inputs/debuginfo2.ll70
-rw-r--r--test/wasm/Inputs/global-ctor-dtor.ll14
-rw-r--r--test/wasm/Inputs/globals.yaml54
-rw-r--r--test/wasm/Inputs/hello.ll2
-rw-r--r--test/wasm/Inputs/hidden.ll2
-rw-r--r--test/wasm/Inputs/locals-duplicate1.ll51
-rw-r--r--test/wasm/Inputs/locals-duplicate2.ll51
-rw-r--r--test/wasm/Inputs/many-funcs.ll2
-rw-r--r--test/wasm/Inputs/ret32.ll6
-rw-r--r--test/wasm/Inputs/ret64.ll4
-rw-r--r--test/wasm/Inputs/start.ll6
-rw-r--r--test/wasm/Inputs/strong-symbol.ll6
-rw-r--r--test/wasm/Inputs/undefined-globals.yaml52
-rw-r--r--test/wasm/Inputs/weak-alias.ll2
-rw-r--r--test/wasm/Inputs/weak-symbol1.ll2
-rw-r--r--test/wasm/Inputs/weak-symbol2.ll2
-rw-r--r--test/wasm/alias.ll88
-rw-r--r--test/wasm/archive.ll56
-rw-r--r--test/wasm/call-indirect.ll119
-rw-r--r--test/wasm/comdats.ll99
-rw-r--r--test/wasm/compress-relocs.ll22
-rw-r--r--test/wasm/conflict.test4
-rw-r--r--test/wasm/custom-sections.ll22
-rw-r--r--test/wasm/cxx-mangling.ll66
-rw-r--r--test/wasm/data-layout.ll153
-rw-r--r--test/wasm/data-segment-merging.ll48
-rw-r--r--test/wasm/debuginfo.test85
-rw-r--r--test/wasm/demangle.ll17
-rw-r--r--test/wasm/driver.ll22
-rw-r--r--test/wasm/entry-signature.ll10
-rw-r--r--test/wasm/entry.ll59
-rw-r--r--test/wasm/export-all.ll48
-rw-r--r--test/wasm/export-table.test19
-rw-r--r--test/wasm/export.ll37
-rw-r--r--test/wasm/fatal-warnings.ll17
-rw-r--r--test/wasm/function-imports-first.ll28
-rw-r--r--test/wasm/function-imports.ll25
-rw-r--r--test/wasm/function-index.test6
-rw-r--r--test/wasm/gc-imports.ll93
-rw-r--r--test/wasm/gc-sections.ll153
-rw-r--r--test/wasm/import-memory.test28
-rw-r--r--test/wasm/import-table.test18
-rw-r--r--test/wasm/init-fini.ll315
-rw-r--r--test/wasm/invalid-stack-size.test9
-rw-r--r--test/wasm/load-undefined.ll38
-rw-r--r--test/wasm/load-undefined.test40
-rw-r--r--test/wasm/local-symbols.ll71
-rw-r--r--test/wasm/locals-duplicate.test568
-rw-r--r--test/wasm/lto/Inputs/archive.ll6
-rw-r--r--test/wasm/lto/Inputs/cache.ll10
-rw-r--r--test/wasm/lto/Inputs/save-temps.ll6
-rw-r--r--test/wasm/lto/Inputs/thinlto.ll7
-rw-r--r--test/wasm/lto/Inputs/used.ll8
-rw-r--r--test/wasm/lto/archive.ll25
-rw-r--r--test/wasm/lto/atomics.ll14
-rw-r--r--test/wasm/lto/cache.ll38
-rw-r--r--test/wasm/lto/diagnostics.ll22
-rw-r--r--test/wasm/lto/export.ll38
-rw-r--r--test/wasm/lto/incompatible.ll8
-rw-r--r--test/wasm/lto/internalize-basic.ll20
-rw-r--r--test/wasm/lto/lto-start.ll18
-rw-r--r--test/wasm/lto/opt-level.ll30
-rw-r--r--test/wasm/lto/parallel.ll24
-rw-r--r--test/wasm/lto/save-temps.ll19
-rw-r--r--test/wasm/lto/thinlto.ll34
-rw-r--r--test/wasm/lto/undef.ll20
-rw-r--r--test/wasm/lto/used.ll45
-rw-r--r--test/wasm/lto/verify-invalid.ll16
-rw-r--r--test/wasm/lto/weak.ll16
-rw-r--r--test/wasm/many-functions.ll1323
-rw-r--r--test/wasm/reloc-addend.ll19
-rw-r--r--test/wasm/relocatable.ll239
-rw-r--r--test/wasm/responsefile.test10
-rw-r--r--test/wasm/signature-mismatch-weak.ll18
-rw-r--r--test/wasm/signature-mismatch.ll16
-rw-r--r--test/wasm/stack-first.test42
-rw-r--r--test/wasm/stack-pointer.ll50
-rw-r--r--test/wasm/strip-debug.test4
-rw-r--r--test/wasm/symbol-type-mismatch.ll12
-rw-r--r--test/wasm/undefined-entry.test11
-rw-r--r--test/wasm/undefined-weak-call.ll120
-rw-r--r--test/wasm/undefined.ll18
-rw-r--r--test/wasm/version.ll6
-rw-r--r--test/wasm/visibility-hidden.ll26
-rw-r--r--test/wasm/weak-alias-overide.ll106
-rw-r--r--test/wasm/weak-alias.ll273
-rw-r--r--test/wasm/weak-symbols.ll88
-rw-r--r--test/wasm/weak-undefined.ll (renamed from test/wasm/weak-external.ll)75
-rw-r--r--test/wasm/whole-archive.test34
-rw-r--r--tools/lld/lld.cpp49
-rw-r--r--unittests/DriverTests/DarwinLdDriverTest.cpp9
-rw-r--r--unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp15
-rw-r--r--wasm/CMakeLists.txt16
-rw-r--r--wasm/Config.h24
-rw-r--r--wasm/Driver.cpp374
-rw-r--r--wasm/InputChunks.cpp295
-rw-r--r--wasm/InputChunks.h236
-rw-r--r--wasm/InputFiles.cpp462
-rw-r--r--wasm/InputFiles.h95
-rw-r--r--wasm/InputGlobal.h59
-rw-r--r--wasm/InputSegment.cpp25
-rw-r--r--wasm/InputSegment.h76
-rw-r--r--wasm/LTO.cpp155
-rw-r--r--wasm/LTO.h57
-rw-r--r--wasm/MarkLive.cpp118
-rw-r--r--wasm/MarkLive.h21
-rw-r--r--wasm/Options.td119
-rw-r--r--wasm/OutputSections.cpp287
-rw-r--r--wasm/OutputSections.h50
-rw-r--r--wasm/OutputSegment.h28
-rw-r--r--wasm/SymbolTable.cpp390
-rw-r--r--wasm/SymbolTable.h43
-rw-r--r--wasm/Symbols.cpp240
-rw-r--r--wasm/Symbols.h337
-rw-r--r--wasm/Writer.cpp954
-rw-r--r--wasm/WriterUtils.cpp113
-rw-r--r--wasm/WriterUtils.h46
1593 files changed, 40958 insertions, 11573 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
index 4610ccc880fd..bb241e788c19 100644
--- a/COFF/CMakeLists.txt
+++ b/COFF/CMakeLists.txt
@@ -18,7 +18,6 @@ add_lld_library(lldCOFF
MarkLive.cpp
MinGW.cpp
PDB.cpp
- Strings.cpp
SymbolTable.cpp
Symbols.cpp
Writer.cpp
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 557b02654426..412ff783222b 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -31,8 +31,7 @@ namespace coff {
SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
: Chunk(SectionKind), Repl(this), Header(H), File(F),
- Relocs(File->getCOFFObj()->getRelocations(Header)),
- NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+ Relocs(File->getCOFFObj()->getRelocations(Header)) {
// Initialize SectionName.
File->getCOFFObj()->getSectionName(Header, SectionName);
@@ -51,13 +50,21 @@ static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+// Verify that given sections are appropriate targets for SECREL
+// relocations. This check is relaxed because unfortunately debug
+// sections have section-relative relocations against absolute symbols.
+static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) {
+ if (OS)
+ return true;
+ if (Sec->isCodeView())
+ return false;
+ fatal("SECREL relocation cannot be applied to absolute symbols");
+}
+
static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
OutputSection *OS, uint64_t S) {
- if (!OS) {
- if (Sec->isCodeView())
- return;
- fatal("SECREL relocation cannot be applied to absolute symbols");
- }
+ if (!checkSecRel(Sec, OS))
+ return;
uint64_t SecRel = S - OS->getRVA();
if (SecRel > UINT32_MAX) {
error("overflow in SECREL relocation in section: " + Sec->getSectionName());
@@ -67,10 +74,13 @@ static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
}
static void applySecIdx(uint8_t *Off, OutputSection *OS) {
- // If we have no output section, this must be an absolute symbol. Use the
- // sentinel absolute symbol section index.
- uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex;
- add16(Off, SecIdx);
+ // Absolute symbol doesn't have section index, but section index relocation
+ // against absolute symbol should be resolved to one plus the last output
+ // section index. This is required for compatibility with MSVC.
+ if (OS)
+ add16(Off, OS->SectionIndex);
+ else
+ add16(Off, DefinedAbsolute::NumOutputSections + 1);
}
void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
@@ -88,7 +98,8 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -102,7 +113,8 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -112,11 +124,10 @@ static void applyMOV(uint8_t *Off, uint16_t V) {
}
static uint16_t readMOV(uint8_t *Off) {
- uint16_t Opcode1 = read16le(Off);
- uint16_t Opcode2 = read16le(Off + 2);
- uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700);
- Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12);
- return Imm;
+ uint16_t Op1 = read16le(Off);
+ uint16_t Op2 = read16le(Off + 2);
+ return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) |
+ ((Op1 & 0x000f) << 12);
}
void applyMOV32T(uint8_t *Off, uint32_t V) {
@@ -153,7 +164,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
// Pointer to thumb code must have the LSB set.
uint64_t SX = S;
- if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
SX |= 1;
switch (Type) {
case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
@@ -165,18 +176,19 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) {
+static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
uint32_t Orig = read32le(Off);
uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
S += Imm;
- Imm = (S >> 12) - (P >> 12);
+ Imm = (S >> Shift) - (P >> Shift);
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
@@ -213,19 +225,70 @@ static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
applyArm64Imm(Off, Imm >> Size, Size);
}
+static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0);
+}
+
+static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (!checkSecRel(Sec, OS))
+ return;
+ uint64_t SecRel = (S - OS->getRVA()) >> 12;
+ if (0xfff < SecRel) {
+ error("overflow in SECREL_HIGH12A relocation in section: " +
+ Sec->getSectionName());
+ return;
+ }
+ applyArm64Imm(Off, SecRel & 0xfff, 0);
+}
+
+static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
+}
+
+static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+ if (!isInt<28>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0FFFFFFC) >> 2);
+}
+
+static void applyArm64Branch19(uint8_t *Off, int64_t V) {
+ if (!isInt<21>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x001FFFFC) << 3);
+}
+
+static void applyArm64Branch14(uint8_t *Off, int64_t V) {
+ if (!isInt<16>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0000FFFC) << 3);
+}
+
void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
switch (Type) {
- case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break;
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
- case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -234,7 +297,8 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
return;
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> A = getContents();
- memcpy(Buf + OutputSectionOff, A.data(), A.size());
+ if (!A.empty())
+ memcpy(Buf + OutputSectionOff, A.data(), A.size());
// Apply relocations.
size_t InputSize = getSize();
@@ -350,8 +414,8 @@ bool SectionChunk::hasData() const {
return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
}
-uint32_t SectionChunk::getPermissions() const {
- return Header->Characteristics & PermMask;
+uint32_t SectionChunk::getOutputCharacteristics() const {
+ return Header->Characteristics & (PermMask | TypeMask);
}
bool SectionChunk::isCOMDAT() const {
@@ -378,6 +442,7 @@ ArrayRef<uint8_t> SectionChunk::getContents() const {
}
void SectionChunk::replace(SectionChunk *Other) {
+ Alignment = std::max(Alignment, Other->Alignment);
Other->Repl = Repl;
Other->Live = false;
}
@@ -388,7 +453,7 @@ CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
}
-uint32_t CommonChunk::getPermissions() const {
+uint32_t CommonChunk::getOutputCharacteristics() const {
return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE;
}
@@ -433,7 +498,7 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
int64_t Off = ImpSymbol->getRVA() & 0xfff;
memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
- applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA);
+ applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12);
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
@@ -453,12 +518,14 @@ void LocalImportChunk::writeTo(uint8_t *Buf) const {
}
}
-void SEHTableChunk::writeTo(uint8_t *Buf) const {
+void RVATableChunk::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();
+ for (const ChunkAndOffset &CO : Syms)
+ Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset;
std::sort(Begin, Begin + Cnt);
+ assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt &&
+ "RVA tables should be de-duplicated");
}
// Windows-specific. This class represents a block in .reloc section.
@@ -531,5 +598,47 @@ uint8_t Baserel::getDefaultType() {
}
}
+std::map<uint32_t, MergeChunk *> MergeChunk::Instances;
+
+MergeChunk::MergeChunk(uint32_t Alignment)
+ : Builder(StringTableBuilder::RAW, Alignment) {
+ this->Alignment = Alignment;
+}
+
+void MergeChunk::addSection(SectionChunk *C) {
+ auto *&MC = Instances[C->Alignment];
+ if (!MC)
+ MC = make<MergeChunk>(C->Alignment);
+ MC->Sections.push_back(C);
+}
+
+void MergeChunk::finalizeContents() {
+ for (SectionChunk *C : Sections)
+ if (C->isLive())
+ Builder.add(toStringRef(C->getContents()));
+ Builder.finalize();
+
+ for (SectionChunk *C : Sections) {
+ if (!C->isLive())
+ continue;
+ size_t Off = Builder.getOffset(toStringRef(C->getContents()));
+ C->setOutputSection(Out);
+ C->setRVA(RVA + Off);
+ C->OutputSectionOff = OutputSectionOff + Off;
+ }
+}
+
+uint32_t MergeChunk::getOutputCharacteristics() const {
+ return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
+}
+
+size_t MergeChunk::getSize() const {
+ return Builder.getSize();
+}
+
+void MergeChunk::writeTo(uint8_t *Buf) const {
+ Builder.write(Buf + OutputSectionOff);
+}
+
} // namespace coff
} // namespace lld
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index 381527ee6ef2..9e896531bd9a 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/COFF.h"
#include <utility>
#include <vector>
@@ -37,9 +38,11 @@ class ObjFile;
class OutputSection;
class Symbol;
-// Mask for section types (code, data, bss, disacardable, etc.)
-// and permissions (writable, readable or executable).
-const uint32_t PermMask = 0xFF0000F0;
+// Mask for permissions (discardable, writable, readable, executable, etc).
+const uint32_t PermMask = 0xFE000000;
+
+// Mask for section types (code, data, bss).
+const uint32_t TypeMask = 0x000000E0;
// 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
@@ -60,6 +63,10 @@ public:
// before calling this function.
virtual void writeTo(uint8_t *Buf) const {}
+ // Called by the writer after an RVA is assigned, but before calling
+ // getSize().
+ virtual void finalizeContents() {}
+
// The writer sets and uses the addresses.
uint64_t getRVA() const { return RVA; }
void setRVA(uint64_t V) { RVA = V; }
@@ -70,7 +77,7 @@ public:
virtual bool hasData() const { return true; }
// Returns readable/writable/executable bits.
- virtual uint32_t getPermissions() const { return 0; }
+ virtual uint32_t getOutputCharacteristics() const { return 0; }
// Returns the section name if this is a section chunk.
// It is illegal to call this function on non-section chunks.
@@ -137,7 +144,7 @@ public:
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
bool hasData() const override;
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return SectionName; }
void getBaserels(std::vector<Baserel> *Res) override;
bool isCOMDAT() const;
@@ -208,11 +215,11 @@ public:
// The COMDAT leader symbol if this is a COMDAT chunk.
DefinedRegular *Sym = nullptr;
+ ArrayRef<coff_relocation> Relocs;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
- llvm::iterator_range<const coff_relocation *> Relocs;
- size_t NumRelocs;
// Used by the garbage collector.
bool Live;
@@ -222,13 +229,40 @@ private:
uint32_t Class[2] = {0, 0};
};
+// This class is used to implement an lld-specific feature (not implemented in
+// MSVC) that minimizes the output size by finding string literals sharing tail
+// parts and merging them.
+//
+// If string tail merging is enabled and a section is identified as containing a
+// string literal, it is added to a MergeChunk with an appropriate alignment.
+// The MergeChunk then tail merges the strings using the StringTableBuilder
+// class and assigns RVAs and section offsets to each of the member chunks based
+// on the offsets assigned by the StringTableBuilder.
+class MergeChunk : public Chunk {
+public:
+ MergeChunk(uint32_t Alignment);
+ static void addSection(SectionChunk *C);
+ void finalizeContents() override;
+
+ uint32_t getOutputCharacteristics() const override;
+ StringRef getSectionName() const override { return ".rdata"; }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ static std::map<uint32_t, MergeChunk *> Instances;
+ std::vector<SectionChunk *> Sections;
+
+private:
+ llvm::StringTableBuilder Builder;
+};
+
// 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;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".bss"; }
private:
@@ -320,17 +354,41 @@ private:
Defined *Sym;
};
-// Windows-specific.
-// A chunk for SEH table which contains RVAs of safe exception handler
-// functions. x86-only.
-class SEHTableChunk : public Chunk {
+// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
+// offset into the chunk. Order does not matter as the RVA table will be sorted
+// later.
+struct ChunkAndOffset {
+ Chunk *InputChunk;
+ uint32_t Offset;
+
+ struct DenseMapInfo {
+ static ChunkAndOffset getEmptyKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};
+ }
+ static ChunkAndOffset getTombstoneKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
+ }
+ static unsigned getHashValue(const ChunkAndOffset &CO) {
+ return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
+ {CO.InputChunk, CO.Offset});
+ }
+ static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
+ return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
+ }
+ };
+};
+
+using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
+
+// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
+class RVATableChunk : public Chunk {
public:
- explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {}
+ explicit RVATableChunk(SymbolRVASet 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;
+ SymbolRVASet Syms;
};
// Windows-specific.
@@ -362,4 +420,10 @@ void applyBranch24T(uint8_t *Off, int32_t V);
} // namespace coff
} // namespace lld
+namespace llvm {
+template <>
+struct DenseMapInfo<lld::coff::ChunkAndOffset>
+ : lld::coff::ChunkAndOffset::DenseMapInfo {};
+}
+
#endif
diff --git a/COFF/Config.h b/COFF/Config.h
index 93bef23a97f0..3ae50b868333 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_COFF_CONFIG_H
#define LLD_COFF_CONFIG_H
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CachePruning.h"
@@ -71,6 +72,12 @@ enum class DebugType {
Fixup = 0x4, /// Relocation Table
};
+enum class GuardCFLevel {
+ Off,
+ NoLongJmp, // Emit gfids but no longjmp tables
+ Full, // Enable all protections.
+};
+
// Global configuration.
struct Configuration {
enum ManifestKind { SideBySide, Embed, No };
@@ -85,13 +92,19 @@ struct Configuration {
std::string ImportName;
bool DoGC = true;
bool DoICF = true;
+ bool TailMerge;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool DebugDwarf = false;
bool DebugGHashes = false;
+ bool DebugSymtab = false;
+ bool ShowTiming = false;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+ std::vector<std::string> NatvisFiles;
+ llvm::SmallString<128> PDBAltPath;
llvm::SmallString<128> PDBPath;
+ llvm::SmallString<128> PDBSourcePath;
std::vector<llvm::StringRef> Argv;
// Symbols in this set are considered as live by the garbage collector.
@@ -110,15 +123,18 @@ struct Configuration {
bool SaveTemps = false;
+ // /guard:cf
+ GuardCFLevel GuardCF = GuardCFLevel::Off;
+
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
// Used for /opt:lldlto=N
- unsigned LTOOptLevel = 2;
+ unsigned LTOO = 2;
// Used for /opt:lldltojobs=N
- unsigned LTOJobs = 0;
+ unsigned ThinLTOJobs = 0;
// Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1;
@@ -152,6 +168,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
+ // Used for /order.
+ llvm::StringMap<int> Order;
+
// Used for /lldmap.
std::string MapFile;
@@ -164,7 +183,7 @@ struct Configuration {
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
- bool CanExitEarly = false;
+ uint32_t Timestamp = 0;
bool DynamicBase = true;
bool AllowBind = true;
bool NxCompat = true;
@@ -174,7 +193,12 @@ struct Configuration {
bool HighEntropyVA = false;
bool AppContainer = false;
bool MinGW = false;
+ bool WarnMissingOrderSymbol = true;
bool WarnLocallyDefinedImported = true;
+ bool Incremental = true;
+ bool IntegrityCheck = false;
+ bool KillAt = false;
+ bool Repro = false;
};
extern Configuration *Config;
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
index 195839139670..464abe8e0894 100644
--- a/COFF/DLL.cpp
+++ b/COFF/DLL.cpp
@@ -18,8 +18,8 @@
//
//===----------------------------------------------------------------------===//
-#include "Chunks.h"
#include "DLL.h"
+#include "Chunks.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
diff --git a/COFF/DLL.h b/COFF/DLL.h
index ad312789edf1..c5d6e7c93abf 100644
--- a/COFF/DLL.h
+++ b/COFF/DLL.h
@@ -76,6 +76,11 @@ class EdataContents {
public:
EdataContents();
std::vector<Chunk *> Chunks;
+
+ uint64_t getRVA() { return Chunks[0]->getRVA(); }
+ uint64_t getSize() {
+ return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
+ }
};
} // namespace coff
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 1aaec355c7a5..eefdb48beadd 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -9,14 +9,18 @@
#include "Driver.h"
#include "Config.h"
+#include "ICF.h"
#include "InputFiles.h"
+#include "MarkLive.h"
#include "MinGW.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
+#include "lld/Common/Args.h"
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
@@ -35,9 +39,8 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
#include <algorithm>
-#include <memory>
-
#include <future>
+#include <memory>
using namespace llvm;
using namespace llvm::object;
@@ -47,19 +50,20 @@ using llvm::sys::Process;
namespace lld {
namespace coff {
+static Timer InputFileTimer("Input File Reading", Timer::root());
+
Configuration *Config;
LinkerDriver *Driver;
bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorOS = &Diag;
errorHandler().ColorDiagnostics = Diag.has_colors();
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now"
- " (use /ERRORLIMIT:0 to see all errors)";
+ " (use /errorlimit:0 to see all errors)";
+ errorHandler().ExitEarly = CanExitEarly;
Config = make<Configuration>();
- Config->Argv = {Args.begin(), Args.end()};
- Config->CanExitEarly = CanExitEarly;
Symtab = make<SymbolTable>();
@@ -71,6 +75,9 @@ bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
exitLld(errorCount() ? 1 : 0);
freeArena();
+ ObjFile::Instances.clear();
+ ImportFile::Instances.clear();
+ BitcodeFile::Instances.clear();
return !errorCount();
}
@@ -92,7 +99,7 @@ typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair;
// Create a std::future that opens and maps a file using the best strategy for
// the host platform.
static std::future<MBErrPair> createFutureForFile(std::string Path) {
-#if LLVM_ON_WIN32
+#if _WIN32
// On Windows, file I/O is relatively slow so it is best to do this
// asynchronously.
auto Strategy = std::launch::async;
@@ -100,7 +107,9 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) {
auto Strategy = std::launch::deferred;
#endif
return std::async(Strategy, [=]() {
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
if (!MBOrErr)
return MBErrPair{nullptr, MBOrErr.getError()};
return MBErrPair{std::move(*MBOrErr), std::error_code()};
@@ -119,39 +128,46 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB,
bool WholeArchive) {
+ StringRef Filename = MB->getBufferIdentifier();
+
MemoryBufferRef MBRef = takeBuffer(std::move(MB));
- FilePaths.push_back(MBRef.getBufferIdentifier());
+ FilePaths.push_back(Filename);
// File type is detected by contents, not by file extension.
switch (identify_magic(MBRef.getBuffer())) {
case file_magic::windows_resource:
Resources.push_back(MBRef);
break;
-
case file_magic::archive:
if (WholeArchive) {
std::unique_ptr<Archive> File =
- CHECK(Archive::create(MBRef),
- MBRef.getBufferIdentifier() + ": failed to parse archive");
+ CHECK(Archive::create(MBRef), Filename + ": failed to parse archive");
for (MemoryBufferRef M : getArchiveMembers(File.get()))
- addArchiveBuffer(M, "<whole-archive>", MBRef.getBufferIdentifier());
+ addArchiveBuffer(M, "<whole-archive>", Filename);
return;
}
Symtab->addFile(make<ArchiveFile>(MBRef));
break;
-
case file_magic::bitcode:
Symtab->addFile(make<BitcodeFile>(MBRef));
break;
-
+ case file_magic::coff_object:
+ case file_magic::coff_import_library:
+ Symtab->addFile(make<ObjFile>(MBRef));
+ break;
case file_magic::coff_cl_gl_object:
- error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
- "Recompile without /GL");
+ error(Filename + ": is not a native COFF file. Recompile without /GL");
break;
-
+ case file_magic::pecoff_executable:
+ if (Filename.endswith_lower(".dll")) {
+ error(Filename + ": bad file type. Did you specify a DLL instead of an "
+ "import library?");
+ break;
+ }
+ LLVM_FALLTHROUGH;
default:
- Symtab->addFile(make<ObjFile>(MBRef));
+ error(MBRef.getBufferIdentifier() + ": unknown file type");
break;
}
}
@@ -227,7 +243,29 @@ static bool isDecorated(StringRef Sym) {
void LinkerDriver::parseDirectives(StringRef S) {
ArgParser Parser;
// .drectve is always tokenized using Windows shell rules.
- opt::InputArgList Args = Parser.parseDirectives(S);
+ // /EXPORT: option can appear too many times, processing in fastpath.
+ opt::InputArgList Args;
+ std::vector<StringRef> Exports;
+ std::tie(Args, Exports) = Parser.parseDirectives(S);
+
+ for (StringRef E : Exports) {
+ // If a common header file contains dllexported function
+ // declarations, many object files may end up with having the
+ // same /EXPORT options. In order to save cost of parsing them,
+ // we dedup them first.
+ if (!DirectivesExports.insert(E).second)
+ continue;
+
+ Export Exp = parseExport(E);
+ if (Config->Machine == I386 && Config->MinGW) {
+ if (!isDecorated(Exp.Name))
+ Exp.Name = Saver.save("_" + Exp.Name);
+ if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName))
+ Exp.ExtName = Saver.save("_" + Exp.ExtName);
+ }
+ Exp.Directives = true;
+ Config->Exports.push_back(Exp);
+ }
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
@@ -244,25 +282,6 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_entry:
Config->Entry = addUndefined(mangle(Arg->getValue()));
break;
- case OPT_export: {
- // If a common header file contains dllexported function
- // declarations, many object files may end up with having the
- // same /EXPORT options. In order to save cost of parsing them,
- // we dedup them first.
- if (!DirectivesExports.insert(Arg->getValue()).second)
- break;
-
- Export E = parseExport(Arg->getValue());
- if (Config->Machine == I386 && Config->MinGW) {
- if (!isDecorated(E.Name))
- E.Name = Saver.save("_" + E.Name);
- if (!E.ExtName.empty() && !isDecorated(E.ExtName))
- E.ExtName = Saver.save("_" + E.ExtName);
- }
- E.Directives = true;
- Config->Exports.push_back(E);
- break;
- }
case OPT_failifmismatch:
checkFailIfMismatch(Arg->getValue());
break;
@@ -315,13 +334,24 @@ StringRef LinkerDriver::doFindFile(StringRef Filename) {
return Filename;
}
+static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) {
+ sys::fs::UniqueID Ret;
+ if (sys::fs::getUniqueID(Path, Ret))
+ return None;
+ return Ret;
+}
+
// 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;
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) {
+ bool Seen = !VisitedFiles.insert(*ID).second;
+ if (Seen)
+ return None;
+ }
+
if (Path.endswith_lower(".lib"))
VisitedLibs.insert(sys::path::filename(Path));
return Path;
@@ -344,11 +374,14 @@ Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
return None;
if (!VisitedLibs.insert(Filename.lower()).second)
return None;
+
StringRef Path = doFindLib(Filename);
if (Config->NoDefaultLibs.count(Path))
return None;
- if (!VisitedFiles.insert(Path.lower()).second)
- return None;
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ if (!VisitedFiles.insert(*ID).second)
+ return None;
return Path;
}
@@ -383,7 +416,24 @@ StringRef LinkerDriver::mangle(StringRef Sym) {
}
// Windows specific -- find default entry point name.
+//
+// There are four different entry point functions for Windows executables,
+// each of which corresponds to a user-defined "main" function. This function
+// infers an entry point from a user-defined "main" function.
StringRef LinkerDriver::findDefaultEntry() {
+ // As a special case, if /nodefaultlib is given, we directly look for an
+ // entry point. This is because, if no default library is linked, users
+ // need to define an entry point instead of a "main".
+ if (Config->NoDefaultLibAll) {
+ for (StringRef S : {"mainCRTStartup", "wmainCRTStartup",
+ "WinMainCRTStartup", "wWinMainCRTStartup"}) {
+ StringRef Entry = Symtab->findMangle(S);
+ if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry)))
+ return mangle(S);
+ }
+ return "";
+ }
+
// User-defined main functions and their corresponding entry points.
static const char *Entries[][2] = {
{"main", "mainCRTStartup"},
@@ -533,10 +583,49 @@ static void createImportLibrary(bool AsLib) {
Exports.push_back(E2);
}
- auto E = writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports,
- Config->Machine, false);
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+ auto HandleError = [](Error &&E) {
+ handleAllErrors(std::move(E),
+ [](ErrorInfoBase &EIB) { error(EIB.message()); });
+ };
+ std::string LibName = getImportName(AsLib);
+ std::string Path = getImplibPath();
+
+ if (!Config->Incremental) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ // If the import library already exists, replace it only if the contents
+ // have changed.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(
+ Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
+ if (!OldBuf) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ SmallString<128> TmpName;
+ if (std::error_code EC =
+ sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName))
+ fatal("cannot create temporary file for import library " + Path + ": " +
+ EC.message());
+
+ if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine,
+ Config->MinGW)) {
+ HandleError(std::move(E));
+ return;
+ }
+
+ std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(
+ TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
+ if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) {
+ OldBuf->reset();
+ HandleError(errorCodeToError(sys::fs::rename(TmpName, Path)));
+ } else {
+ sys::fs::remove(TmpName);
+ }
}
static void parseModuleDefs(StringRef Path) {
@@ -569,9 +658,18 @@ static void parseModuleDefs(StringRef Path) {
for (COFFShortExport E1 : M.Exports) {
Export E2;
+ // In simple cases, only Name is set. Renamed exports are parsed
+ // and set as "ExtName = Name". If Name has the form "OtherDll.Func",
+ // it shouldn't be a normal exported function but a forward to another
+ // DLL instead. This is supported by both MS and GNU linkers.
+ if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) {
+ E2.Name = Saver.save(E1.ExtName);
+ E2.ForwardTo = Saver.save(E1.Name);
+ Config->Exports.push_back(E2);
+ continue;
+ }
E2.Name = Saver.save(E1.Name);
- if (E1.isWeak())
- E2.ExtName = Saver.save(E1.ExtName);
+ E2.ExtName = Saver.save(E1.ExtName);
E2.Ordinal = E1.Ordinal;
E2.Noname = E1.Noname;
E2.Data = E1.Data;
@@ -634,8 +732,8 @@ filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
log("Creating a temporary archive for " + Path + " to remove bitcode files");
SmallString<128> S;
- if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
- ".lib", S))
+ if (std::error_code EC = sys::fs::createTemporaryFile(
+ "lld-" + sys::path::stem(Path), ".lib", S))
fatal("cannot create a temporary file: " + EC.message());
std::string Temp = S.str();
TemporaryFiles.push_back(Temp);
@@ -711,6 +809,8 @@ void LinkerDriver::enqueueTask(std::function<void()> Task) {
}
bool LinkerDriver::run() {
+ ScopedTimer T(InputFileTimer);
+
bool DidWork = !TaskQueue.empty();
while (!TaskQueue.empty()) {
TaskQueue.front()();
@@ -719,6 +819,46 @@ bool LinkerDriver::run() {
return DidWork;
}
+// Parse an /order file. If an option is given, the linker places
+// COMDAT sections in the same order as their names appear in the
+// given file.
+static void parseOrderFile(StringRef Arg) {
+ // For some reason, the MSVC linker requires a filename to be
+ // preceded by "@".
+ if (!Arg.startswith("@")) {
+ error("malformed /order option: '@' missing");
+ return;
+ }
+
+ // Get a list of all comdat sections for error checking.
+ DenseSet<StringRef> Set;
+ for (Chunk *C : Symtab->getChunks())
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ Set.insert(Sec->Sym->getName());
+
+ // Open a file.
+ StringRef Path = Arg.substr(1);
+ std::unique_ptr<MemoryBuffer> MB = CHECK(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+
+ // Parse a file. An order file contains one symbol per line.
+ // All symbols that were not present in a given order file are
+ // considered to have the lowest priority 0 and are placed at
+ // end of an output section.
+ for (std::string S : args::getLines(MB->getMemBufferRef())) {
+ if (Config->Machine == I386 && !isDecorated(S))
+ S = "_" + S;
+
+ if (Set.count(S) == 0) {
+ if (Config->WarnMissingOrderSymbol)
+ warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]");
+ }
+ else
+ Config->Order[S] = INT_MIN + Config->Order.size();
+ }
+}
+
void LinkerDriver::link(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.
@@ -734,11 +874,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
- InitializeAllDisassemblers();
// Parse command line options.
ArgParser Parser;
- opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+ opt::InputArgList Args = Parser.parseLINK(ArgsArr);
// Parse and evaluate -mllvm options.
std::vector<const char *> V;
@@ -762,6 +901,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
}
+ if (Args.hasArg(OPT_show_timing))
+ Config->ShowTiming = true;
+
+ ScopedTimer T(Timer::root());
// Handle --version, which is an lld extension. This option is a bit odd
// because it doesn't start with "/", but we deliberately chose "--" to
// avoid conflict with /version and for compatibility with clang-cl.
@@ -804,7 +947,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /ignore
for (auto *Arg : Args.filtered(OPT_ignore)) {
- if (StringRef(Arg->getValue()) == "4217")
+ if (StringRef(Arg->getValue()) == "4037")
+ Config->WarnMissingOrderSymbol = false;
+ else if (StringRef(Arg->getValue()) == "4217")
Config->WarnLocallyDefinedImported = false;
// Other warning numbers are ignored.
}
@@ -825,6 +970,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /debug
if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) {
Config->Debug = true;
+ Config->Incremental = true;
if (auto *Arg = Args.getLastArg(OPT_debugtype))
Config->DebugTypes = parseDebugType(Arg->getValue());
else
@@ -833,9 +979,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /pdb
bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash);
- if (ShouldCreatePDB)
+ if (ShouldCreatePDB) {
if (auto *Arg = Args.getLastArg(OPT_pdb))
Config->PDBPath = Arg->getValue();
+ if (auto *Arg = Args.getLastArg(OPT_pdbaltpath))
+ Config->PDBAltPath = Arg->getValue();
+ if (Args.hasArg(OPT_natvis))
+ Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
+
+ if (auto *Arg = Args.getLastArg(OPT_pdb_source_path))
+ Config->PDBSourcePath = Arg->getValue();
+ }
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
@@ -859,6 +1013,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
Config->DynamicBase = false;
+ // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the
+ // default setting for any other project type.", but link.exe defaults to
+ // /FIXED:NO for exe outputs as well. Match behavior, not docs.
bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false);
if (Fixed) {
if (DynamicBaseArg &&
@@ -894,6 +1051,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_stack))
parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+ // Handle /guard:cf
+ if (auto *Arg = Args.getLastArg(OPT_guard))
+ parseGuard(Arg->getValue());
+
// Handle /heap
if (auto *Arg = Args.getLastArg(OPT_heap))
parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
@@ -908,6 +1069,23 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
&Config->MinorOSVersion);
+ // Handle /timestamp
+ if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) {
+ if (Arg->getOption().getID() == OPT_repro) {
+ Config->Timestamp = 0;
+ Config->Repro = true;
+ } else {
+ Config->Repro = false;
+ StringRef Value(Arg->getValue());
+ if (Value.getAsInteger(0, Config->Timestamp))
+ fatal(Twine("invalid timestamp: ") + Value +
+ ". Expected 32-bit integer");
+ }
+ } else {
+ Config->Repro = false;
+ Config->Timestamp = time(nullptr);
+ }
+
// Handle /alternatename
for (auto *Arg : Args.filtered(OPT_alternatename))
parseAlternateName(Arg->getValue());
@@ -921,8 +1099,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->Implib = Arg->getValue();
// Handle /opt.
- bool DoGC = !Args.hasArg(OPT_debug);
- unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on
+ bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile);
+ unsigned ICFLevel =
+ Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
+ unsigned TailMerge = 1;
for (auto *Arg : Args.filtered(OPT_opt)) {
std::string Str = StringRef(Arg->getValue()).lower();
SmallVector<StringRef, 1> Vec;
@@ -936,14 +1116,18 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
ICFLevel = 2;
} else if (S == "noicf") {
ICFLevel = 0;
+ } else if (S == "lldtailmerge") {
+ TailMerge = 2;
+ } else if (S == "nolldtailmerge") {
+ TailMerge = 0;
} else if (S.startswith("lldlto=")) {
StringRef OptLevel = S.substr(7);
- if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
- Config->LTOOptLevel > 3)
+ if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3)
error("/opt:lldlto: invalid optimization level: " + OptLevel);
} else if (S.startswith("lldltojobs=")) {
StringRef Jobs = S.substr(11);
- if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
+ if (Jobs.getAsInteger(10, Config->ThinLTOJobs) ||
+ Config->ThinLTOJobs == 0)
error("/opt:lldltojobs: invalid job count: " + Jobs);
} else if (S.startswith("lldltopartitions=")) {
StringRef N = S.substr(17);
@@ -964,11 +1148,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
ICFLevel = 0;
Config->DoGC = DoGC;
Config->DoICF = ICFLevel > 0;
+ Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2;
// Handle /lldsavetemps
if (Args.hasArg(OPT_lldsavetemps))
Config->SaveTemps = true;
+ // Handle /kill-at
+ if (Args.hasArg(OPT_kill_at))
+ Config->KillAt = true;
+
// Handle /lldltocache
if (auto *Arg = Args.getLastArg(OPT_lldltocache))
Config->LTOCache = Arg->getValue();
@@ -987,6 +1176,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
for (auto *Arg : Args.filtered(OPT_merge))
parseMerge(Arg->getValue());
+ // Add default section merging rules after user rules. User rules take
+ // precedence, but we will emit a warning if there is a conflict.
+ parseMerge(".idata=.rdata");
+ parseMerge(".didat=.rdata");
+ parseMerge(".edata=.rdata");
+ parseMerge(".xdata=.rdata");
+ parseMerge(".bss=.data");
+
// Handle /section
for (auto *Arg : Args.filtered(OPT_section))
parseSection(Arg->getValue());
@@ -1024,39 +1221,77 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (!Config->ManifestInput.empty() &&
Config->Manifest != Configuration::Embed) {
- fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED");
+ fatal("/manifestinput: requires /manifest:embed");
}
// Handle miscellaneous boolean flags.
Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
Config->AllowIsolation =
Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
+ Config->Incremental =
+ Args.hasFlag(OPT_incremental, OPT_incremental_no,
+ !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) &&
+ !Args.hasArg(OPT_profile));
+ Config->IntegrityCheck =
+ Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
- Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
+ Config->TerminalServerAware =
+ !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf);
Config->DebugGHashes = Args.hasArg(OPT_debug_ghash);
+ Config->DebugSymtab = Args.hasArg(OPT_debug_symtab);
Config->MapFile = getMapFile(Args);
+ if (Config->Incremental && Args.hasArg(OPT_profile)) {
+ warn("ignoring '/incremental' due to '/profile' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Args.hasArg(OPT_order)) {
+ warn("ignoring '/incremental' due to '/order' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoGC) {
+ warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoICF) {
+ warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
if (errorCount())
return;
- bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag);
+ std::set<sys::fs::UniqueID> WholeArchives;
+ for (auto *Arg : Args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path))
+ WholeArchives.insert(*ID);
+
+ // A predicate returning true if a given path is an argument for
+ // /wholearchive:, or /wholearchive is enabled globally.
+ // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"
+ // needs to be handled as "/wholearchive:foo.obj foo.obj".
+ auto IsWholeArchive = [&](StringRef Path) -> bool {
+ if (Args.hasArg(OPT_wholearchive_flag))
+ return true;
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ return WholeArchives.count(*ID);
+ return false;
+ };
+
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
- std::vector<MemoryBufferRef> MBs;
- for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) {
- switch (Arg->getOption().getID()) {
- case OPT_INPUT:
- if (Optional<StringRef> Path = findFile(Arg->getValue()))
- enqueuePath(*Path, WholeArchiveFlag);
- break;
- case OPT_wholearchive_file:
- if (Optional<StringRef> Path = findFile(Arg->getValue()))
- enqueuePath(*Path, true);
- break;
- }
- }
+ for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file))
+ if (Optional<StringRef> Path = findFile(Arg->getValue()))
+ enqueuePath(*Path, IsWholeArchive(*Path));
+
for (auto *Arg : Args.filtered(OPT_defaultlib))
if (Optional<StringRef> Path = findLib(Arg->getValue()))
enqueuePath(*Path, false);
@@ -1160,10 +1395,24 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
}
- // Put the PDB next to the image if no /pdb flag was passed.
- if (ShouldCreatePDB && Config->PDBPath.empty()) {
- Config->PDBPath = Config->OutputFile;
- sys::path::replace_extension(Config->PDBPath, ".pdb");
+ if (ShouldCreatePDB) {
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // The embedded PDB path should be the absolute path to the PDB if no
+ // /pdbaltpath flag was passed.
+ if (Config->PDBAltPath.empty()) {
+ Config->PDBAltPath = Config->PDBPath;
+
+ // It's important to make the path absolute and remove dots. This path
+ // will eventually be written into the PE header, and certain Microsoft
+ // tools won't work correctly if these assumptions are not held.
+ sys::fs::make_absolute(Config->PDBAltPath);
+ sys::path::remove_dots(Config->PDBAltPath);
+ }
}
// Set default image base if /base is not given.
@@ -1176,11 +1425,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Symtab->addAbsolute("___safe_se_handler_count", 0);
}
- // We do not support /guard:cf (control flow protection) yet.
- // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
Symtab->addAbsolute(mangle("__guard_fids_count"), 0);
Symtab->addAbsolute(mangle("__guard_fids_table"), 0);
- Symtab->addAbsolute(mangle("__guard_flags"), 0x100);
+ Symtab->addAbsolute(mangle("__guard_flags"), 0);
Symtab->addAbsolute(mangle("__guard_iat_count"), 0);
Symtab->addAbsolute(mangle("__guard_iat_table"), 0);
Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
@@ -1255,7 +1502,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /safeseh.
if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
for (ObjFile *File : ObjFile::Instances)
- if (!File->SEHCompat)
+ if (!File->hasSafeSEH())
error("/safeseh: " + File->getName() + " is not compatible with SEH");
if (errorCount())
return;
@@ -1275,7 +1522,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
E.Name = Def->getName();
E.Sym = Def;
if (Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
E.Data = true;
Config->Exports.push_back(E);
});
@@ -1318,6 +1565,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Config->Manifest == Configuration::SideBySide)
createSideBySideManifest();
+ // Handle /order. We want to do this at this moment because we
+ // need a complete list of comdat sections to warn on nonexistent
+ // functions.
+ if (auto *Arg = Args.getLastArg(OPT_order))
+ parseOrderFile(Arg->getValue());
+
// Identify unreferenced COMDAT sections.
if (Config->DoGC)
markLive(Symtab->getChunks());
@@ -1328,6 +1581,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Write the result.
writeResult();
+
+ // Stop early so we can print the results.
+ Timer::root().stop();
+ if (Config->ShowTiming)
+ Timer::root().print();
}
} // namespace coff
diff --git a/COFF/Driver.h b/COFF/Driver.h
index 3f7fad1038f3..627e991a9028 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -21,6 +21,7 @@
#include "llvm/Object/COFF.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TarWriter.h"
#include <memory>
#include <set>
@@ -36,12 +37,6 @@ using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using llvm::Optional;
-// Implemented in MarkLive.cpp.
-void markLive(ArrayRef<Chunk *> Chunks);
-
-// Implemented in ICF.cpp.
-void doICF(ArrayRef<Chunk *> Chunks);
-
class COFFOptTable : public llvm::opt::OptTable {
public:
COFFOptTable();
@@ -56,8 +51,10 @@ public:
llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
// Tokenizes a given string and then parses as command line options in
- // .drectve section.
- llvm::opt::InputArgList parseDirectives(StringRef S);
+ // .drectve section. /EXPORT options are returned in second element
+ // to be processed in fastpath.
+ std::pair<llvm::opt::InputArgList, std::vector<StringRef>>
+ parseDirectives(StringRef S);
private:
// Parses command line options.
@@ -98,7 +95,11 @@ private:
// Library search path. The first element is always "" (current directory).
std::vector<StringRef> SearchPaths;
- std::set<std::string> VisitedFiles;
+
+ // We don't want to add the same file more than once.
+ // Files are uniquified by their filesystem and file number.
+ std::set<llvm::sys::fs::UniqueID> VisitedFiles;
+
std::set<std::string> VisitedLibs;
Symbol *addUndefined(StringRef Sym);
@@ -143,6 +144,8 @@ StringRef machineToStr(MachineTypes MT);
// Parses a string in the form of "<integer>[,<integer>]".
void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+void parseGuard(StringRef Arg);
+
// 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);
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index e0641e04a017..c12e791f9507 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -61,12 +61,7 @@ public:
StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
- std::vector<const char *> Vec;
- for (StringRef S : Args)
- Vec.push_back(S.data());
- Vec.push_back(nullptr);
-
- if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+ if (sys::ExecuteAndWait(Args[0], Args) != 0)
fatal("ExecuteAndWait failed: " +
llvm::join(Args.begin(), Args.end(), " "));
}
@@ -128,6 +123,21 @@ void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
fatal("invalid number: " + S2);
}
+void parseGuard(StringRef FullArg) {
+ SmallVector<StringRef, 1> SplitArgs;
+ FullArg.split(SplitArgs, ",");
+ for (StringRef Arg : SplitArgs) {
+ if (Arg.equals_lower("no"))
+ Config->GuardCF = GuardCFLevel::Off;
+ else if (Arg.equals_lower("nolongjmp"))
+ Config->GuardCF = GuardCFLevel::NoLongJmp;
+ else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
+ Config->GuardCF = GuardCFLevel::Full;
+ else
+ fatal("invalid argument to /guard: " + Arg);
+ }
+}
+
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
uint32_t *Minor) {
@@ -170,6 +180,10 @@ void parseMerge(StringRef S) {
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
fatal("/merge: invalid argument: " + S);
+ if (From == ".rsrc" || To == ".rsrc")
+ fatal("/merge: cannot merge '.rsrc' with any section");
+ if (From == ".reloc" || To == ".reloc")
+ fatal("/merge: cannot merge '.reloc' with any section");
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
@@ -418,15 +432,15 @@ static std::string createManifestXml() {
return createManifestXmlWithExternalMt(DefaultXml);
}
-static std::unique_ptr<MemoryBuffer>
+static std::unique_ptr<WritableMemoryBuffer>
createMemoryBufferForManifestRes(size_t ManifestSize) {
size_t ResSize = alignTo(
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix) + ManifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return MemoryBuffer::getNewMemBuffer(ResSize,
- Config->OutputFile + ".manifest.res");
+ return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile +
+ ".manifest.res");
}
static void writeResFileHeader(char *&Buf) {
@@ -465,16 +479,16 @@ static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
std::unique_ptr<MemoryBuffer> createManifestRes() {
std::string Manifest = createManifestXml();
- std::unique_ptr<MemoryBuffer> Res =
+ std::unique_ptr<WritableMemoryBuffer> Res =
createMemoryBufferForManifestRes(Manifest.size());
- char *Buf = const_cast<char *>(Res->getBufferStart());
+ char *Buf = Res->getBufferStart();
writeResFileHeader(Buf);
writeResEntryHeader(Buf, Manifest.size());
// Copy the manifest data into the .res file.
std::copy(Manifest.begin(), Manifest.end(), Buf);
- return Res;
+ return std::move(Res);
}
void createSideBySideManifest() {
@@ -558,9 +572,35 @@ err:
static StringRef undecorate(StringRef Sym) {
if (Config->Machine != I386)
return Sym;
+ // In MSVC mode, a fully decorated stdcall function is exported
+ // as-is with the leading underscore (with type IMPORT_NAME).
+ // In MinGW mode, a decorated stdcall function gets the underscore
+ // removed, just like normal cdecl functions.
+ if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW)
+ return Sym;
return Sym.startswith("_") ? Sym.substr(1) : Sym;
}
+// Convert stdcall/fastcall style symbols into unsuffixed symbols,
+// with or without a leading underscore. (MinGW specific.)
+static StringRef killAt(StringRef Sym, bool Prefix) {
+ if (Sym.empty())
+ return Sym;
+ // Strip any trailing stdcall suffix
+ Sym = Sym.substr(0, Sym.find('@', 1));
+ if (!Sym.startswith("@")) {
+ if (Prefix && !Sym.startswith("_"))
+ return Saver.save("_" + Sym);
+ return Sym;
+ }
+ // For fastcall, remove the leading @ and replace it with an
+ // underscore, if prefixes are used.
+ Sym = Sym.substr(1);
+ if (Prefix)
+ Sym = Saver.save("_" + Sym);
+ return Sym;
+}
+
// Performs error checking on all /export arguments.
// It also sets ordinals.
void fixupExports() {
@@ -593,6 +633,15 @@ void fixupExports() {
}
}
+ if (Config->KillAt && Config->Machine == I386) {
+ for (Export &E : Config->Exports) {
+ E.Name = killAt(E.Name, true);
+ E.ExportName = killAt(E.ExportName, false);
+ E.ExtName = killAt(E.ExtName, true);
+ E.SymbolName = killAt(E.SymbolName, true);
+ }
+ }
+
// Uniquefy by name.
DenseMap<StringRef, Export *> Map(Config->Exports.size());
std::vector<Export> V;
@@ -702,6 +751,28 @@ static const llvm::opt::OptTable::Info InfoTable[] = {
COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+// Set color diagnostics according to --color-diagnostics={auto,always,never}
+// or --no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
@@ -720,50 +791,73 @@ opt::InputArgList ArgParser::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 = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
- Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size());
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
+ Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex,
+ MissingCount);
// Print the real command line if response files are expanded.
- if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) {
+ if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) {
std::string Msg = "Command line:";
- for (const char *S : Vec)
+ for (const char *S : ExpandedArgv)
Msg += " " + std::string(S);
message(Msg);
}
+ // Save the command line after response file expansion so we can write it to
+ // the PDB if necessary.
+ Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()};
+
// Handle /WX early since it converts missing argument warnings to errors.
errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ handleColorDiagnostics(Args);
+
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
+
+ if (Args.hasArg(OPT_lib))
+ warn("ignoring /lib since it's not the first argument");
+
return Args;
}
// Tokenizes and parses a given string as command line in .drective section.
-opt::InputArgList ArgParser::parseDirectives(StringRef S) {
- // Make InputArgList from string vectors.
+// /EXPORT options are processed in fastpath.
+std::pair<opt::InputArgList, std::vector<StringRef>>
+ArgParser::parseDirectives(StringRef S) {
+ std::vector<StringRef> Exports;
+ SmallVector<const char *, 16> Rest;
+
+ for (StringRef Tok : tokenize(S)) {
+ if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
+ Exports.push_back(Tok.substr(strlen("/export:")));
+ else
+ Rest.push_back(Tok.data());
+ }
+
+ // Make InputArgList from unparsed string vectors.
unsigned MissingIndex;
unsigned MissingCount;
- opt::InputArgList Args =
- Table.ParseArgs(tokenize(S), MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
- return Args;
+ return {std::move(Args), std::move(Exports)};
}
// link.exe has an interesting feature. If LINK or _LINK_ environment
@@ -773,11 +867,11 @@ opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
// Concatenate LINK env and command line arguments, and then parse them.
if (Optional<std::string> S = Process::GetEnv("LINK")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
return parse(Argv);
}
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 48895c34886c..629720901ab8 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -18,9 +18,11 @@
//
//===----------------------------------------------------------------------===//
+#include "ICF.h"
#include "Chunks.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Parallel.h"
@@ -34,6 +36,8 @@ using namespace llvm;
namespace lld {
namespace coff {
+static Timer ICFTimer("ICF", Timer::root());
+
class ICF {
public:
void run(ArrayRef<Chunk *> V);
@@ -41,6 +45,8 @@ public:
private:
void segregate(size_t Begin, size_t End, bool Constant);
+ bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+
bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
@@ -61,8 +67,8 @@ private:
// Returns a hash value for S.
uint32_t ICF::getHash(SectionChunk *C) {
- return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs,
- C->Alignment, uint32_t(C->Header->SizeOfRawData),
+ return hash_combine(C->getOutputCharacteristics(), C->SectionName,
+ C->Relocs.size(), uint32_t(C->Header->SizeOfRawData),
C->Checksum, C->getContents());
}
@@ -73,21 +79,27 @@ uint32_t ICF::getHash(SectionChunk *C) {
// 2017) says that /opt:icf folds both functions and read-only data.
// Despite that, the MSVC linker folds only functions. We found
// a few instances of programs that are not safe for data merging.
-// Therefore, we merge only functions just like the MSVC tool. However, we merge
-// identical .xdata sections, because the address of unwind information is
-// insignificant to the user program and the Visual C++ linker does this.
+// Therefore, we merge only functions just like the MSVC tool. However, we also
+// merge read-only sections in a couple of cases where the address of the
+// section is insignificant to the user program and the behaviour matches that
+// of the Visual C++ linker.
bool ICF::isEligible(SectionChunk *C) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
- bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!C->isCOMDAT() || !C->isLive() || Writable)
return false;
// Code sections are eligible.
- if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ return true;
+
+ // .pdata and .xdata unwind info sections are eligible.
+ StringRef OutSecName = C->getSectionName().split('$').first;
+ if (OutSecName == ".pdata" || OutSecName == ".xdata")
return true;
- // .xdata unwind info sections are eligble.
- return C->getSectionName().split('$').first == ".xdata";
+ // So are vtables.
+ return C->Sym && C->Sym->getName().startswith("??_7");
}
// Split an equivalence class into smaller classes.
@@ -116,10 +128,23 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) {
}
}
+// Returns true if two sections' associative children are equal.
+bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
+ auto ChildClasses = [&](const SectionChunk *SC) {
+ std::vector<uint32_t> Classes;
+ for (const SectionChunk *C : SC->children())
+ if (!C->SectionName.startswith(".debug") &&
+ C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y")
+ Classes.push_back(C->Class[Cnt % 2]);
+ return Classes;
+ };
+ return ChildClasses(A) == ChildClasses(B);
+}
+
// Compare "non-moving" part of two sections, namely everything
// except relocation targets.
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
- if (A->NumRelocs != B->NumRelocs)
+ if (A->Relocs.size() != B->Relocs.size())
return false;
// Compare relocations.
@@ -142,10 +167,11 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
return false;
// Compare section attributes and contents.
- return A->getPermissions() == B->getPermissions() &&
- A->SectionName == B->SectionName && A->Alignment == B->Alignment &&
+ return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
+ A->SectionName == B->SectionName &&
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
- A->Checksum == B->Checksum && A->getContents() == B->getContents();
+ A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
+ assocEquals(A, B);
}
// Compare "moving" part of two sections, namely relocation targets.
@@ -161,9 +187,12 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
return false;
};
- return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+ return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
+ Eq) &&
+ assocEquals(A, B);
}
+// Find the first Chunk after Begin that has a different class from Begin.
size_t ICF::findBoundary(size_t Begin, size_t End) {
for (size_t I = Begin + 1; I < End; ++I)
if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
@@ -173,11 +202,8 @@ size_t ICF::findBoundary(size_t Begin, size_t End) {
void ICF::forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn) {
- if (Begin > 0)
- Begin = findBoundary(Begin - 1, End);
-
while (Begin < End) {
- size_t Mid = findBoundary(Begin, Chunks.size());
+ size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
}
@@ -193,12 +219,22 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
return;
}
- // Split sections into 256 shards and call Fn in parallel.
- size_t NumShards = 256;
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
size_t Step = Chunks.size() / NumShards;
- for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) {
- size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step;
- forEachClassRange(I * Step, End, Fn);
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Chunks.size();
+ for_each_n(parallel::par, size_t(1), NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size());
+ });
+ for_each_n(parallel::par, size_t(1), NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I]) {
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
+ }
});
++Cnt;
}
@@ -207,6 +243,8 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Two sections are considered the same if their section headers,
// contents and relocations are all the same.
void ICF::run(ArrayRef<Chunk *> Vec) {
+ ScopedTimer T(ICFTimer);
+
// Collect only mergeable sections and group by hash value.
uint32_t NextId = 1;
for (Chunk *C : Vec) {
@@ -218,6 +256,12 @@ void ICF::run(ArrayRef<Chunk *> Vec) {
}
}
+ // Make sure that ICF doesn't merge sections that are being handled by string
+ // tail merging.
+ for (auto &P : MergeChunk::Instances)
+ for (SectionChunk *SC : P.second->Sections)
+ SC->Class[0] = NextId++;
+
// Initially, we use hash values to partition sections.
for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) {
// Set MSB to 1 to avoid collisions with non-hash classs.
diff --git a/COFF/Strings.h b/COFF/ICF.h
index 67fc1c773c66..9c54e0c9ec2d 100644
--- a/COFF/Strings.h
+++ b/COFF/ICF.h
@@ -1,4 +1,4 @@
-//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//===- ICF.h --------------------------------------------------------------===//
//
// The LLVM Linker
//
@@ -7,17 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLD_COFF_STRINGS_H
-#define LLD_COFF_STRINGS_H
+#ifndef LLD_COFF_ICF_H
+#define LLD_COFF_ICF_H
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include <string>
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
namespace lld {
namespace coff {
-llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
-}
-}
+
+class Chunk;
+
+void doICF(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
#endif
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index a8f52e0391f7..2b3e65fae04b 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Target/TargetOptions.h"
#include <cstring>
#include <system_error>
@@ -138,12 +139,13 @@ void ObjFile::initializeChunks() {
if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT)
SparseChunks[I] = PendingComdat;
else
- SparseChunks[I] = readSection(I, nullptr);
+ SparseChunks[I] = readSection(I, nullptr, "");
}
}
SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
- const coff_aux_section_definition *Def) {
+ const coff_aux_section_definition *Def,
+ StringRef LeaderName) {
const coff_section *Sec;
StringRef Name;
if (auto EC = COFFObj->getSection(SectionNumber, Sec))
@@ -151,15 +153,7 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
if (auto EC = COFFObj->getSectionName(Sec, Name))
fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
EC.message());
- if (Name == ".sxdata") {
- ArrayRef<uint8_t> Data;
- COFFObj->getSectionContents(Sec, Data);
- if (Data.size() % 4 != 0)
- fatal(".sxdata must be an array of symbol table indices");
- SXData = {reinterpret_cast<const ulittle32_t *>(Data.data()),
- Data.size() / 4};
- return nullptr;
- }
+
if (Name == ".drectve") {
ArrayRef<uint8_t> Data;
COFFObj->getSectionContents(Sec, Data);
@@ -177,8 +171,8 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
// CodeView needs a linker support. We need to interpret and debug
// info, and then write it to a separate .pdb file.
- // Ignore debug info unless /debug is given.
- if (!Config->Debug && Name.startswith(".debug"))
+ // Ignore DWARF debug info unless /debug is given.
+ if (!Config->Debug && Name.startswith(".debug_"))
return nullptr;
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
@@ -191,6 +185,18 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
// linked in the regular manner.
if (C->isCodeView())
DebugChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y")
+ GuardFidChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y")
+ GuardLJmpChunks.push_back(C);
+ else if (Name == ".sxdata")
+ SXDataChunks.push_back(C);
+ else if (Config->TailMerge && Sec->NumberOfRelocations == 0 &&
+ Name == ".rdata" && LeaderName.startswith("??_C@"))
+ // COFF sections that look like string literal sections (i.e. no
+ // relocations, in .rdata, leader symbol name matches the MSVC name mangling
+ // for string literals) are subject to string tail merging.
+ MergeChunk::addSection(C);
else
Chunks.push_back(C);
@@ -211,7 +217,7 @@ void ObjFile::readAssociativeDefinition(
// the section; otherwise mark it as discarded.
int32_t SectionNumber = Sym.getSectionNumber();
if (Parent) {
- SparseChunks[SectionNumber] = readSection(SectionNumber, Def);
+ SparseChunks[SectionNumber] = readSection(SectionNumber, Def, "");
if (SparseChunks[SectionNumber])
Parent->addAssociative(SparseChunks[SectionNumber]);
} else {
@@ -275,6 +281,13 @@ void ObjFile::initializeSymbols() {
if (auto *Def = Sym.getSectionDefinition())
if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
readAssociativeDefinition(Sym, Def);
+ if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ log("comdat section " + Name +
+ " without leader and unassociated, discarding");
+ continue;
+ }
Symbols[I] = createRegular(Sym);
}
@@ -294,43 +307,46 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) {
Optional<Symbol *> ObjFile::createDefined(
COFFSymbolRef Sym,
std::vector<const coff_aux_section_definition *> &ComdatDefs) {
- StringRef Name;
+ auto GetName = [&]() {
+ StringRef S;
+ COFFObj->getSymbolName(Sym, S);
+ return S;
+ };
+
if (Sym.isCommon()) {
auto *C = make<CommonChunk>(Sym);
Chunks.push_back(C);
- COFFObj->getSymbolName(Sym, Name);
- Symbol *S =
- Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
- return S;
+ return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(),
+ C);
}
+
if (Sym.isAbsolute()) {
- COFFObj->getSymbolName(Sym, Name);
+ StringRef Name = GetName();
+
// 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;
+ Feat00Flags = Sym.getValue();
return nullptr;
}
+
if (Sym.isExternal())
return Symtab->addAbsolute(Name, Sym);
- else
- return make<DefinedAbsolute>(Name, Sym);
+ return make<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: " + toString(this));
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to special section " + Twine(SectionNumber));
- // This symbol references a section which is not present in the section
- // header.
if ((uint32_t)SectionNumber >= SparseChunks.size())
- fatal("broken object file: " + toString(this));
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to non-existent section " + Twine(SectionNumber));
// Handle comdat leader symbols.
if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
@@ -338,16 +354,16 @@ Optional<Symbol *> ObjFile::createDefined(
Symbol *Leader;
bool Prevailing;
if (Sym.isExternal()) {
- COFFObj->getSymbolName(Sym, Name);
std::tie(Leader, Prevailing) =
- Symtab->addComdat(this, Name, Sym.getGeneric());
+ Symtab->addComdat(this, GetName(), Sym.getGeneric());
} else {
Leader = make<DefinedRegular>(this, /*Name*/ "", false,
/*IsExternal*/ false, Sym.getGeneric());
Prevailing = true;
}
+
if (Prevailing) {
- SectionChunk *C = readSection(SectionNumber, Def);
+ SectionChunk *C = readSection(SectionNumber, Def, GetName());
SparseChunks[SectionNumber] = C;
C->Sym = cast<DefinedRegular>(Leader);
cast<DefinedRegular>(Leader)->Data = &C->Repl;
@@ -429,7 +445,8 @@ void ImportFile::parse() {
// 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)
- ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine);
+ ThunkSym = Symtab->addImportThunk(
+ Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine);
}
void BitcodeFile::parse() {
@@ -462,7 +479,7 @@ void BitcodeFile::parse() {
} else {
Sym = Symtab->addRegular(this, SymName);
}
- SymbolBodies.push_back(Sym);
+ Symbols.push_back(Sym);
}
Directives = Obj->getCOFFLinkerOpts();
}
@@ -486,10 +503,7 @@ MachineTypes BitcodeFile::getMachineType() {
// 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);
+ return sys::path::filename(Path, sys::path::Style::windows);
}
// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index adedbc2ad7a8..4ee4b363886f 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -110,6 +110,9 @@ public:
MachineTypes getMachineType() override;
ArrayRef<Chunk *> getChunks() { return Chunks; }
ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
+ ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
+ ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
+ ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
// Returns a Symbol object for the SymbolIndex'th symbol in the
@@ -123,13 +126,17 @@ public:
static std::vector<ObjFile *> Instances;
- // True if this object file is compatible with SEH.
- // COFF-specific and x86-only.
- bool SEHCompat = false;
+ // Flags in the absolute @feat.00 symbol if it is present. These usually
+ // indicate if an object was compiled with certain security features enabled
+ // like stack guard, safeseh, /guard:cf, or other things.
+ uint32_t Feat00Flags = 0;
- // The symbol table indexes of the safe exception handlers.
- // COFF-specific and x86-only.
- ArrayRef<llvm::support::ulittle32_t> SXData;
+ // True if this object file is compatible with SEH. COFF-specific and
+ // x86-only. COFF spec 5.10.1. The .sxdata section.
+ bool hasSafeSEH() { return Feat00Flags & 0x1; }
+
+ // True if this file was compiled with /guard:cf.
+ bool hasGuardCF() { return Feat00Flags & 0x800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
@@ -143,7 +150,8 @@ private:
SectionChunk *
readSection(uint32_t SectionNumber,
- const llvm::object::coff_aux_section_definition *Def);
+ const llvm::object::coff_aux_section_definition *Def,
+ StringRef LeaderName);
void readAssociativeDefinition(
COFFSymbolRef COFFSym,
@@ -165,6 +173,15 @@ private:
// CodeView debug info sections.
std::vector<SectionChunk *> DebugChunks;
+ // Chunks containing symbol table indices of exception handlers. Only used for
+ // 32-bit x86.
+ std::vector<SectionChunk *> SXDataChunks;
+
+ // Chunks containing symbol table indices of address taken symbols and longjmp
+ // targets. These are not linked into the final binary when /guard:cf is set.
+ std::vector<SectionChunk *> GuardFidChunks;
+ std::vector<SectionChunk *> GuardLJmpChunks;
+
// 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.
@@ -184,15 +201,14 @@ private:
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef M)
- : InputFile(ImportKind, M), Live(!Config->DoGC) {}
+ explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
static std::vector<ImportFile *> Instances;
- DefinedImportData *ImpSym = nullptr;
- DefinedImportThunk *ThunkSym = nullptr;
+ Symbol *ImpSym = nullptr;
+ Symbol *ThunkSym = nullptr;
std::string DLLName;
private:
@@ -204,12 +220,15 @@ public:
Chunk *Location = nullptr;
// We want to eliminate dllimported symbols if no one actually refers them.
- // This "Live" bit is used to keep track of which import library members
+ // These "Live" bits are used to keep track of which import library members
// are actually in use.
//
// If the Live bit is turned off by MarkLive, Writer will ignore dllimported
- // symbols provided by this import library member.
- bool Live;
+ // symbols provided by this import library member. We also track whether the
+ // imported symbol is used separately from whether the thunk is used in order
+ // to avoid creating unnecessary thunks.
+ bool Live = !Config->DoGC;
+ bool ThunkLive = !Config->DoGC;
};
// Used for LTO.
@@ -217,7 +236,7 @@ class BitcodeFile : public InputFile {
public:
explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
- ArrayRef<Symbol *> getSymbols() { return SymbolBodies; }
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
MachineTypes getMachineType() override;
static std::vector<BitcodeFile *> Instances;
std::unique_ptr<llvm::lto::InputFile> Obj;
@@ -225,7 +244,7 @@ public:
private:
void parse() override;
- std::vector<Symbol *> SymbolBodies;
+ std::vector<Symbol *> Symbols;
};
} // namespace coff
diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp
index fa2a54b61841..93f7ba3f9e4c 100644
--- a/COFF/LTO.cpp
+++ b/COFF/LTO.cpp
@@ -12,6 +12,7 @@
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -40,47 +41,32 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
-}
-
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
-}
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
-static void saveBuffer(StringRef Buffer, const Twine &Path) {
- std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
-}
+ // Always emit a section per function/datum with LTO. LLVM LTO should get most
+ // of the benefit of linker GC, but there are still opportunities for ICF.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
-static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
- Conf.RelocModel = Reloc::Static;
+ C.RelocModel = Reloc::Static;
else
- Conf.RelocModel = Reloc::PIC_;
- Conf.DisableVerify = true;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOOptLevel;
+ C.RelocModel = Reloc::PIC_;
+ C.DisableVerify = true;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
+ checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
lto::ThinBackend Backend;
- if (Config->LTOJobs != 0)
- Backend = lto::createInProcessThinBackend(Config->LTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ if (Config->ThinLTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
Config->LTOPartitions);
}
@@ -119,7 +105,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The /lldltocache option specifies the path to a directory in which to cache
@@ -127,15 +113,15 @@ std::vector<StringRef> BitcodeCompiler::compile() {
// specified, configure LTO to use it as the cache directory.
lto::NativeObjectCache Cache;
if (!Config->LTOCache.empty())
- Cache = check(
- lto::localCache(Config->LTOCache,
- [&](size_t Task, std::unique_ptr<MemoryBuffer> MB,
- StringRef Path) { Files[Task] = std::move(MB); }));
+ Cache = check(lto::localCache(
+ Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
@@ -144,15 +130,15 @@ std::vector<StringRef> BitcodeCompiler::compile() {
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
}
- Ret.emplace_back(Buff[I].data(), Buff[I].size());
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
diff --git a/COFF/LTO.h b/COFF/LTO.h
index a444aa7ac4fe..f00924654780 100644
--- a/COFF/LTO.h
+++ b/COFF/LTO.h
@@ -48,7 +48,7 @@ public:
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
}
diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp
index 717ed3419ea5..6ca1b6647bd7 100644
--- a/COFF/MapFile.cpp
+++ b/COFF/MapFile.cpp
@@ -23,7 +23,6 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
-
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
@@ -37,14 +36,15 @@ using namespace lld::coff;
typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>
SymbolMapTy;
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
+
// Print out the first three columns of a line.
static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
uint64_t Align) {
OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
}
-static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
-
// Returns a list of all symbols that we want to print out.
static std::vector<DefinedRegular *> getSymbols() {
std::vector<DefinedRegular *> V;
@@ -79,7 +79,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
writeHeader(OS, Syms[I]->getRVA(), 0, 0);
- OS << indent(2) << toString(*Syms[I]);
+ OS << Indent16 << toString(*Syms[I]);
});
DenseMap<DefinedRegular *, std::string> Ret;
@@ -108,7 +108,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
// Print out file contents.
for (OutputSection *Sec : OutputSections) {
writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
- OS << Sec->getName() << '\n';
+ OS << Sec->Name << '\n';
for (Chunk *C : Sec->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
@@ -116,7 +116,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
continue;
writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment);
- OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName()
+ OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName()
<< ")\n";
for (DefinedRegular *Sym : SectionSyms[SC])
OS << SymStr[Sym] << '\n';
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
index 01be60d12d82..57ae450a9138 100644
--- a/COFF/MarkLive.cpp
+++ b/COFF/MarkLive.cpp
@@ -9,16 +9,21 @@
#include "Chunks.h"
#include "Symbols.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/STLExtras.h"
#include <vector>
namespace lld {
namespace coff {
+static Timer GCTimer("GC", Timer::root());
+
// 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(ArrayRef<Chunk *> Chunks) {
+ ScopedTimer T(GCTimer);
+
// 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.
@@ -43,7 +48,7 @@ void markLive(ArrayRef<Chunk *> Chunks) {
else if (auto *Sym = dyn_cast<DefinedImportData>(B))
Sym->File->Live = true;
else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
- Sym->WrappedSym->File->Live = true;
+ Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
};
// Add GC root chunks.
diff --git a/COFF/MarkLive.h b/COFF/MarkLive.h
new file mode 100644
index 000000000000..5b652dd48196
--- /dev/null
+++ b/COFF/MarkLive.h
@@ -0,0 +1,24 @@
+//===- MarkLive.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_MARKLIVE_H
+#define LLD_COFF_MARKLIVE_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+
+void markLive(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
+
+#endif // LLD_COFF_MARKLIVE_H
diff --git a/COFF/MinGW.cpp b/COFF/MinGW.cpp
index b7a47165640d..2ca00587331f 100644
--- a/COFF/MinGW.cpp
+++ b/COFF/MinGW.cpp
@@ -138,7 +138,7 @@ void coff::writeDefFile(StringRef Name) {
<< "@" << E.Ordinal;
if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
if (Def && Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
OS << " DATA";
}
OS << "\n";
diff --git a/COFF/Options.td b/COFF/Options.td
index 7d4cdba14f75..871bad8bd655 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -20,6 +20,10 @@ def align : P<"align", "Section alignment">;
def aligncomm : P<"aligncomm", "Set common symbol alignment">;
def alternatename : P<"alternatename", "Define weak alias">;
def base : P<"base", "Base address of the program">;
+def color_diagnostics: Flag<["--"], "color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
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">;
@@ -28,9 +32,12 @@ def errorlimit : P<"errorlimit",
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 guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
def implib : P<"implib", "Import library name">;
+def lib : F<"lib">,
+ HelpText<"Act like lib.exe; must be first argument if present">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">;
@@ -42,12 +49,18 @@ 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 order : P<"order", "Put functions in order">;
def out : P<"out", "Path to file to write output">;
+def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
def pdb : P<"pdb", "PDB file path">;
+def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">;
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 timestamp : P<"timestamp", "Specify the PE header timestamp">;
def version : P<"version", "Specify a version number in the PE header">;
def wholearchive_file : P<"wholearchive", "Include all object files from this archive">;
@@ -72,12 +85,14 @@ def deffile : Joined<["/", "-"], "def:">,
HelpText<"Use module-definition file">;
def debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def debug_full : F<"debug:full">, Alias<debug>;
def debugtype : P<"debugtype", "Debug Info Options">;
def dll : F<"dll">, HelpText<"Create a DLL">;
def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">;
def nodefaultlib_all : F<"nodefaultlib">;
def noentry : F<"noentry">;
def profile : F<"profile">;
+def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">;
def swaprun_cd : F<"swaprun:cd">;
def swaprun_net : F<"swaprun:net">;
def verbose : F<"verbose">;
@@ -102,6 +117,12 @@ defm fixed : B<"fixed", "Disable base relocations",
defm highentropyva : B<"highentropyva",
"Enable 64-bit ASLR (default on 64-bit)",
"Disable 64-bit ASLR">;
+defm incremental : B<"incremental",
+ "Keep original import library if contents are unchanged",
+ "Overwrite import library even if contents are unchanged">;
+defm integritycheck : B<"integritycheck",
+ "Set FORCE_INTEGRITY bit in PE header",
+ "No effect (default)">;
defm largeaddressaware : B<"largeaddressaware",
"Enable large addresses (default on 64-bit)",
"Disable large addresses (default on 32-bit)">;
@@ -120,10 +141,14 @@ def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
def debug_ghash : F<"debug:ghash">;
def debug_dwarf : F<"debug:dwarf">;
+def debug_symtab : F<"debug:symtab">;
def export_all_symbols : F<"export-all-symbols">;
+def kill_at : F<"kill-at">;
def lldmingw : F<"lldmingw">;
def msvclto : F<"msvclto">;
def output_def : Joined<["/", "-"], "output-def:">;
+def pdb_source_path : P<"pdbsourcepath",
+ "Base path used to make relative source file path absolute in PDB">;
def rsp_quoting : Joined<["--"], "rsp-quoting=">,
HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
def dash_dash_version : Flag<["--"], "version">,
@@ -132,6 +157,7 @@ def dash_dash_version : Flag<["--"], "version">,
// Flags for debugging
def lldmap : F<"lldmap">;
def lldmap_file : Joined<["/", "-"], "lldmap:">;
+def show_timing : F<"time">;
//==============================================================================
// The flags below do nothing. They are defined only for link.exe compatibility.
@@ -146,8 +172,6 @@ multiclass QB<string name> {
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">;
@@ -157,8 +181,6 @@ def delay : QF<"delay">;
def errorreport : QF<"errorreport">;
def idlout : QF<"idlout">;
def maxilksize : QF<"maxilksize">;
-def natvis : QF<"natvis">;
-def pdbaltpath : QF<"pdbaltpath">;
def tlbid : QF<"tlbid">;
def tlbout : QF<"tlbout">;
def verbose_all : QF<"verbose">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 91a9a01db569..766bf3f6b456 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -15,7 +15,7 @@
#include "Symbols.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
-#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
+#include "lld/Common/Timer.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
@@ -45,8 +45,10 @@
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Object/CVDebugRecord.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JamCRC.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -61,6 +63,15 @@ using llvm::object::coff_section;
static ExitOnError ExitOnErr;
+static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
+
+static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer);
+static Timer TypeMergingTimer("Type Merging", AddObjectsTimer);
+static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer);
+static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer);
+static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer);
+static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer);
+
namespace {
/// Map from type index and item index in a type server PDB to the
/// corresponding index in the destination PDB.
@@ -74,11 +85,19 @@ class PDBLinker {
public:
PDBLinker(SymbolTable *Symtab)
: Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
- IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {}
+ IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {
+ // This isn't strictly necessary, but link.exe usually puts an empty string
+ // as the first "valid" string in the string table, so we do the same in
+ // order to maintain as much byte-for-byte compatibility as possible.
+ PDBStrTab.insert("");
+ }
/// Emit the basic PDB structure: initial streams, headers, etc.
void initialize(const llvm::codeview::DebugInfo &BuildId);
+ /// Add natvis files specified on the command line.
+ void addNatvisFiles();
+
/// Link CodeView from each object file in the symbol table into the PDB.
void addObjectsToPDB();
@@ -96,18 +115,16 @@ public:
/// If the object does not use a type server PDB (compiled with /Z7), we merge
/// all the type and item records from the .debug$S stream and fill in the
/// caller-provided ObjectIndexMap.
- const CVIndexMap &mergeDebugT(ObjFile *File, CVIndexMap &ObjectIndexMap);
+ Expected<const CVIndexMap&> mergeDebugT(ObjFile *File,
+ CVIndexMap &ObjectIndexMap);
- const CVIndexMap &maybeMergeTypeServerPDB(ObjFile *File,
- TypeServer2Record &TS);
+ Expected<const CVIndexMap&> maybeMergeTypeServerPDB(ObjFile *File,
+ TypeServer2Record &TS);
/// Add the section map and section contributions to the PDB.
void addSections(ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable);
- void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C);
-
/// Write the PDB to disk.
void commit();
@@ -136,10 +153,19 @@ private:
llvm::SmallString<128> NativePath;
+ /// A list of other PDBs which are loaded during the linking process and which
+ /// we need to keep around since the linking operation may reference pointers
+ /// inside of these PDBs.
+ llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs;
+
std::vector<pdb::SecMapEntry> SectionMap;
/// Type index mappings of type server PDBs that we've loaded so far.
std::map<GUID, CVIndexMap> TypeServerIndexMappings;
+
+ /// List of TypeServer PDBs which cannot be loaded.
+ /// Cached to prevent repeated load attempts.
+ std::set<GUID> MissingTypeServerPDBs;
};
}
@@ -179,8 +205,8 @@ static bool canUseDebugH(ArrayRef<uint8_t> DebugH) {
DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
Header->Version == 0 &&
- Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) &&
- (DebugH.size() % 20 == 0);
+ Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
+ (DebugH.size() % 8 == 0);
}
static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
@@ -230,8 +256,10 @@ maybeReadTypeServerRecord(CVTypeArray &Types) {
return std::move(TS);
}
-const CVIndexMap &PDBLinker::mergeDebugT(ObjFile *File,
- CVIndexMap &ObjectIndexMap) {
+Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File,
+ CVIndexMap &ObjectIndexMap) {
+ ScopedTimer T(TypeMergingTimer);
+
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
if (Data.empty())
return ObjectIndexMap;
@@ -304,11 +332,19 @@ tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
return std::move(NS);
}
-const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
- TypeServer2Record &TS) {
- // First, check if we already loaded a PDB with this GUID. Return the type
+Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
+ TypeServer2Record &TS) {
+ const GUID& TSId = TS.getGuid();
+ StringRef TSPath = TS.getName();
+
+ // First, check if the PDB has previously failed to load.
+ if (MissingTypeServerPDBs.count(TSId))
+ return make_error<pdb::GenericError>(
+ pdb::generic_error_code::type_server_not_found, TSPath);
+
+ // Second, check if we already loaded a PDB with this GUID. Return the type
// index mapping if we have it.
- auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()});
+ auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()});
CVIndexMap &IndexMap = Insertion.first->second;
if (!Insertion.second)
return IndexMap;
@@ -319,23 +355,32 @@ const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
// Check for a PDB at:
// 1. The given file path
// 2. Next to the object file or archive file
- auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName());
+ auto ExpectedSession = tryToLoadPDB(TSId, TSPath);
if (!ExpectedSession) {
consumeError(ExpectedSession.takeError());
StringRef LocalPath =
!File->ParentName.empty() ? File->ParentName : File->getName();
SmallString<128> Path = sys::path::parent_path(LocalPath);
sys::path::append(
- Path, sys::path::filename(TS.getName(), sys::path::Style::windows));
- ExpectedSession = tryToLoadPDB(TS.getGuid(), Path);
+ Path, sys::path::filename(TSPath, sys::path::Style::windows));
+ ExpectedSession = tryToLoadPDB(TSId, Path);
+ }
+ if (auto E = ExpectedSession.takeError()) {
+ TypeServerIndexMappings.erase(TSId);
+ MissingTypeServerPDBs.emplace(TSId);
+ return std::move(E);
}
- if (auto E = ExpectedSession.takeError())
- fatal("Type server PDB was not found: " + toString(std::move(E)));
- auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream();
+ pdb::NativeSession *Session = ExpectedSession->get();
+
+ // Keep a strong reference to this PDB, so that it's safe to hold pointers
+ // into the file.
+ LoadedPDBs.push_back(std::move(*ExpectedSession));
+
+ auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream();
if (auto E = ExpectedTpi.takeError())
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
- auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream();
+ auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream();
if (auto E = ExpectedIpi.takeError())
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
@@ -412,6 +457,38 @@ static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind,
}
}
+static void
+recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents,
+ uint32_t Offset,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ Contents =
+ Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t));
+ ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data());
+ StrTableRefs.push_back(Index);
+}
+
+static void
+recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ // For now we only handle S_FILESTATIC, but we may need the same logic for
+ // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any
+ // PDBs that contain these types of records, so because of the uncertainty
+ // they are omitted here until we can prove that it's necessary.
+ switch (Kind) {
+ case SymbolKind::S_FILESTATIC:
+ // FileStaticSym::ModFileOffset
+ recordStringTableReferenceAtOffset(Contents, 4, StrTableRefs);
+ break;
+ case SymbolKind::S_DEFRANGE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ log("Not fixing up string table reference in S_DEFRANGE / "
+ "S_DEFRANGE_SUBFIELD record");
+ break;
+ default:
+ break;
+ }
+}
+
static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) {
const RecordPrefix *Prefix =
reinterpret_cast<const RecordPrefix *>(RecordData.data());
@@ -628,53 +705,65 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File,
pdb::GSIStreamBuilder &GsiBuilder,
const CVIndexMap &IndexMap,
TypeCollection &IDTable,
+ std::vector<ulittle32_t *> &StringTableRefs,
BinaryStreamRef SymData) {
// FIXME: Improve error recovery by warning and skipping records when
// possible.
- CVSymbolArray Syms;
- BinaryStreamReader Reader(SymData);
- ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+ ArrayRef<uint8_t> SymsBuffer;
+ cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
SmallVector<SymbolScope, 4> Scopes;
- for (CVSymbol Sym : Syms) {
- // Discover type index references in the record. Skip it if we don't know
- // where they are.
- SmallVector<TiReference, 32> TypeRefs;
- if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
- log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
- continue;
- }
-
- // Copy the symbol record so we can mutate it.
- MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
-
- // Re-map all the type index references.
- MutableArrayRef<uint8_t> Contents =
- NewData.drop_front(sizeof(RecordPrefix));
- remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs);
- // An object file may have S_xxx_ID symbols, but these get converted to
- // "real" symbols in a PDB.
- translateIdSymbols(NewData, IDTable);
-
- SymbolKind NewKind = symbolKind(NewData);
-
- // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
- CVSymbol NewSym(NewKind, NewData);
- if (symbolOpensScope(NewKind))
- scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
- else if (symbolEndsScope(NewKind))
- scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
-
- // Add the symbol to the globals stream if necessary. Do this before adding
- // the symbol to the module since we may need to get the next symbol offset,
- // and writing to the module's symbol stream will update that offset.
- if (symbolGoesInGlobalsStream(NewSym))
- addGlobalSymbol(GsiBuilder, *File, NewSym);
+ auto EC = forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
+ // Discover type index references in the record. Skip it if we don't
+ // know where they are.
+ SmallVector<TiReference, 32> TypeRefs;
+ if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+ log("ignoring unknown symbol record with kind 0x" +
+ utohexstr(Sym.kind()));
+ return Error::success();
+ }
- // Add the symbol to the module.
- if (symbolGoesInModuleStream(NewSym))
- File->ModuleDBI->addSymbol(NewSym);
- }
+ // Copy the symbol record so we can mutate it.
+ MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+ // Re-map all the type index references.
+ MutableArrayRef<uint8_t> Contents =
+ NewData.drop_front(sizeof(RecordPrefix));
+ remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap,
+ TypeRefs);
+
+ // An object file may have S_xxx_ID symbols, but these get converted to
+ // "real" symbols in a PDB.
+ translateIdSymbols(NewData, IDTable);
+
+ // If this record refers to an offset in the object file's string table,
+ // add that item to the global PDB string table and re-write the index.
+ recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
+
+ SymbolKind NewKind = symbolKind(NewData);
+
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ CVSymbol NewSym(NewKind, NewData);
+ if (symbolOpensScope(NewKind))
+ scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(),
+ NewSym);
+ else if (symbolEndsScope(NewKind))
+ scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+ // Add the symbol to the globals stream if necessary. Do this before
+ // adding the symbol to the module since we may need to get the next
+ // symbol offset, and writing to the module's symbol stream will update
+ // that offset.
+ if (symbolGoesInGlobalsStream(NewSym))
+ addGlobalSymbol(GsiBuilder, *File, NewSym);
+
+ // Add the symbol to the module.
+ if (symbolGoesInModuleStream(NewSym))
+ File->ModuleDBI->addSymbol(NewSym);
+ return Error::success();
+ });
+ cantFail(std::move(EC));
}
// Allocate memory for a .debug$S section and relocate it.
@@ -688,6 +777,32 @@ static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
".debug$S");
}
+static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
+ OutputSection *OS = C->getOutputSection();
+ pdb::SectionContrib SC;
+ memset(&SC, 0, sizeof(SC));
+ SC.ISect = OS->SectionIndex;
+ SC.Off = C->getRVA() - OS->getRVA();
+ SC.Size = C->getSize();
+ if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
+ SC.Characteristics = SecChunk->Header->Characteristics;
+ SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
+ ArrayRef<uint8_t> Contents = SecChunk->getContents();
+ JamCRC CRC(0);
+ ArrayRef<char> CharContents = makeArrayRef(
+ reinterpret_cast<const char *>(Contents.data()), Contents.size());
+ CRC.update(CharContents);
+ SC.DataCrc = CRC.getCRC();
+ } else {
+ SC.Characteristics = OS->Header.Characteristics;
+ // FIXME: When we start creating DBI for import libraries, use those here.
+ SC.Imod = Modi;
+ }
+ SC.RelocCrc = 0; // FIXME
+
+ return SC;
+}
+
void PDBLinker::addObjFile(ObjFile *File) {
// Add a module descriptor for every object file. We need to put an absolute
// path to the object into the PDB. If this is a plain object, we make its
@@ -702,14 +817,39 @@ void PDBLinker::addObjFile(ObjFile *File) {
File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
File->ModuleDBI->setObjFileName(Path);
+ auto Chunks = File->getChunks();
+ uint32_t Modi = File->ModuleDBI->getModuleIndex();
+ for (Chunk *C : Chunks) {
+ auto *SecChunk = dyn_cast<SectionChunk>(C);
+ if (!SecChunk || !SecChunk->isLive())
+ continue;
+ pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
+ File->ModuleDBI->setFirstSectionContrib(SC);
+ break;
+ }
+
// Before we can process symbol substreams from .debug$S, we need to process
// type information, file checksums, and the string table. Add type info to
// the PDB first, so that we can get the map from object file type and item
// indices to PDB type and item indices.
CVIndexMap ObjectIndexMap;
- const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap);
+ auto IndexMapResult = mergeDebugT(File, ObjectIndexMap);
+
+ // If the .debug$T sections fail to merge, assume there is no debug info.
+ if (!IndexMapResult) {
+ warn("Type server PDB for " + Name + " is invalid, ignoring debug info. " +
+ toString(IndexMapResult.takeError()));
+ return;
+ }
+
+ const CVIndexMap &IndexMap = *IndexMapResult;
+
+ ScopedTimer T(SymbolMergingTimer);
// Now do all live .debug$S sections.
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ std::vector<ulittle32_t *> StringTableReferences;
for (SectionChunk *DebugChunk : File->getDebugChunks()) {
if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
continue;
@@ -723,14 +863,17 @@ void PDBLinker::addObjFile(ObjFile *File) {
BinaryStreamReader Reader(RelocatedDebugContents, support::little);
ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
- DebugStringTableSubsectionRef CVStrTab;
- DebugChecksumsSubsectionRef Checksums;
for (const DebugSubsectionRecord &SS : Subsections) {
switch (SS.kind()) {
- case DebugSubsectionKind::StringTable:
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
break;
+ }
case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
ExitOnErr(Checksums.initialize(SS.getRecordData()));
break;
case DebugSubsectionKind::Lines:
@@ -741,10 +884,12 @@ void PDBLinker::addObjFile(ObjFile *File) {
case DebugSubsectionKind::Symbols:
if (Config->DebugGHashes) {
mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- GlobalIDTable, SS.getRecordData());
+ GlobalIDTable, StringTableReferences,
+ SS.getRecordData());
} else {
mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- IDTable, SS.getRecordData());
+ IDTable, StringTableReferences,
+ SS.getRecordData());
}
break;
default:
@@ -752,25 +897,55 @@ void PDBLinker::addObjFile(ObjFile *File) {
break;
}
}
+ }
+
+ // We should have seen all debug subsections across the entire object file now
+ // which means that if a StringTable subsection and Checksums subsection were
+ // present, now is the time to handle them.
+ if (!CVStrTab.valid()) {
+ if (Checksums.valid())
+ fatal(".debug$S sections with a checksums subsection must also contain a "
+ "string table subsection");
+
+ if (!StringTableReferences.empty())
+ warn("No StringTable subsection was encountered, but there are string "
+ "table references");
+ return;
+ }
+
+ // Rewrite each string table reference based on the value that the string
+ // assumes in the final PDB.
+ for (ulittle32_t *Ref : StringTableReferences) {
+ auto ExpectedString = CVStrTab.getString(*Ref);
+ if (!ExpectedString) {
+ warn("Invalid string table reference");
+ consumeError(ExpectedString.takeError());
+ continue;
+ }
- if (Checksums.valid()) {
- // Make a new file checksum table that refers to offsets in the PDB-wide
- // string table. Generally the string table subsection appears after the
- // checksum table, so we have to do this after looping over all the
- // subsections.
- if (!CVStrTab.valid())
- fatal(".debug$S sections must have both a string table subsection "
- "and a checksum subsection table or neither");
- auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
- for (FileChecksumEntry &FC : Checksums) {
- StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
- ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
- FileName));
- NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
- }
- File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+ *Ref = PDBStrTab.insert(*ExpectedString);
+ }
+
+ // Make a new file checksum table that refers to offsets in the PDB-wide
+ // string table. Generally the string table subsection appears after the
+ // checksum table, so we have to do this after looping over all the
+ // subsections.
+ auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
+ for (FileChecksumEntry &FC : Checksums) {
+ SmallString<128> FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+ if (!sys::path::is_absolute(FileName) &&
+ !Config->PDBSourcePath.empty()) {
+ SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
+ sys::path::append(AbsoluteFileName, FileName);
+ sys::path::native(AbsoluteFileName);
+ sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true);
+ FileName = std::move(AbsoluteFileName);
}
+ ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
+ FileName));
+ NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
}
+ File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
}
static PublicSym32 createPublic(Defined *Def) {
@@ -793,12 +968,15 @@ static PublicSym32 createPublic(Defined *Def) {
// Add all object files to the PDB. Merge .debug$T sections into IpiData and
// TpiData.
void PDBLinker::addObjectsToPDB() {
+ ScopedTimer T1(AddObjectsTimer);
for (ObjFile *File : ObjFile::Instances)
addObjFile(File);
Builder.getStringTableBuilder().setStrings(PDBStrTab);
+ T1.stop();
// Construct TPI and IPI stream contents.
+ ScopedTimer T2(TpiStreamLayoutTimer);
if (Config->DebugGHashes) {
addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable);
addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable);
@@ -806,7 +984,9 @@ void PDBLinker::addObjectsToPDB() {
addTypeInfo(Builder.getTpiBuilder(), TypeTable);
addTypeInfo(Builder.getIpiBuilder(), IDTable);
}
+ T2.stop();
+ ScopedTimer T3(GlobalsLayoutTimer);
// Compute the public and global symbols.
auto &GsiBuilder = Builder.getGsiBuilder();
std::vector<PublicSym32> Publics;
@@ -828,6 +1008,35 @@ void PDBLinker::addObjectsToPDB() {
}
}
+void PDBLinker::addNatvisFiles() {
+ for (StringRef File : Config->NatvisFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr =
+ MemoryBuffer::getFile(File);
+ if (!DataOrErr) {
+ warn("Cannot open input file: " + File);
+ continue;
+ }
+ Builder.addInjectedSource(File, std::move(*DataOrErr));
+ }
+}
+
+static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
+ switch (Machine) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return codeview::CPUType::X64;
+ case COFF::IMAGE_FILE_MACHINE_ARM:
+ return codeview::CPUType::ARM7;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return codeview::CPUType::ARM64;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return codeview::CPUType::ARMNT;
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return codeview::CPUType::Intel80386;
+ default:
+ llvm_unreachable("Unsupported CPU Type");
+ }
+}
+
static void addCommonLinkerModuleSymbols(StringRef Path,
pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
@@ -838,7 +1047,7 @@ static void addCommonLinkerModuleSymbols(StringRef Path,
ONS.Name = "* Linker *";
ONS.Signature = 0;
- CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+ CS.Machine = toCodeViewMachine(Config->Machine);
// Interestingly, if we set the string to 0.0.0.0, then when trying to view
// local variables WinDbg emits an error that private symbols are not present.
// By setting this to a valid MSVC linker version string, local variables are
@@ -889,9 +1098,9 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
SectionSym Sym(SymbolRecordKind::SectionSym);
Sym.Alignment = 12; // 2^12 = 4KB
- Sym.Characteristics = OS.getCharacteristics();
+ Sym.Characteristics = OS.Header.Characteristics;
Sym.Length = OS.getVirtualSize();
- Sym.Name = OS.getName();
+ Sym.Name = OS.Name;
Sym.Rva = OS.getRVA();
Sym.SectionNumber = OS.SectionIndex;
Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
@@ -903,10 +1112,15 @@ void coff::createPDB(SymbolTable *Symtab,
ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo &BuildId) {
+ ScopedTimer T1(TotalPdbLinkTimer);
PDBLinker PDB(Symtab);
+
PDB.initialize(BuildId);
PDB.addObjectsToPDB();
PDB.addSections(OutputSections, SectionTable);
+ PDB.addNatvisFiles();
+
+ ScopedTimer T2(DiskCommitTimer);
PDB.commit();
}
@@ -920,44 +1134,22 @@ void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) {
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(BuildId.PDB70.Age);
-
GUID uuid;
memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid));
+ InfoBuilder.setAge(BuildId.PDB70.Age);
InfoBuilder.setGuid(uuid);
- InfoBuilder.setSignature(time(nullptr));
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
// Add an empty DBI stream.
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setAge(BuildId.PDB70.Age);
DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
- ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
-}
-
-void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C) {
- pdb::SectionContrib SC;
- memset(&SC, 0, sizeof(SC));
- SC.ISect = OS->SectionIndex;
- SC.Off = C->getRVA() - OS->getRVA();
- SC.Size = C->getSize();
- if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
- SC.Characteristics = SecChunk->Header->Characteristics;
- SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
- ArrayRef<uint8_t> Contents = SecChunk->getContents();
- JamCRC CRC(0);
- ArrayRef<char> CharContents = makeArrayRef(
- reinterpret_cast<const char *>(Contents.data()), Contents.size());
- CRC.update(CharContents);
- SC.DataCrc = CRC.getCRC();
- } else {
- SC.Characteristics = OS->getCharacteristics();
- // FIXME: When we start creating DBI for import libraries, use those here.
- SC.Imod = LinkerModule.getModuleIndex();
- }
- SC.RelocCrc = 0; // FIXME
- Builder.getDbiBuilder().addSectionContrib(SC);
+ DbiBuilder.setMachineType(Config->Machine);
+ // Technically we are not link.exe 14.11, but there are known cases where
+ // debugging tools on Windows expect Microsoft-specific version numbers or
+ // they fail to work at all. Since we know we produce PDBs that are
+ // compatible with LINK 14.11, we set that version number here.
+ DbiBuilder.setBuildNumber(14, 11);
}
void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
@@ -975,8 +1167,11 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
// Add section contributions. They must be ordered by ascending RVA.
for (OutputSection *OS : OutputSections) {
addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
- for (Chunk *C : OS->getChunks())
- addSectionContrib(LinkerModule, OS, C);
+ for (Chunk *C : OS->getChunks()) {
+ pdb::SectionContrib SC =
+ createSectionContrib(C, LinkerModule.getModuleIndex());
+ Builder.getDbiBuilder().addSectionContrib(SC);
+ }
}
// Add Section Map stream.
@@ -995,3 +1190,145 @@ void PDBLinker::commit() {
// Write to a file.
ExitOnErr(Builder.commit(Config->PDBPath));
}
+
+static Expected<StringRef>
+getFileName(const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
+ auto Iter = Checksums.getArray().at(FileID);
+ if (Iter == Checksums.getArray().end())
+ return make_error<CodeViewError>(cv_error_code::no_records);
+ uint32_t Offset = Iter->FileNameOffset;
+ return Strings.getString(Offset);
+}
+
+static uint32_t getSecrelReloc() {
+ switch (Config->Machine) {
+ case AMD64:
+ return COFF::IMAGE_REL_AMD64_SECREL;
+ case I386:
+ return COFF::IMAGE_REL_I386_SECREL;
+ case ARMNT:
+ return COFF::IMAGE_REL_ARM_SECREL;
+ case ARM64:
+ return COFF::IMAGE_REL_ARM64_SECREL;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Try to find a line table for the given offset Addr into the given chunk C.
+// If a line table was found, the line table, the string and checksum tables
+// that are used to interpret the line table, and the offset of Addr in the line
+// table are stored in the output arguments. Returns whether a line table was
+// found.
+static bool findLineTable(const SectionChunk *C, uint32_t Addr,
+ DebugStringTableSubsectionRef &CVStrTab,
+ DebugChecksumsSubsectionRef &Checksums,
+ DebugLinesSubsectionRef &Lines,
+ uint32_t &OffsetInLinetable) {
+ ExitOnError ExitOnErr;
+ uint32_t SecrelReloc = getSecrelReloc();
+
+ for (SectionChunk *DbgC : C->File->getDebugChunks()) {
+ if (DbgC->getSectionName() != ".debug$S")
+ continue;
+
+ // Build a mapping of SECREL relocations in DbgC that refer to C.
+ DenseMap<uint32_t, uint32_t> Secrels;
+ for (const coff_relocation &R : DbgC->Relocs) {
+ if (R.Type != SecrelReloc)
+ continue;
+
+ if (auto *S = dyn_cast_or_null<DefinedRegular>(
+ C->File->getSymbols()[R.SymbolTableIndex]))
+ if (S->getChunk() == C)
+ Secrels[R.VirtualAddress] = S->getValue();
+ }
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic(DbgC->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ }
+ case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines: {
+ ArrayRef<uint8_t> Bytes;
+ auto Ref = SS.getRecordData();
+ ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes));
+ size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data();
+
+ // Check whether this line table refers to C.
+ auto I = Secrels.find(OffsetInDbgC);
+ if (I == Secrels.end())
+ break;
+
+ // Check whether this line table covers Addr in C.
+ DebugLinesSubsectionRef LinesTmp;
+ ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref)));
+ uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset;
+ if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize)
+ break;
+
+ assert(!Lines.header() &&
+ "Encountered multiple line tables for function!");
+ ExitOnErr(Lines.initialize(BinaryStreamReader(Ref)));
+ OffsetInLinetable = Addr - OffsetInC;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (CVStrTab.valid() && Checksums.valid() && Lines.header())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Use CodeView line tables to resolve a file and line number for the given
+// offset into the given chunk and return them, or {"", 0} if a line table was
+// not found.
+std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
+ uint32_t Addr) {
+ ExitOnError ExitOnErr;
+
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ DebugLinesSubsectionRef Lines;
+ uint32_t OffsetInLinetable;
+
+ if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
+ return {"", 0};
+
+ uint32_t NameIndex;
+ uint32_t LineNumber;
+ for (LineColumnEntry &Entry : Lines) {
+ for (const LineNumberEntry &LN : Entry.LineNumbers) {
+ if (LN.Offset > OffsetInLinetable) {
+ StringRef Filename =
+ ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+ }
+ LineInfo LI(LN.Flags);
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
+ }
+ StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+}
diff --git a/COFF/PDB.h b/COFF/PDB.h
index defd7d236790..a98d129a633b 100644
--- a/COFF/PDB.h
+++ b/COFF/PDB.h
@@ -22,12 +22,16 @@ union DebugInfo;
namespace lld {
namespace coff {
class OutputSection;
+class SectionChunk;
class SymbolTable;
void createPDB(SymbolTable *Symtab,
llvm::ArrayRef<OutputSection *> OutputSections,
llvm::ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo &BuildId);
+
+std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
+ uint32_t Addr);
}
}
diff --git a/COFF/Strings.cpp b/COFF/Strings.cpp
deleted file mode 100644
index 89b9c5186fd1..000000000000
--- a/COFF/Strings.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- 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 <mutex>
-
-#if defined(_MSC_VER)
-#include <Windows.h>
-#include <DbgHelp.h>
-#pragma comment(lib, "dbghelp.lib")
-#endif
-
-using namespace lld;
-using namespace lld::coff;
-using namespace llvm;
-
-Optional<std::string> coff::demangleMSVC(StringRef S) {
-#if defined(_MSC_VER)
- // UnDecorateSymbolName is not thread-safe, so we need a mutex.
- static std::mutex Mu;
- std::lock_guard<std::mutex> Lock(Mu);
-
- char Buf[4096];
- if (S.startswith("?"))
- if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
- return std::string(Buf, Len);
-#endif
- return None;
-}
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index df76679535cb..b286d865caaf 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -11,9 +11,11 @@
#include "Config.h"
#include "Driver.h"
#include "LTO.h"
+#include "PDB.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -24,6 +26,8 @@ using namespace llvm;
namespace lld {
namespace coff {
+static Timer LTOTimer("LTO", Timer::root());
+
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
@@ -34,8 +38,9 @@ void SymbolTable::addFile(InputFile *File) {
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
Config->Machine = MT;
} else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
- fatal(toString(File) + ": machine type " + machineToStr(MT) +
+ error(toString(File) + ": machine type " + machineToStr(MT) +
" conflicts with " + machineToStr(Config->Machine));
+ return;
}
if (auto *F = dyn_cast<ObjFile>(File)) {
@@ -61,6 +66,66 @@ static void errorOrWarn(const Twine &S) {
error(S);
}
+// Returns the name of the symbol in SC whose value is <= Addr that is closest
+// to Addr. This is generally the name of the global variable or function whose
+// definition contains Addr.
+static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
+ DefinedRegular *Candidate = nullptr;
+
+ for (Symbol *S : SC->File->getSymbols()) {
+ auto *D = dyn_cast_or_null<DefinedRegular>(S);
+ if (!D || D->getChunk() != SC || D->getValue() > Addr ||
+ (Candidate && D->getValue() < Candidate->getValue()))
+ continue;
+
+ Candidate = D;
+ }
+
+ if (!Candidate)
+ return "";
+ return Candidate->getName();
+}
+
+static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+ struct Location {
+ StringRef SymName;
+ std::pair<StringRef, uint32_t> FileLine;
+ };
+ std::vector<Location> Locations;
+
+ for (Chunk *C : File->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+ for (const coff_relocation &R : SC->Relocs) {
+ if (R.SymbolTableIndex != SymIndex)
+ continue;
+ std::pair<StringRef, uint32_t> FileLine =
+ getFileLine(SC, R.VirtualAddress);
+ StringRef SymName = getSymbolName(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || !SymName.empty())
+ Locations.push_back({SymName, FileLine});
+ }
+ }
+
+ if (Locations.empty())
+ return "\n>>> referenced by " + toString(File) + "\n";
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ for (Location Loc : Locations) {
+ OS << "\n>>> referenced by ";
+ if (!Loc.FileLine.first.empty())
+ OS << Loc.FileLine.first << ":" << Loc.FileLine.second
+ << "\n>>> ";
+ OS << toString(File);
+ if (!Loc.SymName.empty())
+ OS << ":(" << Loc.SymName << ')';
+ }
+ OS << '\n';
+ return OS.str();
+}
+
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
@@ -120,20 +185,23 @@ void SymbolTable::reportRemainingUndefines() {
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(B))
warn("<root>: locally defined symbol imported: " + Imp->getName() +
- " (defined in " + toString(Imp->getFile()) + ")");
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
for (ObjFile *File : ObjFile::Instances) {
+ size_t SymIndex = (size_t)-1;
for (Symbol *Sym : File->getSymbols()) {
+ ++SymIndex;
if (!Sym)
continue;
if (Undefs.count(Sym))
- errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName());
+ errorOrWarn("undefined symbol: " + Sym->getName() +
+ getSymbolLocations(File, SymIndex));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(Sym))
warn(toString(File) + ": locally defined symbol imported: " +
Imp->getName() + " (defined in " + toString(Imp->getFile()) +
- ")");
+ ") [LNK4217]");
}
}
}
@@ -142,7 +210,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
if (Sym)
return {Sym, false};
- Sym = (Symbol *)make<SymbolUnion>();
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->IsUsedInRegularObj = false;
Sym->PendingArchiveLoad = false;
return {Sym, true};
@@ -274,30 +342,29 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
return S;
}
-DefinedImportData *SymbolTable::addImportData(StringRef N, ImportFile *F) {
+Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportData>(S, N, F);
- return cast<DefinedImportData>(S);
+ return S;
}
reportDuplicate(S, F);
return nullptr;
}
-DefinedImportThunk *SymbolTable::addImportThunk(StringRef Name,
- DefinedImportData *ID,
- uint16_t Machine) {
+Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
+ uint16_t Machine) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
- return cast<DefinedImportThunk>(S);
+ return S;
}
reportDuplicate(S, ID->File);
@@ -314,10 +381,7 @@ std::vector<Chunk *> SymbolTable::getChunks() {
}
Symbol *SymbolTable::find(StringRef Name) {
- auto It = SymMap.find(CachedHashStringRef(Name));
- if (It == SymMap.end())
- return nullptr;
- return It->second;
+ return SymMap.lookup(CachedHashStringRef(Name));
}
Symbol *SymbolTable::findUnderscore(StringRef Name) {
@@ -384,6 +448,8 @@ std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFile::Instances.empty())
return;
+
+ ScopedTimer T(LTOTimer);
for (StringRef Object : compileBitcodeFiles()) {
auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
index 55481e6475bb..30cb1a5410c3 100644
--- a/COFF/SymbolTable.h
+++ b/COFF/SymbolTable.h
@@ -92,9 +92,9 @@ public:
Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
const llvm::object::coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr);
- DefinedImportData *addImportData(StringRef N, ImportFile *F);
- DefinedImportThunk *addImportThunk(StringRef Name, DefinedImportData *S,
- uint16_t Machine);
+ Symbol *addImportData(StringRef N, ImportFile *F);
+ Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
+ uint16_t Machine);
void reportDuplicate(Symbol *Existing, InputFile *NewFile);
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
index 4c5ab48c7565..7c8b7d5e8fc5 100644
--- a/COFF/Symbols.cpp
+++ b/COFF/Symbols.cpp
@@ -9,9 +9,9 @@
#include "Symbols.h"
#include "InputFiles.h"
-#include "Strings.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -21,7 +21,7 @@ using namespace llvm::object;
// Returns a symbol name for an error message.
std::string lld::toString(coff::Symbol &B) {
- if (Optional<std::string> S = coff::demangleMSVC(B.getName()))
+ if (Optional<std::string> S = lld::demangleMSVC(B.getName()))
return ("\"" + *S + "\" (" + B.getName() + ")").str();
return B.getName();
}
@@ -58,7 +58,7 @@ bool Symbol::isLive() const {
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
- return Imp->WrappedSym->File->Live;
+ return Imp->WrappedSym->File->ThunkLive;
// Assume any other kind of symbol is live.
return true;
}
@@ -71,7 +71,7 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
}
-uint16_t DefinedAbsolute::OutputSectionIndex = 0;
+uint16_t DefinedAbsolute::NumOutputSections;
static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
if (Machine == AMD64)
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
index d8a030705e27..783965adbd9a 100644
--- a/COFF/Symbols.h
+++ b/COFF/Symbols.h
@@ -213,11 +213,10 @@ public:
uint64_t getRVA() { return VA - Config->ImageBase; }
void setVA(uint64_t V) { VA = V; }
- // The sentinel absolute symbol section index. Section index relocations
- // against absolute symbols resolve to this 16 bit number, and it is the
- // largest valid section index plus one. This is written by the Writer.
- static uint16_t OutputSectionIndex;
- uint16_t getSecIdx() { return OutputSectionIndex; }
+ // Section index relocations against absolute symbols resolve to
+ // this 16 bit number, and it is the largest valid section index
+ // plus one. This variable keeps it.
+ static uint16_t NumOutputSections;
private:
uint64_t VA;
@@ -416,6 +415,8 @@ union SymbolUnion {
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 584f0621bea3..d17405ec26ab 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -17,6 +17,7 @@
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -25,7 +26,9 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <cstdio>
#include <map>
@@ -40,8 +43,40 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
+/* To re-generate DOSProgram:
+$ cat > /tmp/DOSProgram.asm
+org 0
+ ; Copy cs to ds.
+ push cs
+ pop ds
+ ; Point ds:dx at the $-terminated string.
+ mov dx, str
+ ; Int 21/AH=09h: Write string to standard output.
+ mov ah, 0x9
+ int 0x21
+ ; Int 21/AH=4Ch: Exit with return code (in AL).
+ mov ax, 0x4C01
+ int 0x21
+str:
+ db 'This program cannot be run in DOS mode.$'
+align 8, db 0
+$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin
+$ xxd -i /tmp/DOSProgram.bin
+*/
+static unsigned char DOSProgram[] = {
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,
+ 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,
+ 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00
+};
+static_assert(sizeof(DOSProgram) % 8 == 0,
+ "DOSProgram size must be multiple of 8");
+
static const int SectorSize = 512;
-static const int DOSStubSize = 64;
+static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram);
+static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8");
+
static const int NumberfOfDataDirectory = 16;
namespace {
@@ -69,24 +104,25 @@ public:
uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
D->PointerToRawData = Offs;
+ TimeDateStamps.push_back(&D->TimeDateStamp);
++D;
}
}
+ void setTimeDateStamp(uint32_t TimeDateStamp) {
+ for (support::ulittle32_t *TDS : TimeDateStamps)
+ *TDS = TimeDateStamp;
+ }
+
private:
+ mutable std::vector<support::ulittle32_t *> TimeDateStamps;
const std::vector<Chunk *> &Records;
};
class CVDebugRecordChunk : public Chunk {
public:
- CVDebugRecordChunk() {
- PDBAbsPath = Config->PDBPath;
- if (!PDBAbsPath.empty())
- llvm::sys::fs::make_absolute(PDBAbsPath);
- }
-
size_t getSize() const override {
- return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1;
+ return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1;
}
void writeTo(uint8_t *B) const override {
@@ -96,12 +132,11 @@ public:
// variable sized field (PDB Path)
char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId));
- if (!PDBAbsPath.empty())
- memcpy(P, PDBAbsPath.data(), PDBAbsPath.size());
- P[PDBAbsPath.size()] = '\0';
+ if (!Config->PDBAltPath.empty())
+ memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
+ P[Config->PDBAltPath.size()] = '\0';
}
- SmallString<128> PDBAbsPath;
mutable codeview::DebugInfo *BuildId = nullptr;
};
@@ -116,12 +151,19 @@ private:
void createMiscChunks();
void createImportTables();
void createExportTable();
+ void mergeSections();
void assignAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
- void createSEHTable(OutputSection *RData);
+ void createSEHTable();
+ void createGuardCFTables();
+ void markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols);
+ void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -131,9 +173,8 @@ private:
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);
+ void addBaserels();
+ void addBaserelBlocks(std::vector<Baserel> &V);
uint32_t getSizeOfInitializedData();
std::map<StringRef, std::vector<DefinedImportData *>> binImports();
@@ -145,9 +186,9 @@ private:
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- SEHTableChunk *SEHTable = nullptr;
+ bool SetNoSEHCharacteristic = false;
- Chunk *DebugDirectory = nullptr;
+ DebugDirectoryChunk *DebugDirectory = nullptr;
std::vector<Chunk *> DebugRecords;
CVDebugRecordChunk *BuildId = nullptr;
Optional<codeview::DebugInfo> PreviousBuildId;
@@ -157,50 +198,55 @@ private:
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
+
+ OutputSection *TextSec;
+ OutputSection *RdataSec;
+ OutputSection *BuildidSec;
+ OutputSection *DataSec;
+ OutputSection *PdataSec;
+ OutputSection *IdataSec;
+ OutputSection *EdataSec;
+ OutputSection *DidatSec;
+ OutputSection *RsrcSec;
+ OutputSection *RelocSec;
+
+ // The first and last .pdata sections in the output file.
+ //
+ // We need to keep track of the location of .pdata in whichever section it
+ // gets merged into so that we can sort its contents and emit a correct data
+ // directory entry for the exception table. This is also the case for some
+ // other sections (such as .edata) but because the contents of those sections
+ // are entirely linker-generated we can keep track of their locations using
+ // the chunks that the linker creates. All .pdata chunks come from input
+ // files, so we need to keep track of them separately.
+ Chunk *FirstPdata = nullptr;
+ Chunk *LastPdata;
};
} // anonymous namespace
namespace lld {
namespace coff {
-void writeResult() { Writer().run(); }
-
-void OutputSection::setRVA(uint64_t RVA) {
- Header.VirtualAddress = RVA;
- for (Chunk *C : Chunks)
- C->setRVA(C->getRVA() + RVA);
-}
+static Timer CodeLayoutTimer("Code Layout", Timer::root());
+static Timer DiskCommitTimer("Commit Output File", Timer::root());
-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 writeResult() { Writer().run(); }
void OutputSection::addChunk(Chunk *C) {
Chunks.push_back(C);
C->setOutputSection(this);
- uint64_t Off = Header.VirtualSize;
- Off = alignTo(Off, C->Alignment);
- C->setRVA(Off);
- C->OutputSectionOff = Off;
- Off += C->getSize();
- if (Off > UINT32_MAX)
- error("section larger than 4 GiB: " + Name);
- 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 &= ~PermMask;
+ Header.Characteristics |= C;
}
-void OutputSection::setPermissions(uint32_t C) {
- Header.Characteristics = C & PermMask;
+void OutputSection::merge(OutputSection *Other) {
+ for (Chunk *C : Other->Chunks)
+ C->setOutputSection(this);
+ Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
+ Other->Chunks.clear();
}
// Write the section header to a given buffer.
@@ -284,17 +330,22 @@ static Optional<codeview::DebugInfo> loadExistingBuildId(StringRef Path) {
// The main function of the writer.
void Writer::run() {
+ ScopedTimer T1(CodeLayoutTimer);
+
createSections();
createMiscChunks();
createImportTables();
createExportTable();
- if (Config->Relocatable)
- createSection(".reloc");
+ mergeSections();
assignAddresses();
removeEmptySections();
setSectionPermissions();
createSymbolAndStringTable();
+ if (FileSize > UINT32_MAX)
+ fatal("image size (" + Twine(FileSize) + ") " +
+ "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
+
// We must do this before opening the output file, as it depends on being able
// to read the contents of the existing output file.
PreviousBuildId = loadExistingBuildId(Config->OutputFile);
@@ -308,35 +359,79 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
- if (!Config->PDBPath.empty() && Config->Debug) {
+ T1.stop();
+ if (!Config->PDBPath.empty() && Config->Debug) {
assert(BuildId);
createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId);
}
writeMapFile(OutputSections);
+ ScopedTimer T2(DiskCommitTimer);
if (auto E = Buffer->commit())
fatal("failed to write the output file: " + toString(std::move(E)));
}
-static StringRef getOutputSection(StringRef Name) {
+static StringRef getOutputSectionName(StringRef Name) {
StringRef S = Name.split('$').first;
// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
- S = S.substr(0, S.find('.', 1));
+ return S.substr(0, S.find('.', 1));
+}
- auto It = Config->Merge.find(S);
- if (It == Config->Merge.end())
- return S;
- return It->second;
+// For /order.
+static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
+ auto GetPriority = [](const Chunk *C) {
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ return Config->Order.lookup(Sec->Sym->getName());
+ return 0;
+ };
+
+ std::stable_sort(Chunks.begin(), Chunks.end(),
+ [=](const Chunk *A, const Chunk *B) {
+ return GetPriority(A) < GetPriority(B);
+ });
}
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
- // First, bin chunks by name.
- std::map<StringRef, std::vector<Chunk *>> Map;
+ // First, create the builtin sections.
+ const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const uint32_t CODE = IMAGE_SCN_CNT_CODE;
+ const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+ const uint32_t R = IMAGE_SCN_MEM_READ;
+ const uint32_t W = IMAGE_SCN_MEM_WRITE;
+ const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
+
+ SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections;
+ auto CreateSection = [&](StringRef Name, uint32_t OutChars) {
+ OutputSection *&Sec = Sections[{Name, OutChars}];
+ if (!Sec) {
+ Sec = make<OutputSection>(Name, OutChars);
+ OutputSections.push_back(Sec);
+ }
+ return Sec;
+ };
+
+ // Try to match the section order used by link.exe.
+ TextSec = CreateSection(".text", CODE | R | X);
+ CreateSection(".bss", BSS | R | W);
+ RdataSec = CreateSection(".rdata", DATA | R);
+ BuildidSec = CreateSection(".buildid", DATA | R);
+ DataSec = CreateSection(".data", DATA | R | W);
+ PdataSec = CreateSection(".pdata", DATA | R);
+ IdataSec = CreateSection(".idata", DATA | R);
+ EdataSec = CreateSection(".edata", DATA | R);
+ DidatSec = CreateSection(".didat", DATA | R);
+ RsrcSec = CreateSection(".rsrc", DATA | R);
+ RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+
+ // Then bin chunks by name and output characteristics.
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (SC && !SC->isLive()) {
@@ -344,42 +439,71 @@ void Writer::createSections() {
SC->printDiscardedMessage();
continue;
}
- Map[C->getSectionName()].push_back(C);
+ Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
}
+ // Process an /order option.
+ if (!Config->Order.empty())
+ for (auto &Pair : Map)
+ sortBySectionOrder(Pair.second);
+
// 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 = make<OutputSection>(Name);
- OutputSections.push_back(Sec);
- }
+ StringRef Name = getOutputSectionName(Pair.first.first);
+ uint32_t OutChars = Pair.first.second;
+
+ // In link.exe, there is a special case for the I386 target where .CRT
+ // sections are treated as if they have output characteristics DATA | R if
+ // their characteristics are DATA | R | W. This implements the same special
+ // case for all architectures.
+ if (Name == ".CRT")
+ OutChars = DATA | R;
+
+ OutputSection *Sec = CreateSection(Name, OutChars);
std::vector<Chunk *> &Chunks = Pair.second;
- for (Chunk *C : Chunks) {
+ for (Chunk *C : Chunks)
Sec->addChunk(C);
- Sec->addPermissions(C->getPermissions());
- }
}
+
+ // Finally, move some output sections to the end.
+ auto SectionOrder = [&](OutputSection *S) {
+ // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+ // the loader cannot handle holes. Stripping can remove other discardable ones
+ // than .reloc, which is first of them (created early).
+ if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ return 2;
+ // .rsrc should come at the end of the non-discardable sections because its
+ // size may change by the Win32 UpdateResources() function, causing
+ // subsequent sections to move (see https://crbug.com/827082).
+ if (S == RsrcSec)
+ return 1;
+ return 0;
+ };
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ [&](OutputSection *S, OutputSection *T) {
+ return SectionOrder(S) < SectionOrder(T);
+ });
}
void Writer::createMiscChunks() {
- OutputSection *RData = createSection(".rdata");
+ for (auto &P : MergeChunk::Instances)
+ RdataSec->addChunk(P.second);
// Create thunks for locally-dllimported symbols.
if (!Symtab->LocalImportChunks.empty()) {
for (Chunk *C : Symtab->LocalImportChunks)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create Debug Information Chunks
if (Config->Debug) {
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
+ OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
+
// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
@@ -388,12 +512,18 @@ void Writer::createMiscChunks() {
BuildId = CVChunk;
DebugRecords.push_back(CVChunk);
- RData->addChunk(DebugDirectory);
+ DebugInfoSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
- RData->addChunk(C);
+ DebugInfoSec->addChunk(C);
}
- createSEHTable(RData);
+ // Create SEH table. x86-only.
+ if (Config->Machine == I386)
+ createSEHTable();
+
+ // Create /guard:cf tables if requested.
+ if (Config->GuardCF != GuardCFLevel::Off)
+ createGuardCFTables();
}
// Create .idata section for the DLL-imported symbol table.
@@ -414,53 +544,49 @@ void Writer::createImportTables() {
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 : ImportFile::Instances) {
- if (!File->Live)
- continue;
-
- if (DefinedImportThunk *Thunk = File->ThunkSym)
- Text->addChunk(Thunk->getChunk());
+ if (File->ThunkSym) {
+ if (!isa<DefinedImportThunk>(File->ThunkSym))
+ fatal(toString(*File->ThunkSym) + " was replaced");
+ DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym);
+ if (File->ThunkLive)
+ TextSec->addChunk(Thunk->getChunk());
+ }
+ if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym))
+ fatal(toString(*File->ImpSym) + " was replaced");
+ DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym);
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
if (!File->ThunkSym)
fatal("cannot delay-load " + toString(File) +
- " due to import of data: " + toString(*File->ImpSym));
- DelayIdata.add(File->ImpSym);
+ " due to import of data: " + toString(*ImpSym));
+ DelayIdata.add(ImpSym);
} else {
- Idata.add(File->ImpSym);
+ Idata.add(ImpSym);
}
}
- if (!Idata.empty()) {
- OutputSection *Sec = createSection(".idata");
+ if (!Idata.empty())
for (Chunk *C : Idata.getChunks())
- Sec->addChunk(C);
- }
+ IdataSec->addChunk(C);
if (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
DelayIdata.create(Helper);
- OutputSection *Sec = createSection(".didat");
for (Chunk *C : DelayIdata.getChunks())
- Sec->addChunk(C);
- Sec = createSection(".data");
+ DidatSec->addChunk(C);
for (Chunk *C : DelayIdata.getDataChunks())
- Sec->addChunk(C);
- Sec = createSection(".text");
+ DataSec->addChunk(C);
for (Chunk *C : DelayIdata.getCodeChunks())
- Sec->addChunk(C);
+ TextSec->addChunk(C);
}
}
void Writer::createExportTable() {
if (Config->Exports.empty())
return;
- OutputSection *Sec = createSection(".edata");
for (Chunk *C : Edata.Chunks)
- Sec->addChunk(C);
+ EdataSec->addChunk(C);
}
// The Windows loader doesn't seem to like empty sections,
@@ -484,19 +610,31 @@ size_t Writer::addEntryToStringTable(StringRef Str) {
}
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
- // Relative symbols are unrepresentable in a COFF symbol table.
- if (isa<DefinedSynthetic>(Def))
- return None;
-
- // Don't write dead symbols or symbols in codeview sections to the symbol
- // table.
- if (!Def->isLive())
+ coff_symbol16 Sym;
+ switch (Def->kind()) {
+ case Symbol::DefinedAbsoluteKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ case Symbol::DefinedSyntheticKind:
+ // Relative symbols are unrepresentable in a COFF symbol table.
return None;
- if (auto *D = dyn_cast<DefinedRegular>(Def))
- if (D->getChunk()->isCodeView())
+ default: {
+ // Don't write symbols that won't be written to the output to the symbol
+ // table.
+ Chunk *C = Def->getChunk();
+ if (!C)
+ return None;
+ OutputSection *OS = C->getOutputSection();
+ if (!OS)
return None;
- coff_symbol16 Sym;
+ Sym.Value = Def->getRVA() - OS->getRVA();
+ Sym.SectionNumber = OS->SectionIndex;
+ break;
+ }
+ }
+
StringRef Name = Def->getName();
if (Name.size() > COFF::NameSize) {
Sym.Name.Offset.Zeroes = 0;
@@ -515,46 +653,27 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
Sym.NumberOfAuxSymbols = 0;
-
- switch (Def->kind()) {
- case Symbol::DefinedAbsoluteKind:
- Sym.Value = Def->getRVA();
- Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
- break;
- default: {
- uint64_t RVA = Def->getRVA();
- OutputSection *Sec = nullptr;
- for (OutputSection *S : OutputSections) {
- if (S->getRVA() > RVA)
- break;
- Sec = S;
- }
- Sym.Value = RVA - Sec->getRVA();
- Sym.SectionNumber = Sec->SectionIndex;
- break;
- }
- }
return Sym;
}
void Writer::createSymbolAndStringTable() {
- // Name field in the section table is 8 byte long. Longer names need
- // to be written to the string table. First, construct string table.
+ // PE/COFF images are limited to 8 byte section names. Longer names can be
+ // supported by writing a non-standard string table, but this string table is
+ // not mapped at runtime and the long names will therefore be inaccessible.
+ // link.exe always truncates section names to 8 bytes, whereas binutils always
+ // preserves long section names via the string table. LLD adopts a hybrid
+ // solution where discardable sections have long names preserved and
+ // non-discardable sections have their names truncated, to ensure that any
+ // section which is mapped at runtime also has its name mapped at runtime.
for (OutputSection *Sec : OutputSections) {
- StringRef Name = Sec->getName();
- if (Name.size() <= COFF::NameSize)
+ if (Sec->Name.size() <= COFF::NameSize)
continue;
- // If a section isn't discardable (i.e. will be mapped at runtime),
- // prefer a truncated section name over a long section name in
- // the string table that is unavailable at runtime. This is different from
- // what link.exe does, but finding ".eh_fram" instead of "/4" is useful
- // to libunwind.
- if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
+ if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
- Sec->setStringTableOff(addEntryToStringTable(Name));
+ Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
}
- if (Config->DebugDwarf) {
+ if (Config->DebugDwarf || Config->DebugSymtab) {
for (ObjFile *File : ObjFile::Instances) {
for (Symbol *B : File->getSymbols()) {
auto *D = dyn_cast_or_null<Defined>(B);
@@ -571,16 +690,45 @@ void Writer::createSymbolAndStringTable() {
if (OutputSymtab.empty() && Strtab.empty())
return;
- 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);
+ uint64_t FileOff = FileSize;
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
FileOff += 4 + Strtab.size();
FileSize = alignTo(FileOff, SectorSize);
}
+void Writer::mergeSections() {
+ if (!PdataSec->getChunks().empty()) {
+ FirstPdata = PdataSec->getChunks().front();
+ LastPdata = PdataSec->getChunks().back();
+ }
+
+ for (auto &P : Config->Merge) {
+ StringRef ToName = P.second;
+ if (P.first == ToName)
+ continue;
+ StringSet<> Names;
+ while (1) {
+ if (!Names.insert(ToName).second)
+ fatal("/merge: cycle found for section '" + P.first + "'");
+ auto I = Config->Merge.find(ToName);
+ if (I == Config->Merge.end())
+ break;
+ ToName = I->second;
+ }
+ OutputSection *From = findSection(P.first);
+ OutputSection *To = findSection(ToName);
+ if (!From)
+ continue;
+ if (!To) {
+ From->Name = ToName;
+ continue;
+ }
+ To->merge(From);
+ }
+}
+
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
@@ -590,35 +738,57 @@ void Writer::assignAddresses() {
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
- uint64_t RVA = 0x1000; // The first page is kept unmapped.
+ uint64_t RVA = PageSize; // 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);
+ if (Sec == RelocSec)
+ addBaserels();
+ uint64_t RawSize = 0, VirtualSize = 0;
+ Sec->Header.VirtualAddress = RVA;
+ for (Chunk *C : Sec->getChunks()) {
+ VirtualSize = alignTo(VirtualSize, C->Alignment);
+ C->setRVA(RVA + VirtualSize);
+ C->OutputSectionOff = VirtualSize;
+ C->finalizeContents();
+ VirtualSize += C->getSize();
+ if (C->hasData())
+ RawSize = alignTo(VirtualSize, SectorSize);
+ }
+ if (VirtualSize > UINT32_MAX)
+ error("section larger than 4 GiB: " + Sec->Name);
+ Sec->Header.VirtualSize = VirtualSize;
+ Sec->Header.SizeOfRawData = RawSize;
+ if (RawSize != 0)
+ Sec->Header.PointerToRawData = FileSize;
+ RVA += alignTo(VirtualSize, PageSize);
+ FileSize += alignTo(RawSize, SectorSize);
}
SizeOfImage = alignTo(RVA, PageSize);
}
template <typename PEHeaderTy> void Writer::writeHeader() {
- // Write DOS stub
+ // Write DOS header. For backwards compatibility, the first part of a PE/COFF
+ // executable consists of an MS-DOS MZ executable. If the executable is run
+ // under DOS, that program gets run (usually to just print an error message).
+ // When run under Windows, the loader looks at AddressOfNewExeHeader and uses
+ // the PE header instead.
uint8_t *Buf = Buffer->getBufferStart();
auto *DOS = reinterpret_cast<dos_header *>(Buf);
- Buf += DOSStubSize;
+ Buf += sizeof(dos_header);
DOS->Magic[0] = 'M';
DOS->Magic[1] = 'Z';
+ DOS->UsedBytesInTheLastPage = DOSStubSize % 512;
+ DOS->FileSizeInPages = divideCeil(DOSStubSize, 512);
+ DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
+
DOS->AddressOfRelocationTable = sizeof(dos_header);
DOS->AddressOfNewExeHeader = DOSStubSize;
+ // Write DOS program.
+ memcpy(Buf, DOSProgram, sizeof(DOSProgram));
+ Buf += sizeof(DOSProgram);
+
// Write PE magic
memcpy(Buf, PEMagic, sizeof(PEMagic));
Buf += sizeof(PEMagic);
@@ -688,24 +858,27 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!Config->AllowIsolation)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
- if (Config->Machine == I386 && !SEHTable &&
- !Symtab->findUnderscore("_load_config_used"))
+ if (Config->GuardCF != GuardCFLevel::Off)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
+ if (Config->IntegrityCheck)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
+ if (SetNoSEHCharacteristic)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
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();
+ if (TextSec->getVirtualSize()) {
+ PE->BaseOfCode = TextSec->getRVA();
+ PE->SizeOfCode = TextSec->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 (!Config->Exports.empty()) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
+ Dir[EXPORT_TABLE].Size = Edata.getSize();
}
if (!Idata.empty()) {
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -713,17 +886,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
Dir[IAT].Size = Idata.getIATSize();
}
- if (OutputSection *Sec = findSection(".rsrc")) {
- Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+ if (RsrcSec->getVirtualSize()) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
+ Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
}
- if (OutputSection *Sec = findSection(".pdata")) {
- Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+ if (FirstPdata) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
+ Dir[EXCEPTION_TABLE].Size =
+ LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
}
- if (OutputSection *Sec = findSection(".reloc")) {
- Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+ if (RelocSec->getVirtualSize()) {
+ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
+ Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
}
if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
if (Defined *B = dyn_cast<Defined>(Sym)) {
@@ -792,35 +966,172 @@ void Writer::openFile(StringRef Path) {
"failed to open " + Path);
}
-void Writer::createSEHTable(OutputSection *RData) {
- // Create SEH table. x86-only.
- if (Config->Machine != I386)
- return;
-
- std::set<Defined *> Handlers;
+void Writer::createSEHTable() {
+ // Set the no SEH characteristic on x86 binaries unless we find exception
+ // handlers.
+ SetNoSEHCharacteristic = true;
+ SymbolRVASet Handlers;
for (ObjFile *File : ObjFile::Instances) {
- if (!File->SEHCompat)
+ // FIXME: We should error here instead of earlier unless /safeseh:no was
+ // passed.
+ if (!File->hasSafeSEH())
return;
- for (uint32_t I : File->SXData)
- if (Symbol *B = File->getSymbol(I))
- if (B->isLive())
- Handlers.insert(cast<Defined>(B));
+
+ markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
+ }
+
+ // Remove the "no SEH" characteristic if all object files were built with
+ // safeseh, we found some exception handlers, and there is a load config in
+ // the object.
+ SetNoSEHCharacteristic =
+ Handlers.empty() || !Symtab->findUnderscore("_load_config_used");
+
+ maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
+ "__safe_se_handler_count");
+}
+
+// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
+// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
+// symbol's offset into that Chunk.
+static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
+ Chunk *C = S->getChunk();
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ C = SC->Repl; // Look through ICF replacement.
+ uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0);
+ RVASet.insert({C, Off});
+}
+
+// Visit all relocations from all section contributions of this object file and
+// mark the relocation target as address-taken.
+static void markSymbolsWithRelocations(ObjFile *File,
+ SymbolRVASet &UsedSymbols) {
+ for (Chunk *C : File->getChunks()) {
+ // We only care about live section chunks. Common chunks and other chunks
+ // don't generally contain relocations.
+ SectionChunk *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->isLive())
+ continue;
+
+ // Look for relocations in this section against symbols in executable output
+ // sections.
+ for (Symbol *Ref : SC->symbols()) {
+ // FIXME: Do further testing to see if the relocation type matters,
+ // especially for 32-bit where taking the address of something usually
+ // uses an absolute relocation instead of a relative one.
+ if (auto *D = dyn_cast_or_null<Defined>(Ref)) {
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(UsedSymbols, D);
+ }
+ }
+ }
+}
+
+// Create the guard function id table. This is a table of RVAs of all
+// address-taken functions. It is sorted and uniqued, just like the safe SEH
+// table.
+void Writer::createGuardCFTables() {
+ SymbolRVASet AddressTakenSyms;
+ SymbolRVASet LongJmpTargets;
+ for (ObjFile *File : ObjFile::Instances) {
+ // If the object was compiled with /guard:cf, the address taken symbols
+ // are in .gfids$y sections, and the longjmp targets are in .gljmp$y
+ // sections. If the object was not compiled with /guard:cf, we assume there
+ // were no setjmp targets, and that all code symbols with relocations are
+ // possibly address-taken.
+ if (File->hasGuardCF()) {
+ markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
+ markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets);
+ } else {
+ markSymbolsWithRelocations(File, AddressTakenSyms);
+ }
+ }
+
+ // Mark the image entry as address-taken.
+ if (Config->Entry)
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
+
+ // Ensure sections referenced in the gfid table are 16-byte aligned.
+ for (const ChunkAndOffset &C : AddressTakenSyms)
+ if (C.InputChunk->Alignment < 16)
+ C.InputChunk->Alignment = 16;
+
+ maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
+ "__guard_fids_count");
+
+ // Add the longjmp target table unless the user told us not to.
+ if (Config->GuardCF == GuardCFLevel::Full)
+ maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
+ "__guard_longjmp_count");
+
+ // Set __guard_flags, which will be used in the load config to indicate that
+ // /guard:cf was enabled.
+ uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
+ uint32_t(coff_guard_flags::HasFidTable);
+ if (Config->GuardCF == GuardCFLevel::Full)
+ GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
+ Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
+ cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
+}
+
+// Take a list of input sections containing symbol table indices and add those
+// symbols to an RVA table. The challenge is that symbol RVAs are not known and
+// depend on the table size, so we can't directly build a set of integers.
+void Writer::markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols) {
+ for (SectionChunk *C : SymIdxChunks) {
+ // Skip sections discarded by linker GC. This comes up when a .gfids section
+ // is associated with something like a vtable and the vtable is discarded.
+ // In this case, the associated gfids section is discarded, and we don't
+ // mark the virtual member functions as address-taken by the vtable.
+ if (!C->isLive())
+ continue;
+
+ // Validate that the contents look like symbol table indices.
+ ArrayRef<uint8_t> Data = C->getContents();
+ if (Data.size() % 4 != 0) {
+ warn("ignoring " + C->getSectionName() +
+ " symbol table index section in object " + toString(File));
+ continue;
+ }
+
+ // Read each symbol table index and check if that symbol was included in the
+ // final link. If so, add it to the table symbol set.
+ ArrayRef<ulittle32_t> SymIndices(
+ reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4);
+ ArrayRef<Symbol *> ObjSymbols = File->getSymbols();
+ for (uint32_t SymIndex : SymIndices) {
+ if (SymIndex >= ObjSymbols.size()) {
+ warn("ignoring invalid symbol table index in section " +
+ C->getSectionName() + " in object " + toString(File));
+ continue;
+ }
+ if (Symbol *S = ObjSymbols[SymIndex]) {
+ if (S->isLive())
+ addSymbolToRVASet(TableSymbols, cast<Defined>(S));
+ }
+ }
}
+}
- if (Handlers.empty())
+// Replace the absolute table symbol with a synthetic symbol pointing to
+// TableChunk so that we can emit base relocations for it and resolve section
+// relative relocations.
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym) {
+ if (TableSymbols.empty())
return;
- SEHTable = make<SEHTableChunk>(Handlers);
- RData->addChunk(SEHTable);
+ RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
+ RdataSec->addChunk(TableChunk);
- // Replace the absolute table symbol with a synthetic symbol pointing to the
- // SEHTable chunk so that we can emit base relocations for it and resolve
- // section relative relocations.
- Symbol *T = Symtab->find("___safe_se_handler_table");
- Symbol *C = Symtab->find("___safe_se_handler_count");
- replaceSymbol<DefinedSynthetic>(T, T->getName(), SEHTable);
- cast<DefinedAbsolute>(C)->setVA(SEHTable->getSize() / 4);
+ Symbol *T = Symtab->findUnderscore(TableSym);
+ Symbol *C = Symtab->findUnderscore(CountSym);
+ replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
+ cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
}
// Handles /section options to allow users to overwrite
@@ -829,16 +1140,17 @@ 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);
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Name == Name)
+ Sec->setPermissions(Perm);
}
}
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
- // Record the section index that should be used when resolving a section
- // relocation against an absolute symbol.
- DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1;
+ // Record the number of sections to apply section index relocations
+ // against absolute symbols. See applySecIdx in Chunks.cpp..
+ DefinedAbsolute::NumOutputSections = OutputSections.size();
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : OutputSections) {
@@ -846,7 +1158,7 @@ void Writer::writeSections() {
// 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)
+ if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
@@ -854,32 +1166,65 @@ void Writer::writeSections() {
}
void Writer::writeBuildId() {
- // If we're not writing a build id (e.g. because /debug is not specified),
- // then just return;
- if (!Config->Debug)
- return;
+ // There are two important parts to the build ID.
+ // 1) If building with debug info, the COFF debug directory contains a
+ // timestamp as well as a Guid and Age of the PDB.
+ // 2) In all cases, the PE COFF file header also contains a timestamp.
+ // For reproducibility, instead of a timestamp we want to use a hash of the
+ // binary, however when building with debug info the hash needs to take into
+ // account the debug info, since it's possible to add blank lines to a file
+ // which causes the debug info to change but not the generated code.
+ //
+ // To handle this, we first set the Guid and Age in the debug directory (but
+ // only if we're doing a debug build). Then, we hash the binary (thus causing
+ // the hash to change if only the debug info changes, since the Age will be
+ // different). Finally, we write that hash into the debug directory (if
+ // present) as well as the COFF file header (always).
+ if (Config->Debug) {
+ assert(BuildId && "BuildId is not set!");
+ if (PreviousBuildId.hasValue()) {
+ *BuildId->BuildId = *PreviousBuildId;
+ BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1;
+ } else {
+ BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70;
+ BuildId->BuildId->PDB70.Age = 1;
+ llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16);
+ }
+ }
- assert(BuildId && "BuildId is not set!");
+ // At this point the only fields in the COFF file which remain unset are the
+ // "timestamp" in the COFF file header, and the ones in the coff debug
+ // directory. Now we can hash the file and write that hash to the various
+ // timestamp fields in the file.
+ StringRef OutputFileData(
+ reinterpret_cast<const char *>(Buffer->getBufferStart()),
+ Buffer->getBufferSize());
- if (PreviousBuildId.hasValue()) {
- *BuildId->BuildId = *PreviousBuildId;
- BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1;
- return;
- }
+ uint32_t Timestamp = Config->Timestamp;
+ if (Config->Repro)
+ Timestamp = static_cast<uint32_t>(xxHash64(OutputFileData));
+
+ if (DebugDirectory)
+ DebugDirectory->setTimeDateStamp(Timestamp);
- BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70;
- BuildId->BuildId->PDB70.Age = 1;
- llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16);
+ uint8_t *Buf = Buffer->getBufferStart();
+ Buf += DOSStubSize + sizeof(PEMagic);
+ object::coff_file_header *CoffHeader =
+ reinterpret_cast<coff_file_header *>(Buf);
+ CoffHeader->TimeDateStamp = Timestamp;
}
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
- OutputSection *Sec = findSection(".pdata");
- if (!Sec)
+ if (!FirstPdata)
return;
// We assume .pdata contains function table entries only.
- uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
- uint8_t *End = Begin + Sec->getVirtualSize();
+ auto BufAddr = [&](Chunk *C) {
+ return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
+ C->getRVA() - C->getOutputSection()->getRVA();
+ };
+ uint8_t *Begin = BufAddr(FirstPdata);
+ uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
@@ -897,7 +1242,7 @@ void Writer::sortExceptionTable() {
OutputSection *Writer::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
- if (Sec->getName() == Name)
+ if (Sec->Name == Name)
return Sec;
return nullptr;
}
@@ -905,55 +1250,31 @@ OutputSection *Writer::findSection(StringRef Name) {
uint32_t Writer::getSizeOfInitializedData() {
uint32_t Res = 0;
for (OutputSection *S : OutputSections)
- if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ if (S->Header.Characteristics & 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)
- .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
- .Case(".reloc", DATA | DISCARDABLE | R)
- .Case(".text", CODE | R | X)
- .Default(0);
- if (!Perms)
- llvm_unreachable("unknown section name");
- auto Sec = make<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) {
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+ if (!Config->Relocatable)
+ return;
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
- if (Sec == Dest)
+ if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
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);
+ addBaserelBlocks(V);
V.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+void Writer::addBaserelBlocks(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;
@@ -961,11 +1282,11 @@ void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
uint32_t P = V[J].RVA & Mask;
if (P == Page)
continue;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
I = J;
Page = P;
}
if (I == J)
return;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
}
diff --git a/COFF/Writer.h b/COFF/Writer.h
index 21be1be6e92a..d37276cb6d91 100644
--- a/COFF/Writer.h
+++ b/COFF/Writer.h
@@ -13,6 +13,7 @@
#include "Chunks.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
+#include <chrono>
#include <cstdint>
#include <vector>
@@ -29,16 +30,14 @@ void writeResult();
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
- OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
- void setRVA(uint64_t);
- void setFileOffset(uint64_t);
+ OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
+ Header.Characteristics = Chars;
+ }
void addChunk(Chunk *C);
- llvm::StringRef getName() { return Name; }
+ void merge(OutputSection *Other);
ArrayRef<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);
@@ -60,9 +59,10 @@ public:
// N.B. The section index is one based.
uint32_t SectionIndex = 0;
-private:
llvm::StringRef Name;
- llvm::object::coff_section Header;
+ llvm::object::coff_section Header = {};
+
+private:
uint32_t StringTableOff = 0;
std::vector<Chunk *> Chunks;
};
diff --git a/Common/Args.cpp b/Common/Args.cpp
index 680cf5bd0a6e..ff77bfcc3b76 100644
--- a/Common/Args.cpp
+++ b/Common/Args.cpp
@@ -18,13 +18,17 @@ using namespace llvm;
using namespace lld;
int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
- int V = Default;
- if (auto *Arg = Args.getLastArg(Key)) {
- StringRef S = Arg->getValue();
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- }
- return V;
+ auto *A = Args.getLastArg(Key);
+ if (!A)
+ return Default;
+
+ int V;
+ if (to_integer(A->getValue(), V, 10))
+ return V;
+
+ StringRef Spelling = Args.getArgString(A->getIndex());
+ error(Spelling + ": number expected, but got '" + A->getValue() + "'");
+ return 0;
}
std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt
index b376893f35a4..a45fe209f06f 100644
--- a/Common/CMakeLists.txt
+++ b/Common/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lld_library(lldCommon
Strings.cpp
TargetOptionsCommandFlags.cpp
Threads.cpp
+ Timer.cpp
Version.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp
index 18affce4d5a6..d1cb3dbbe03c 100644
--- a/Common/ErrorHandler.cpp
+++ b/Common/ErrorHandler.cpp
@@ -12,7 +12,8 @@
#include "lld/Common/Threads.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/Error.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
@@ -59,6 +60,30 @@ void lld::exitLld(int Val) {
_exit(Val);
}
+void lld::diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> S;
+ raw_svector_ostream OS(S);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ switch (DI.getSeverity()) {
+ case DS_Error:
+ error(S);
+ break;
+ case DS_Warning:
+ warn(S);
+ break;
+ case DS_Remark:
+ case DS_Note:
+ message(S);
+ break;
+ }
+}
+
+void lld::checkError(Error E) {
+ handleAllErrors(std::move(E),
+ [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+}
+
void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << LogName << ": ";
if (ColorDiagnostics) {
diff --git a/Common/Strings.cpp b/Common/Strings.cpp
index 6cd4ad8d600a..36f4f77d8476 100644
--- a/Common/Strings.cpp
+++ b/Common/Strings.cpp
@@ -8,7 +8,21 @@
//===----------------------------------------------------------------------===//
#include "lld/Common/Strings.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/GlobPattern.h"
+#include <algorithm>
+#include <mutex>
+#include <vector>
+
+#if defined(_MSC_VER)
+#include <Windows.h>
+
+// DbgHelp.h must be included after Windows.h.
+#include <DbgHelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#endif
using namespace llvm;
using namespace lld;
@@ -30,3 +44,66 @@ Optional<std::string> lld::demangleItanium(StringRef Name) {
free(Buf);
return S;
}
+
+Optional<std::string> lld::demangleMSVC(StringRef S) {
+#if defined(_MSC_VER)
+ // UnDecorateSymbolName is not thread-safe, so we need a mutex.
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+
+ char Buf[4096];
+ if (S.startswith("?"))
+ if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
+ return std::string(Buf, Len);
+#endif
+ return None;
+}
+
+StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
+ for (StringRef S : Pat) {
+ Expected<GlobPattern> Pat = GlobPattern::create(S);
+ if (!Pat)
+ error(toString(Pat.takeError()));
+ else
+ Patterns.push_back(*Pat);
+ }
+}
+
+bool StringMatcher::match(StringRef S) const {
+ for (const GlobPattern &Pat : Patterns)
+ if (Pat.match(S))
+ return true;
+ return false;
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> lld::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 (!to_integer(B, H, 16)) {
+ error("not a hexadecimal value: " + B);
+ return {};
+ }
+ Hex.push_back(H);
+ }
+ return Hex;
+}
+
+// Returns true if S is valid as a C language identifier.
+bool lld::isValidCIdentifier(StringRef S) {
+ return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
+ std::all_of(S.begin() + 1, S.end(),
+ [](char C) { return C == '_' || isAlnum(C); });
+}
+
+// Write the contents of the a buffer to a file
+void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
diff --git a/Common/TargetOptionsCommandFlags.cpp b/Common/TargetOptionsCommandFlags.cpp
index e8e582f4c256..b46df363c361 100644
--- a/Common/TargetOptionsCommandFlags.cpp
+++ b/Common/TargetOptionsCommandFlags.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file exists as a place for global variables defined in LLVM's
-// CodeGen/CommandFlags.def. By putting the resulting object file in
+// CodeGen/CommandFlags.inc. By putting the resulting object file in
// an archive and linking with it, the definitions will automatically be
// included when needed and skipped when already present.
//
@@ -16,12 +16,12 @@
#include "lld/Common/TargetOptionsCommandFlags.h"
-#include "llvm/CodeGen/CommandFlags.def"
+#include "llvm/CodeGen/CommandFlags.inc"
#include "llvm/Target/TargetOptions.h"
// Define an externally visible version of
// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
-// used without having to include llvm/CodeGen/CommandFlags.def, which
+// used without having to include llvm/CodeGen/CommandFlags.inc, which
// would lead to multiple definitions of the command line flags.
llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
return ::InitTargetOptionsFromCodeGenFlags();
@@ -30,3 +30,5 @@ llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() {
return getCodeModel();
}
+
+std::string lld::GetCPUStr() { return ::getCPUStr(); }
diff --git a/Common/Timer.cpp b/Common/Timer.cpp
new file mode 100644
index 000000000000..89f9829b47cf
--- /dev/null
+++ b/Common/Timer.cpp
@@ -0,0 +1,80 @@
+//===- Timer.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Timer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Format.h"
+
+using namespace lld;
+using namespace llvm;
+
+ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); }
+
+void ScopedTimer::stop() {
+ if (!T)
+ return;
+ T->stop();
+ T = nullptr;
+}
+
+ScopedTimer::~ScopedTimer() { stop(); }
+
+Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {}
+Timer::Timer(llvm::StringRef Name, Timer &Parent)
+ : Name(Name), Parent(&Parent) {}
+
+void Timer::start() {
+ if (Parent && Total.count() == 0)
+ Parent->Children.push_back(this);
+ StartTime = std::chrono::high_resolution_clock::now();
+}
+
+void Timer::stop() {
+ Total += (std::chrono::high_resolution_clock::now() - StartTime);
+}
+
+Timer &Timer::root() {
+ static Timer RootTimer("Total Link Time");
+ return RootTimer;
+}
+
+void Timer::print() {
+ double TotalDuration = static_cast<double>(root().millis());
+
+ // We want to print the grand total under all the intermediate phases, so we
+ // print all children first, then print the total under that.
+ for (const auto &Child : Children)
+ Child->print(1, TotalDuration);
+
+ message(std::string(49, '-'));
+
+ root().print(0, root().millis(), false);
+}
+
+double Timer::millis() const {
+ return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
+ Total)
+ .count();
+}
+
+void Timer::print(int Depth, double TotalDuration, bool Recurse) const {
+ double P = 100.0 * millis() / TotalDuration;
+
+ SmallString<32> Str;
+ llvm::raw_svector_ostream Stream(Str);
+ std::string S = std::string(Depth * 2, ' ') + Name + std::string(":");
+ Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P);
+
+ message(Str);
+
+ if (Recurse) {
+ for (const auto &Child : Children)
+ Child->print(Depth + 1, TotalDuration);
+ }
+}
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp
index 9c0d536dea71..7551919cf86f 100644
--- a/ELF/AArch64ErrataFix.cpp
+++ b/ELF/AArch64ErrataFix.cpp
@@ -34,12 +34,11 @@
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
-#include "Strings.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
-
+#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -47,6 +46,7 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support;
using namespace llvm::support::endian;
using namespace lld;
@@ -341,7 +341,7 @@ static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2,
// patch or 0 if no patch required.
static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
uint64_t Limit) {
- uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff;
+ uint64_t ISAddr = IS->getVA(0);
// Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8.
uint64_t InitialPageOff = (ISAddr + Off) & 0xfff;
@@ -357,7 +357,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
uint64_t PatchOff = 0;
const uint8_t *Buf = IS->Data.begin();
- const uint32_t *InstBuf = reinterpret_cast<const uint32_t *>(Buf + Off);
+ const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off);
uint32_t Instr1 = *InstBuf++;
uint32_t Instr2 = *InstBuf++;
uint32_t Instr3 = *InstBuf++;
@@ -405,7 +405,7 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off)
}
uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
- return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset;
+ return Patchee->getVA(PatcheeOffset);
}
void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) {
@@ -554,9 +554,8 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset,
if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26)
return;
- if (Config->Verbose)
- message("detected cortex-a53-843419 erratum sequence starting at " +
- utohexstr(AdrpAddr) + " in unpatched output.");
+ log("detected cortex-a53-843419 erratum sequence starting at " +
+ utohexstr(AdrpAddr) + " in unpatched output.");
auto *PS = make<Patch843419Section>(IS, PatcheeOffset);
Patches.push_back(PS);
@@ -602,7 +601,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
(DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value;
while (Off < Limit) {
- uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off;
+ uint64_t StartAddr = IS->getVA(Off);
if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit))
implementPatch(StartAddr, PatcheeOffset, IS, Patches);
}
diff --git a/ELF/AArch64ErrataFix.h b/ELF/AArch64ErrataFix.h
index 6c100f25d8af..edd154d4cab3 100644
--- a/ELF/AArch64ErrataFix.h
+++ b/ELF/AArch64ErrataFix.h
@@ -11,7 +11,6 @@
#define LLD_ELF_AARCH64ERRATAFIX_H
#include "lld/Common/LLVM.h"
-
#include <map>
#include <vector>
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index 99e9879a6989..c7b3c0801de2 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -34,7 +34,7 @@ public:
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
@@ -89,6 +89,11 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
@@ -144,8 +149,10 @@ bool AArch64::usesOnlyLowPageBits(RelType Type) const {
}
}
-bool AArch64::isPicRel(RelType Type) const {
- return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
+RelType AArch64::getDynRel(RelType Type) const {
+ if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
+ return Type;
+ return R_AARCH64_NONE;
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
@@ -240,12 +247,12 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_AARCH64_ABS16:
case R_AARCH64_PREL16:
- checkIntUInt<16>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_AARCH64_ABS32:
case R_AARCH64_PREL32:
- checkIntUInt<32>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_AARCH64_ABS64:
@@ -260,11 +267,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
- checkInt<33>(Loc, Val, Type);
+ checkInt(Loc, Val, 33, Type);
write32AArch64Addr(Loc, Val >> 12);
break;
case R_AARCH64_ADR_PREL_LO21:
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write32AArch64Addr(Loc, Val);
break;
case R_AARCH64_JUMP26:
@@ -278,38 +285,40 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, 0x14000000);
LLVM_FALLTHROUGH;
case R_AARCH64_CALL26:
- checkInt<28>(Loc, Val, Type);
+ checkInt(Loc, Val, 28, Type);
or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
break;
case R_AARCH64_CONDBR19:
case R_AARCH64_LD_PREL_LO19:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<21>(Loc, Val, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case R_AARCH64_TLSDESC_LD64_LO12:
- checkAlignment<8>(Loc, Val, Type);
- or32le(Loc, (Val & 0xFF8) << 7);
- break;
case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
- checkAlignment<2>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 2, Type);
or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
- checkAlignment<4>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 4, Type);
or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
- checkAlignment<8>(Loc, Val, Type);
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ checkAlignment(Loc, Val, 8, Type);
or32AArch64Imm(Loc, getBits(Val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
- checkAlignment<16>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 16, Type);
or32AArch64Imm(Loc, getBits(Val, 4, 11));
break;
case R_AARCH64_MOVW_UABS_G0_NC:
@@ -325,11 +334,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
break;
case R_AARCH64_TSTBR14:
- checkInt<16>(Loc, Val, Type);
+ checkInt(Loc, Val, 16, Type);
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt<24>(Loc, Val, Type);
+ checkInt(Loc, Val, 24, Type);
or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -353,7 +362,7 @@ void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// movk x0, #0x10
// nop
// nop
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
switch (Type) {
case R_AARCH64_TLSDESC_ADD_LO12:
@@ -403,7 +412,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
// Generate MOVZ.
diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp
index 505e0e6ad480..48b27f23510c 100644
--- a/ELF/Arch/AMDGPU.cpp
+++ b/ELF/Arch/AMDGPU.cpp
@@ -66,6 +66,7 @@ void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, Val);
break;
case R_AMDGPU_ABS64:
+ case R_AMDGPU_REL64:
write64le(Loc, Val);
break;
case R_AMDGPU_GOTPCREL32_HI:
@@ -86,6 +87,7 @@ RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S,
case R_AMDGPU_REL32:
case R_AMDGPU_REL32_LO:
case R_AMDGPU_REL32_HI:
+ case R_AMDGPU_REL64:
return R_PC;
case R_AMDGPU_GOTPCREL:
case R_AMDGPU_GOTPCREL32_LO:
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
index b9f551e4b3be..d99be9be7c36 100644
--- a/ELF/Arch/ARM.cpp
+++ b/ELF/Arch/ARM.cpp
@@ -29,7 +29,6 @@ public:
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
@@ -55,6 +54,7 @@ ARM::ARM() {
TlsGotRel = R_ARM_TLS_TPOFF32;
TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ GotBaseSymInGotPlt = false;
GotEntrySize = 4;
GotPltEntrySize = 4;
PltEntrySize = 16;
@@ -161,18 +161,10 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
}
}
-bool ARM::isPicRel(RelType Type) const {
- return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
- (Type == R_ARM_ABS32);
-}
-
RelType ARM::getDynRel(RelType Type) const {
- if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+ if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel))
return R_ARM_ABS32;
- if (Type == R_ARM_ABS32)
- return Type;
- // Keep it going with a dummy value so that we can find more reloc errors.
- return R_ARM_ABS32;
+ return R_ARM_NONE;
}
void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
@@ -392,7 +384,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, 1);
break;
case R_ARM_PREL31:
- checkInt<31>(Loc, Val, Type);
+ checkInt(Loc, Val, 31, Type);
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
break;
case R_ARM_CALL:
@@ -401,7 +393,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
if (Val & 1) {
// If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
// The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
- checkInt<26>(Loc, Val, Type);
+ checkInt(Loc, Val, 26, Type);
write32le(Loc, 0xfa000000 | // opcode
((Val & 2) << 23) | // H
((Val >> 2) & 0x00ffffff)); // imm24
@@ -416,16 +408,16 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
- checkInt<26>(Loc, Val, Type);
+ checkInt(Loc, Val, 26, Type);
write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
break;
case R_ARM_THM_JUMP11:
- checkInt<12>(Loc, Val, Type);
+ checkInt(Loc, Val, 12, Type);
write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
break;
case R_ARM_THM_JUMP19:
// Encoding T3: Val = S:J2:J1:imm6:imm11:0
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write16le(Loc,
(read16le(Loc) & 0xfbc0) | // opcode cond
((Val >> 10) & 0x0400) | // S
@@ -451,7 +443,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
// FIXME: Use of I1 and I2 require v6T2ops
- checkInt<25>(Loc, Val, Type);
+ checkInt(Loc, Val, 25, Type);
write16le(Loc,
0xf000 | // opcode
((Val >> 14) & 0x0400) | // S
@@ -469,14 +461,14 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_ARM_MOVT_ABS:
case R_ARM_MOVT_PREL:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
break;
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVT_PREL:
// Encoding T1: A = imm4:i:imm3:imm8
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
diff --git a/ELF/Arch/Hexagon.cpp b/ELF/Arch/Hexagon.cpp
new file mode 100644
index 000000000000..2d5c23fd5ad6
--- /dev/null
+++ b/ELF/Arch/Hexagon.cpp
@@ -0,0 +1,97 @@
+//===-- Hexagon.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 "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class Hexagon final : public TargetInfo {
+public:
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+// Support V60 only at the moment.
+uint32_t Hexagon::calcEFlags() const { return 0x60; }
+
+static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
+ uint32_t Result = 0;
+ size_t Off = 0;
+
+ for (size_t Bit = 0; Bit != 32; ++Bit) {
+ uint32_t ValBit = (Data >> Off) & 1;
+ uint32_t MaskBit = (Mask >> Bit) & 1;
+ if (MaskBit) {
+ Result |= (ValBit << Bit);
+ ++Off;
+ }
+ }
+ return Result;
+}
+
+RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_HEX_B15_PCREL:
+ case R_HEX_B15_PCREL_X:
+ case R_HEX_B22_PCREL:
+ case R_HEX_B22_PCREL_X:
+ case R_HEX_B32_PCREL_X:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_HEX_NONE:
+ break;
+ case R_HEX_B15_PCREL:
+ or32le(Loc, applyMask(0x00df20fe, Val >> 2));
+ break;
+ case R_HEX_B15_PCREL_X:
+ or32le(Loc, applyMask(0x00df20fe, Val & 0x3f));
+ break;
+ case R_HEX_B22_PCREL:
+ or32le(Loc, applyMask(0x1ff3ffe, Val >> 2));
+ break;
+ case R_HEX_B22_PCREL_X:
+ or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f));
+ break;
+ case R_HEX_B32_PCREL_X:
+ or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ break;
+ }
+}
+
+TargetInfo *elf::getHexagonTargetInfo() {
+ static Hexagon Target;
+ return &Target;
+}
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index 495e2567006f..dc70401c0b0e 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -32,7 +32,6 @@ public:
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -50,6 +49,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
DefaultMaxPageSize = 65536;
GotEntrySize = sizeof(typename ELFT::uint);
GotPltEntrySize = sizeof(typename ELFT::uint);
+ GotBaseSymInGotPlt = false;
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
@@ -101,8 +101,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_HIGHEST:
case R_MICROMIPS_HI16:
case R_MICROMIPS_LO16:
- case R_MICROMIPS_HIGHER:
- case R_MICROMIPS_HIGHEST:
// R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
// offset between start of function and 'gp' value which by default
// equal to the start of .got section. In that case we consider these
@@ -124,8 +122,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_TLS_TPREL_LO16:
case R_MIPS_TLS_TPREL32:
case R_MIPS_TLS_TPREL64:
- case R_MICROMIPS_GOT_OFST:
- case R_MICROMIPS_SUB:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_TPREL_HI16:
@@ -155,7 +151,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_GOT_DISP:
case R_MIPS_TLS_GOTTPREL:
case R_MICROMIPS_CALL16:
- case R_MICROMIPS_GOT_DISP:
case R_MICROMIPS_TLS_GOTTPREL:
return R_MIPS_GOT_OFF;
case R_MIPS_CALL_HI16:
@@ -168,7 +163,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MICROMIPS_GOT_LO16:
return R_MIPS_GOT_OFF32;
case R_MIPS_GOT_PAGE:
- case R_MICROMIPS_GOT_PAGE:
return R_MIPS_GOT_LOCAL_PAGE;
case R_MIPS_TLS_GD:
case R_MICROMIPS_TLS_GD:
@@ -183,12 +177,10 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
}
}
-template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const {
- return Type == R_MIPS_32 || Type == R_MIPS_64;
-}
-
template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
- return RelativeRel;
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ return R_MIPS_NONE;
}
template <class ELFT>
@@ -213,8 +205,8 @@ template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
}
template <endianness E>
-static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
uint32_t Instr = read32<E>(Loc);
uint32_t Mask = 0xffffffff >> (32 - BitsSize);
uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
@@ -222,14 +214,14 @@ static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
}
template <endianness E>
-static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
// See comments in readShuffle for purpose of this code.
uint16_t *Words = (uint16_t *)Loc;
if (E == support::little)
std::swap(Words[0], Words[1]);
- writeRelocation<E>(Loc, V, BitsSize, Shift);
+ writeValue<E>(Loc, V, BitsSize, Shift);
if (E == support::little)
std::swap(Words[0], Words[1]);
@@ -296,13 +288,14 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
}
- write32<E>(Buf + 24, 0x0320f809); // jalr $25
+ uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809;
+ write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
uint64_t GotPlt = InX::GotPlt->getVA();
- writeRelocation<E>(Buf, GotPlt + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPlt, 16, 0);
- writeRelocation<E>(Buf + 8, GotPlt, 16, 0);
+ writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPlt, 16, 0);
+ writeValue<E>(Buf + 8, GotPlt, 16, 0);
}
template <class ELFT>
@@ -330,13 +323,16 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
return;
}
+ uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009)
+ : (Config->ZHazardplt ? 0x03200408 : 0x03200008);
+
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, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25
+ write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
- writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0);
- writeRelocation<E>(Buf + 12, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0);
}
template <class ELFT>
@@ -455,9 +451,6 @@ calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) {
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);
- if (Type2 == R_MICROMIPS_SUB &&
- (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16))
- return std::make_pair(Type3, -Val);
error(getErrorLocation(Loc) + "unsupported relocations combination " +
Twine(Type));
return std::make_pair(Type & 0xff, Val);
@@ -467,6 +460,9 @@ template <class ELFT>
void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
const endianness E = ELFT::TargetEndianness;
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+
// 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 ||
@@ -481,9 +477,6 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
Val -= 0x7000;
}
- if (ELFT::Is64Bits || Config->MipsN32Abi)
- std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
-
switch (Type) {
case R_MIPS_32:
case R_MIPS_GPREL32:
@@ -497,25 +490,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write64<E>(Loc, Val);
break;
case R_MIPS_26:
- writeRelocation<E>(Loc, Val, 26, 2);
+ writeValue<E>(Loc, Val, 26, 2);
break;
case R_MIPS_GOT16:
// The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
// is updated addend (not a GOT index). In that case write high 16 bits
// to store a correct addend value.
if (Config->Relocatable) {
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeValue<E>(Loc, Val, 16, 0);
}
break;
case R_MICROMIPS_GOT16:
if (Config->Relocatable) {
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
}
break;
case R_MIPS_CALL16:
@@ -525,7 +518,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_TLS_GD:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
+ checkInt(Loc, Val, 16, Type);
LLVM_FALLTHROUGH;
case R_MIPS_CALL_LO16:
case R_MIPS_GOT_LO16:
@@ -534,28 +527,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCLO16:
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_LO16:
- writeRelocation<E>(Loc, Val, 16, 0);
+ writeValue<E>(Loc, Val, 16, 0);
break;
- case R_MICROMIPS_GOT_DISP:
- case R_MICROMIPS_GOT_PAGE:
case R_MICROMIPS_GPREL16:
case R_MICROMIPS_TLS_GD:
case R_MICROMIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_CALL16:
case R_MICROMIPS_CALL_LO16:
- case R_MICROMIPS_GOT_OFST:
case R_MICROMIPS_LO16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_GOTTPREL:
case R_MICROMIPS_TLS_TPREL_LO16:
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_GPREL7_S2:
- checkInt<7>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 7, 2);
+ checkInt(Loc, Val, 7, Type);
+ writeShuffleValue<E>(Loc, Val, 7, 2);
break;
case R_MIPS_CALL_HI16:
case R_MIPS_GOT_HI16:
@@ -563,86 +553,80 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCHI16:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MICROMIPS_CALL_HI16:
case R_MICROMIPS_GOT_HI16:
case R_MICROMIPS_HI16:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_TPREL_HI16:
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MIPS_HIGHER:
- writeRelocation<E>(Loc, Val + 0x80008000, 16, 32);
+ writeValue<E>(Loc, Val + 0x80008000, 16, 32);
break;
case R_MIPS_HIGHEST:
- writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48);
- break;
- case R_MICROMIPS_HIGHER:
- writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32);
- break;
- case R_MICROMIPS_HIGHEST:
- writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48);
+ writeValue<E>(Loc, Val + 0x800080008000, 16, 48);
break;
case R_MIPS_JALR:
case R_MICROMIPS_JALR:
// Ignore this optimization relocation for now
break;
case R_MIPS_PC16:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<18>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 18, Type);
+ writeValue<E>(Loc, Val, 16, 2);
break;
case R_MIPS_PC19_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<21>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 19, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
+ writeValue<E>(Loc, Val, 19, 2);
break;
case R_MIPS_PC21_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<23>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 21, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 23, Type);
+ writeValue<E>(Loc, Val, 21, 2);
break;
case R_MIPS_PC26_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<28>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 26, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 28, Type);
+ writeValue<E>(Loc, Val, 26, 2);
break;
case R_MIPS_PC32:
- writeRelocation<E>(Loc, Val, 32, 0);
+ writeValue<E>(Loc, Val, 32, 0);
break;
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC26_S1:
- checkInt<27>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 26, 1);
+ checkInt(Loc, Val, 27, Type);
+ writeShuffleValue<E>(Loc, Val, 26, 1);
break;
case R_MICROMIPS_PC7_S1:
- checkInt<8>(Loc, Val, Type);
+ checkInt(Loc, Val, 8, Type);
writeMicroRelocation16<E>(Loc, Val, 7, 1);
break;
case R_MICROMIPS_PC10_S1:
- checkInt<11>(Loc, Val, Type);
+ checkInt(Loc, Val, 11, Type);
writeMicroRelocation16<E>(Loc, Val, 10, 1);
break;
case R_MICROMIPS_PC16_S1:
- checkInt<17>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 1);
+ checkInt(Loc, Val, 17, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 1);
break;
case R_MICROMIPS_PC18_S3:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 18, 3);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 18, 3);
break;
case R_MICROMIPS_PC19_S2:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 19, 2);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 19, 2);
break;
case R_MICROMIPS_PC21_S1:
- checkInt<22>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 21, 1);
+ checkInt(Loc, Val, 22, Type);
+ writeShuffleValue<E>(Loc, Val, 21, 1);
break;
case R_MICROMIPS_PC23_S2:
- checkInt<25>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 23, 2);
+ checkInt(Loc, Val, 25, Type);
+ writeShuffleValue<E>(Loc, Val, 23, 2);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
@@ -651,19 +635,26 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const {
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
- Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST;
+ Type == R_MICROMIPS_LO16;
}
// Return true if the symbol is a PIC function.
template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) {
- typedef typename ELFT::Ehdr Elf_Ehdr;
- if (!Sym->Section || !Sym->isFunc())
+ if (!Sym->isFunc())
+ return false;
+
+ if (Sym->StOther & STO_MIPS_PIC)
+ return true;
+
+ if (!Sym->Section)
+ return false;
+
+ ObjFile<ELFT> *File =
+ cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>();
+ if (!File)
return false;
- auto *Sec = cast<InputSectionBase>(Sym->Section);
- const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
- return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Hdr->e_flags & EF_MIPS_PIC);
+ return File->getObj().getHeader()->e_flags & EF_MIPS_PIC;
}
template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp
index 754a47001579..98ceac3075e0 100644
--- a/ELF/Arch/MipsArchTree.cpp
+++ b/ELF/Arch/MipsArchTree.cpp
@@ -65,25 +65,30 @@ static StringRef getNanName(bool IsNan2008) {
static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
static void checkFlags(ArrayRef<FileFlags> Files) {
+ assert(!Files.empty() && "expected non-empty file list");
+
uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
bool Fp = Files[0].Flags & EF_MIPS_FP64;
- for (const FileFlags &F : Files.slice(1)) {
+ for (const FileFlags &F : Files) {
+ if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS)
+ error(toString(F.File) + ": microMIPS 64-bit is not supported");
+
uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
if (ABI != ABI2)
- error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" +
- getAbiName(ABI2) + "': " + toString(F.File));
+ error(toString(F.File) + ": ABI '" + getAbiName(ABI2) +
+ "' is incompatible with target ABI '" + getAbiName(ABI) + "'");
bool Nan2 = F.Flags & EF_MIPS_NAN2008;
if (Nan != Nan2)
- error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" +
- getNanName(Nan2) + ": " + toString(F.File));
+ error(toString(F.File) + ": -mnan=" + getNanName(Nan2) +
+ " is incompatible with target -mnan=" + getNanName(Nan));
bool Fp2 = F.Flags & EF_MIPS_FP64;
if (Fp != Fp2)
- error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" +
- getFpName(Fp2) + ": " + toString(F.File));
+ error(toString(F.File) + ": -mfp" + getFpName(Fp2) +
+ " is incompatible with target -mfp" + getFpName(Fp));
}
}
@@ -102,11 +107,13 @@ static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
for (const FileFlags &F : Files.slice(1)) {
bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
if (IsPic && !IsPic2)
- warn("linking abicalls code " + toString(Files[0].File) +
- " with non-abicalls file: " + toString(F.File));
+ warn(toString(F.File) +
+ ": linking non-abicalls code with abicalls code " +
+ toString(Files[0].File));
if (!IsPic && IsPic2)
- warn("linking non-abicalls code " + toString(Files[0].File) +
- " with abicalls file: " + toString(F.File));
+ warn(toString(F.File) +
+ ": linking abicalls code with non-abicalls code " +
+ toString(Files[0].File));
}
// Compute the result PIC/non-PIC flag.
@@ -326,7 +333,7 @@ static StringRef getMipsFpAbiName(uint8_t FpAbi) {
case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
return "-msoft-float";
case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
- return "-mips32r2 -mfp64 (old)";
+ return "-mgp32 -mfp64 (old)";
case Mips::Val_GNU_MIPS_ABI_FP_XX:
return "-mfpxx";
case Mips::Val_GNU_MIPS_ABI_FP_64:
@@ -343,9 +350,9 @@ uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
return NewFlag;
if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
- error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
- "' is incompatible with '" + getMipsFpAbiName(NewFlag) +
- "': " + FileName);
+ error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) +
+ "' is incompatible with target floating point ABI '" +
+ getMipsFpAbiName(OldFlag) + "'");
return OldFlag;
}
diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp
index 6af0df331df6..20cae0e59cf4 100644
--- a/ELF/Arch/PPC.cpp
+++ b/ELF/Arch/PPC.cpp
@@ -21,13 +21,18 @@ using namespace lld::elf;
namespace {
class PPC final : public TargetInfo {
public:
- PPC() { GotBaseSymOff = 0x8000; }
+ PPC();
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
};
} // namespace
+PPC::PPC() {
+ GotBaseSymOff = 0x8000;
+ GotBaseSymInGotPlt = false;
+}
+
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
index ac4021b5918d..fa3bf6c62a0d 100644
--- a/ELF/Arch/PPC64.cpp
+++ b/ELF/Arch/PPC64.cpp
@@ -14,12 +14,14 @@
#include "llvm/Support/Endian.h"
using namespace llvm;
+using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
+static uint64_t DynamicThreadPointerOffset = 0x8000;
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
@@ -39,11 +41,21 @@ namespace {
class PPC64 final : public TargetInfo {
public:
PPC64();
+ uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
+ void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void writeGotHeader(uint8_t *Buf) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
@@ -51,21 +63,35 @@ public:
// #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; }
+static uint16_t lo(uint64_t V) { return V; }
+static uint16_t hi(uint64_t V) { return V >> 16; }
+static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; }
+static uint16_t higher(uint64_t V) { return V >> 32; }
+static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
+static uint16_t highest(uint64_t V) { return V >> 48; }
+static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
PPC64::PPC64() {
- PltRel = GotRel = R_PPC64_GLOB_DAT;
+ GotRel = R_PPC64_GLOB_DAT;
+ PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
+ IRelativeRel = R_PPC64_IRELATIVE;
GotEntrySize = 8;
+ PltEntrySize = 4;
GotPltEntrySize = 8;
- PltEntrySize = 32;
- PltHeaderSize = 0;
+ GotBaseSymInGotPlt = false;
+ GotBaseSymOff = 0x8000;
+ GotHeaderEntriesNum = 1;
+ GotPltHeaderEntriesNum = 2;
+ PltHeaderSize = 60;
+ NeedsThunks = true;
+ TcbSize = 8;
+ TlsTpOffset = 0x7000;
+
+ TlsModuleIndexRel = R_PPC64_DTPMOD64;
+ TlsOffsetRel = R_PPC64_DTPREL64;
+
+ TlsGotRel = R_PPC64_TPREL64;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
@@ -80,6 +106,110 @@ PPC64::PPC64() {
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
+
+ TrapInstr =
+ (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
+}
+
+static uint32_t getEFlags(InputFile *File) {
+ if (Config->EKind == ELF64BEKind)
+ return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
+}
+
+// This file implements v2 ABI. This function makes sure that all
+// object files have v2 or an unspecified version as an ABI version.
+uint32_t PPC64::calcEFlags() const {
+ for (InputFile *F : ObjectFiles) {
+ uint32_t Flag = getEFlags(F);
+ if (Flag == 1)
+ error(toString(F) + ": ABI version 1 is not supported");
+ else if (Flag > 2)
+ error(toString(F) + ": unrecognized e_flags: " + Twine(Flag));
+ }
+ return 2;
+}
+
+void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement.
+ // The general dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+ // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsgd@ha into nop
+ // addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, x@tprel@l
+
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ write32(Loc - EndianOffset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSGD16_LO:
+ write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38630000); // addi r3, r3
+ relocateOne(Loc + 4 + EndianOffset, R_PPC64_TPREL16_LO, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+
+void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
+ // The local dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x
+ // addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsld@ha into nop
+ // addi r3, r3, x@got@tlsld@l into addis r3, r13, 0
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, 4096
+
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ switch (Type) {
+ case R_PPC64_GOT_TLSLD16_HA:
+ write32(Loc - EndianOffset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSLD16_LO:
+ write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0
+ break;
+ case R_PPC64_TLSLD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38631000); // addi r3, r3, 4096
+ break;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ relocateOne(Loc, Type, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
+ }
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
@@ -95,48 +225,162 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL24:
- return R_PPC_PLT_OPD;
+ return R_PPC_CALL_PLT;
+ case R_PPC64_REL16_LO:
+ case R_PPC64_REL16_HA:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
+ return R_PC;
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSGD16_LO:
+ return R_TLSGD_GOT;
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSLD16_LO:
+ return R_TLSLD_GOT;
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_TPREL16_HI:
+ return R_GOT_OFF;
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ return R_TLSLD_GOT_OFF;
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHESTA:
+ return R_TLS;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HIGHER:
+ case R_PPC64_DTPREL16_HIGHERA:
+ case R_PPC64_DTPREL16_HIGHEST:
+ case R_PPC64_DTPREL16_HIGHESTA:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_DTPREL64:
+ return R_ABS;
+ case R_PPC64_TLSGD:
+ return R_TLSDESC_CALL;
+ case R_PPC64_TLSLD:
+ return R_TLSLD_HINT;
+ case R_PPC64_TLS:
+ return R_HINT;
default:
return R_ABS;
}
}
+void PPC64::writeGotHeader(uint8_t *Buf) const {
+ write64(Buf, getPPC64TocBase());
+}
+
+void PPC64::writePltHeader(uint8_t *Buf) const {
+ // The generic resolver stub goes first.
+ write32(Buf + 0, 0x7c0802a6); // mflr r0
+ write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
+ write32(Buf + 8, 0x7d6802a6); // mflr r11
+ write32(Buf + 12, 0x7c0803a6); // mtlr r0
+ write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
+ write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
+ write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
+ write32(Buf + 28, 0xe98b002c); // ld r12,44(r11)
+ write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11
+ write32(Buf + 36, 0xe98b0000); // ld r12,0(r11)
+ write32(Buf + 40, 0xe96b0008); // ld r11,8(r11)
+ write32(Buf + 44, 0x7d8903a6); // mtctr r12
+ write32(Buf + 48, 0x4e800420); // bctr
+
+ // The 'bcl' instruction will set the link register to the address of the
+ // following instruction ('mflr r11'). Here we store the offset from that
+ // instruction to the first entry in the GotPlt section.
+ int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8);
+ write64(Buf + 52, GotPltOffset);
+}
+
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
-
- // FIXME: What we should do, in theory, is get the offset of the function
- // descriptor in the .opd section, and use that as the offset from %r2 (the
- // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
- // be a pointer to the function descriptor in the .opd section. Using
- // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
- write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32be(Buf + 28, 0x4e800420); // bctr
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
- uint64_t V = Val - PPC64TocOffset;
+ // Relocations relative to the toc-base need to be adjusted by the Toc offset.
+ uint64_t TocBiasedVal = Val - PPC64TocOffset;
+ // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset.
+ uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset;
+
switch (Type) {
+ // TOC biased relocation.
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
- return {R_PPC64_ADDR16, V};
+ return {R_PPC64_ADDR16, TocBiasedVal};
case R_PPC64_TOC16_DS:
- return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_TOC16_HA:
- return {R_PPC64_ADDR16_HA, V};
+ return {R_PPC64_ADDR16_HA, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TPREL16_HI:
+ case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_TOC16_HI:
- return {R_PPC64_ADDR16_HI, V};
+ return {R_PPC64_ADDR16_HI, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
- return {R_PPC64_ADDR16_LO, V};
+ return {R_PPC64_ADDR16_LO, TocBiasedVal};
case R_PPC64_TOC16_LO_DS:
- return {R_PPC64_ADDR16_LO_DS, V};
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, TocBiasedVal};
+
+ // Dynamic Thread pointer biased relocation types.
+ case R_PPC64_DTPREL16:
+ return {R_PPC64_ADDR16, DTPBiasedVal};
+ case R_PPC64_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HA:
+ return {R_PPC64_ADDR16_HA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HI:
+ return {R_PPC64_ADDR16_HI, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHER:
+ return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHERA:
+ return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHEST:
+ return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHESTA:
+ return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO:
+ return {R_PPC64_ADDR16_LO, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL64:
+ return {R_PPC64_ADDR64, DTPBiasedVal};
+
default:
return {Type, Val};
}
@@ -149,68 +393,139 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_PPC64_ADDR14: {
- checkAlignment<4>(Loc, Val, Type);
+ checkAlignment(Loc, Val, 4, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
- write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
+ write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, Val);
+ case R_PPC64_TPREL16:
+ checkInt(Loc, Val, 16, Type);
+ write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
+ case R_PPC64_TPREL16_DS:
+ checkInt(Loc, Val, 16, Type);
+ write16(Loc, (read16(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
- write16be(Loc, applyPPCHa(Val));
+ case R_PPC64_TPREL16_HA:
+ write16(Loc, ha(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
- write16be(Loc, applyPPCHi(Val));
+ case R_PPC64_TPREL16_HI:
+ write16(Loc, hi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
- write16be(Loc, applyPPCHigher(Val));
+ case R_PPC64_TPREL16_HIGHER:
+ write16(Loc, higher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
- write16be(Loc, applyPPCHighera(Val));
+ case R_PPC64_TPREL16_HIGHERA:
+ write16(Loc, highera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
- write16be(Loc, applyPPCHighest(Val));
+ case R_PPC64_TPREL16_HIGHEST:
+ write16(Loc, highest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
- write16be(Loc, applyPPCHighesta(Val));
+ case R_PPC64_TPREL16_HIGHESTA:
+ write16(Loc, highesta(Val));
break;
case R_PPC64_ADDR16_LO:
- write16be(Loc, applyPPCLo(Val));
+ case R_PPC64_REL16_LO:
+ case R_PPC64_TPREL16_LO:
+ write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_REL16_LO:
- write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
+ case R_PPC64_TPREL16_LO_DS:
+ write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
- checkInt<32>(Loc, Val, Type);
- write32be(Loc, Val);
+ checkInt(Loc, Val, 32, Type);
+ write32(Loc, Val);
break;
case R_PPC64_ADDR64:
case R_PPC64_REL64:
case R_PPC64_TOC:
- write64be(Loc, Val);
+ write64(Loc, Val);
break;
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
- checkInt<24>(Loc, Val, Type);
- write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
+ checkInt(Loc, Val, 24, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
+ case R_PPC64_DTPREL64:
+ write64(Loc, Val - DynamicThreadPointerOffset);
+ break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
+bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // If a function is in the plt it needs to be called through
+ // a call stub.
+ return Type == R_PPC64_REL24 && S.isInPlt();
+}
+
+RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE)
+ return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
+ if (Expr == R_RELAX_TLS_LD_TO_LE)
+ return R_RELAX_TLS_LD_TO_LE_ABS;
+ return Expr;
+}
+
+// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
+// The general dynamic code sequence for a global `x` uses 4 instructions.
+// Instruction Relocation Symbol
+// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+// R_PPC64_REL24 __tls_get_addr
+// nop None None
+//
+// Relaxing to initial-exec entails:
+// 1) Convert the addis/addi pair that builds the address of the tls_index
+// struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
+// 2) Convert the call to __tls_get_addr to a nop.
+// 3) Convert the nop following the call to an add of the loaded offset to the
+// thread pointer.
+// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
+// used as the relaxation hint for both steps 2 and 3.
+void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to
+ // addis rT, r2, sym@got@tprel@ha.
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
+ return;
+ case R_PPC64_GOT_TLSGD16_LO: {
+ // Relax from addi r3, rA, sym@got@tlsgd@l to
+ // ld r3, sym@got@tprel@l(rA)
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16));
+ write32(Loc - EndianOffset, 0xE8600000 | InputRegister);
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
+ return;
+ }
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop
+ write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+ }
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp
index d9d6e1390407..36f5c836930e 100644
--- a/ELF/Arch/SPARCV9.cpp
+++ b/ELF/Arch/SPARCV9.cpp
@@ -77,23 +77,23 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_SPARC_32:
case R_SPARC_UA32:
// V-word32
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
write32be(Loc, Val);
break;
case R_SPARC_DISP32:
// V-disp32
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32be(Loc, Val);
break;
case R_SPARC_WDISP30:
case R_SPARC_WPLT30:
// V-disp30
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
break;
case R_SPARC_22:
// V-imm22
- checkUInt<22>(Loc, Val, Type);
+ checkUInt(Loc, Val, 22, Type);
write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
break;
case R_SPARC_GOT22:
@@ -103,7 +103,7 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_SPARC_WDISP19:
// V-disp19
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
break;
case R_SPARC_GOT10:
@@ -137,7 +137,7 @@ void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Off = PltHeaderSize + Index * PltEntrySize;
+ uint64_t Off = getPltEntryOffset(Index);
relocateOne(Buf, R_SPARC_22, Off);
relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
}
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index 10517bef14f3..19a0b6017f1a 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -21,7 +21,7 @@ using namespace lld;
using namespace lld::elf;
namespace {
-class X86 final : public TargetInfo {
+class X86 : public TargetInfo {
public:
X86();
RelExpr getRelExpr(RelType Type, const Symbol &S,
@@ -46,7 +46,6 @@ public:
} // namespace
X86::X86() {
- GotBaseSymOff = -1;
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
PltRel = R_386_JUMP_SLOT;
@@ -74,9 +73,9 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S,
case R_386_TLS_LDO_32:
return R_ABS;
case R_386_TLS_GD:
- return R_TLSGD;
+ return R_TLSGD_GOT_FROM_END;
case R_386_TLS_LDM:
- return R_TLSLD;
+ return R_TLSLD_GOT_FROM_END;
case R_386_PLT32:
return R_PLT_PC;
case R_386_PC8:
@@ -224,7 +223,7 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
}
write32le(Buf + 7, RelOff);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
}
int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
@@ -256,15 +255,15 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
// being used for some 16-bit programs such as boot loaders, so
// we want to support them.
- checkUInt<8>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_386_PC8:
- checkInt<8>(Loc, Val, Type);
+ checkInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_386_16:
- checkUInt<16>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_386_PC16:
@@ -278,7 +277,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// current location subtracted from it.
// We just check that Val fits in 17 bits. This misses some cases, but
// should have no false positives.
- checkInt<17>(Loc, Val, Type);
+ checkInt(Loc, Val, 17, Type);
write16le(Loc, Val);
break;
case R_386_32:
@@ -301,7 +300,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_386_TLS_LE_32:
case R_386_TLS_TPOFF:
case R_386_TLS_TPOFF32:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
default:
@@ -399,7 +398,152 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
memcpy(Loc - 2, Inst, sizeof(Inst));
}
+namespace {
+class RetpolinePic : public X86 {
+public:
+ RetpolinePic();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+
+class RetpolineNoPic : public X86 {
+public:
+ RetpolineNoPic();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+} // namespace
+
+RetpolinePic::RetpolinePic() {
+ PltHeaderSize = 48;
+ PltEntrySize = 32;
+}
+
+void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write32le(Buf, S.getPltVA() + 17);
+}
+
+void RetpolinePic::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx)
+ 0x50, // 6: pushl %eax
+ 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax
+ 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next
+ 0xf3, 0x90, // 12: loop: pause
+ 0x0f, 0xae, 0xe8, // 14: lfence
+ 0xeb, 0xf9, // 17: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
+ 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)
+ 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx
+ 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)
+ 0x89, 0xc8, // 2b: mov %ecx, %eax
+ 0x59, // 2d: pop %ecx
+ 0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 9, GotPlt + 8);
+}
+
+void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x50, // pushl %eax
+ 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax
+ 0xe8, 0, 0, 0, 0, // call plt+0x20
+ 0xe9, 0, 0, 0, 0, // jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ unsigned Off = getPltEntryOffset(Index);
+ write32le(Buf + 3, GotPltEntryAddr - Ebx);
+ write32le(Buf + 8, -Off - 12 + 32);
+ write32le(Buf + 13, -Off - 17 + 18);
+ write32le(Buf + 18, RelOff);
+ write32le(Buf + 23, -Off - 27);
+}
+
+RetpolineNoPic::RetpolineNoPic() {
+ PltHeaderSize = 48;
+ PltEntrySize = 32;
+}
+
+void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write32le(Buf, S.getPltVA() + 16);
+}
+
+void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4
+ 0x50, // 6: pushl %eax
+ 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax
+ 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next
+ 0xf3, 0x90, // 11: loop: pause
+ 0x0f, 0xae, 0xe8, // 13: lfence
+ 0xeb, 0xf9, // 16: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3
+ 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16
+ 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)
+ 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx
+ 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)
+ 0x89, 0xc8, // 2b: mov %ecx, %eax
+ 0x59, // 2d: pop %ecx
+ 0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t GotPlt = InX::GotPlt->getVA();
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+}
+
+void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x50, // 0: pushl %eax
+ 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax
+ 0xe8, 0, 0, 0, 0, // 6: call plt+0x20
+ 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11
+ 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // 15: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ unsigned Off = getPltEntryOffset(Index);
+ write32le(Buf + 2, GotPltEntryAddr);
+ write32le(Buf + 7, -Off - 11 + 32);
+ write32le(Buf + 12, -Off - 16 + 17);
+ write32le(Buf + 17, RelOff);
+ write32le(Buf + 22, -Off - 26);
+}
+
TargetInfo *elf::getX86TargetInfo() {
- static X86 Target;
- return &Target;
+ if (Config->ZRetpolineplt) {
+ if (Config->Pic) {
+ static RetpolinePic T;
+ return &T;
+ }
+ static RetpolineNoPic T;
+ return &T;
+ }
+
+ static X86 T;
+ return &T;
}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index c977d9247d92..d4bdb3730c58 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -23,12 +23,12 @@ using namespace lld;
using namespace lld::elf;
namespace {
-template <class ELFT> class X86_64 final : public TargetInfo {
+template <class ELFT> class X86_64 : public TargetInfo {
public:
X86_64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -43,6 +43,8 @@ public:
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const override;
private:
void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
@@ -51,7 +53,6 @@ private:
} // namespace
template <class ELFT> X86_64<ELFT>::X86_64() {
- GotBaseSymOff = -1;
CopyRel = R_X86_64_COPY;
GotRel = R_X86_64_GLOB_DAT;
PltRel = R_X86_64_JUMP_SLOT;
@@ -106,6 +107,11 @@ RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_GOTTPOFF:
return R_GOT_PC;
+ case R_X86_64_GOTOFF64:
+ return R_GOTREL_FROM_END;
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPC64:
+ return R_GOTONLY_PC_FROM_END;
case R_X86_64_NONE:
return R_NONE;
default:
@@ -124,7 +130,7 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
template <class ELFT>
void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
// See comments in X86::writeGotPlt.
- write32le(Buf, S.getPltVA() + 6);
+ write64le(Buf, S.getPltVA() + 6);
}
template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
@@ -153,12 +159,14 @@ void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
write32le(Buf + 7, Index);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
}
-template <class ELFT> bool X86_64<ELFT>::isPicRel(RelType Type) const {
- return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
- Type != R_X86_64_TPOFF32;
+template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const {
+ if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 ||
+ Type == R_X86_64_SIZE64)
+ return Type;
+ return R_X86_64_NONE;
}
template <class ELFT>
@@ -285,20 +293,21 @@ template <class ELFT>
void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_X86_64_8:
- checkUInt<8>(Loc, Val, Type);
+ checkUInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_X86_64_16:
- checkUInt<16>(Loc, Val, Type);
+ checkUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_X86_64_32:
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_X86_64_32S:
case R_X86_64_TPOFF32:
case R_X86_64_GOT32:
+ case R_X86_64_GOTPC32:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
@@ -309,7 +318,7 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_SIZE32:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_X86_64_64:
@@ -318,6 +327,8 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_X86_64_PC64:
case R_X86_64_SIZE64:
case R_X86_64_GOT64:
+ case R_X86_64_GOTOFF64:
+ case R_X86_64_GOTPC64:
write64le(Loc, Val);
break;
default:
@@ -460,12 +471,180 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
write32le(Loc - 1, Val + 1);
}
-TargetInfo *elf::getX32TargetInfo() {
- static X86_64<ELF32LE> Target;
- return &Target;
+// This anonymous namespace works around a warning bug in
+// old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+namespace {
+
+// A split-stack prologue starts by checking the amount of stack remaining
+// in one of two ways:
+// A) Comparing of the stack pointer to a field in the tcb.
+// B) Or a load of a stack pointer offset with an lea to r10 or r11.
+template <>
+bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ // Replace "cmp %fs:0x70,%rsp" and subsequent branch
+ // with "stc, nopl 0x0(%rax,%rax,1)"
+ if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) {
+ memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8);
+ return true;
+ }
+
+ // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10"
+ if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) {
+ memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7);
+ return true;
+ }
+
+ // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11"
+ if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) {
+ memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7);
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+} // namespace
+
+// These nonstandard PLT entries are to migtigate Spectre v2 security
+// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect
+// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT
+// entries, we use a CALL followed by MOV and RET to do the same thing as an
+// indirect jump. That instruction sequence is so-called "retpoline".
+//
+// We have two types of retpoline PLTs as a size optimization. If `-z now`
+// is specified, all dynamic symbols are resolved at load-time. Thus, when
+// that option is given, we can omit code for symbol lazy resolution.
+namespace {
+template <class ELFT> class Retpoline : public X86_64<ELFT> {
+public:
+ Retpoline();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+
+template <class ELFT> class RetpolineZNow : public X86_64<ELFT> {
+public:
+ RetpolineZNow();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {}
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+} // namespace
+
+template <class ELFT> Retpoline<ELFT>::Retpoline() {
+ TargetInfo::PltHeaderSize = 48;
+ TargetInfo::PltEntrySize = 32;
}
-TargetInfo *elf::getX86_64TargetInfo() {
- static X86_64<ELF64LE> Target;
- return &Target;
+template <class ELFT>
+void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write64le(Buf, S.getPltVA() + 17);
+}
+
+template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip)
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11
+ 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next
+ 0xf3, 0x90, // 12: loop: pause
+ 0x0f, 0xae, 0xe8, // 14: lfence
+ 0xeb, 0xf9, // 17: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
+ 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp)
+ 0xc3, // 24: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t Plt = InX::Plt->getVA();
+ write32le(Buf + 2, GotPlt - Plt - 6 + 8);
+ write32le(Buf + 9, GotPlt - Plt - 13 + 16);
+}
+
+template <class ELFT>
+void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11
+ 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
+ 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
+ 0xe9, 0, 0, 0, 0, // 16: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint64_t Off = TargetInfo::getPltEntryOffset(Index);
+
+ write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
+ write32le(Buf + 8, -Off - 12 + 32);
+ write32le(Buf + 13, -Off - 17 + 18);
+ write32le(Buf + 18, Index);
+ write32le(Buf + 23, -Off - 27);
+}
+
+template <class ELFT> RetpolineZNow<ELFT>::RetpolineZNow() {
+ TargetInfo::PltHeaderSize = 32;
+ TargetInfo::PltEntrySize = 16;
}
+
+template <class ELFT>
+void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next
+ 0xf3, 0x90, // 5: loop: pause
+ 0x0f, 0xae, 0xe8, // 7: lfence
+ 0xeb, 0xf9, // a: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16
+ 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp)
+ 0xc3, // 14: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+}
+
+template <class ELFT>
+void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
+ write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
+}
+
+template <class ELFT> static TargetInfo *getTargetInfo() {
+ if (Config->ZRetpolineplt) {
+ if (Config->ZNow) {
+ static RetpolineZNow<ELFT> T;
+ return &T;
+ }
+ static Retpoline<ELFT> T;
+ return &T;
+ }
+
+ static X86_64<ELFT> T;
+ return &T;
+}
+
+TargetInfo *elf::getX32TargetInfo() { return getTargetInfo<ELF32LE>(); }
+TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo<ELF64LE>(); }
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index 7ec837841315..fb2f53a72025 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -12,6 +12,7 @@ add_lld_library(lldELF
Arch/AMDGPU.cpp
Arch/ARM.cpp
Arch/AVR.cpp
+ Arch/Hexagon.cpp
Arch/Mips.cpp
Arch/MipsArchTree.cpp
Arch/PPC.cpp
@@ -19,6 +20,7 @@ add_lld_library(lldELF
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
+ CallGraphSort.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
@@ -35,7 +37,6 @@ add_lld_library(lldELF
Relocations.cpp
ScriptLexer.cpp
ScriptParser.cpp
- Strings.cpp
SymbolTable.cpp
Symbols.cpp
SyntheticSections.cpp
@@ -46,6 +47,7 @@ add_lld_library(lldELF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BinaryFormat
+ BitWriter
Core
DebugInfoDWARF
LTO
diff --git a/ELF/CallGraphSort.cpp b/ELF/CallGraphSort.cpp
new file mode 100644
index 000000000000..33ac159a6e26
--- /dev/null
+++ b/ELF/CallGraphSort.cpp
@@ -0,0 +1,249 @@
+//===- CallGraphSort.cpp --------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implementation of Call-Chain Clustering from: Optimizing Function Placement
+/// for Large-Scale Data-Center Applications
+/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf
+///
+/// The goal of this algorithm is to improve runtime performance of the final
+/// executable by arranging code sections such that page table and i-cache
+/// misses are minimized.
+///
+/// Definitions:
+/// * Cluster
+/// * An ordered list of input sections which are layed out as a unit. At the
+/// beginning of the algorithm each input section has its own cluster and
+/// the weight of the cluster is the sum of the weight of all incomming
+/// edges.
+/// * Call-Chain Clustering (C³) Heuristic
+/// * Defines when and how clusters are combined. Pick the highest weighted
+/// input section then add it to its most likely predecessor if it wouldn't
+/// penalize it too much.
+/// * Density
+/// * The weight of the cluster divided by the size of the cluster. This is a
+/// proxy for the ammount of execution time spent per byte of the cluster.
+///
+/// It does so given a call graph profile by the following:
+/// * Build a weighted call graph from the call graph profile
+/// * Sort input sections by weight
+/// * For each input section starting with the highest weight
+/// * Find its most likely predecessor cluster
+/// * Check if the combined cluster would be too large, or would have too low
+/// a density.
+/// * If not, then combine the clusters.
+/// * Sort non-empty clusters by density
+///
+//===----------------------------------------------------------------------===//
+
+#include "CallGraphSort.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct Edge {
+ int From;
+ uint64_t Weight;
+};
+
+struct Cluster {
+ Cluster(int Sec, size_t S) {
+ Sections.push_back(Sec);
+ Size = S;
+ }
+
+ double getDensity() const {
+ if (Size == 0)
+ return 0;
+ return double(Weight) / double(Size);
+ }
+
+ std::vector<int> Sections;
+ size_t Size = 0;
+ uint64_t Weight = 0;
+ uint64_t InitialWeight = 0;
+ std::vector<Edge> Preds;
+};
+
+class CallGraphSort {
+public:
+ CallGraphSort();
+
+ DenseMap<const InputSectionBase *, int> run();
+
+private:
+ std::vector<Cluster> Clusters;
+ std::vector<const InputSectionBase *> Sections;
+
+ void groupClusters();
+};
+
+// Maximum ammount the combined cluster density can be worse than the original
+// cluster to consider merging.
+constexpr int MAX_DENSITY_DEGRADATION = 8;
+
+// Maximum cluster size in bytes.
+constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
+} // end anonymous namespace
+
+// Take the edge list in Config->CallGraphProfile, resolve symbol names to
+// Symbols, and generate a graph between InputSections with the provided
+// weights.
+CallGraphSort::CallGraphSort() {
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t> &Profile = Config->CallGraphProfile;
+ DenseMap<const InputSectionBase *, int> SecToCluster;
+
+ auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
+ auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size()));
+ if (Res.second) {
+ Sections.push_back(IS);
+ Clusters.emplace_back(Clusters.size(), IS->getSize());
+ }
+ return Res.first->second;
+ };
+
+ // Create the graph.
+ for (const auto &C : Profile) {
+ const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
+ const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
+ uint64_t Weight = C.second;
+
+ // Ignore edges between input sections belonging to different output
+ // sections. This is done because otherwise we would end up with clusters
+ // containing input sections that can't actually be placed adjacently in the
+ // output. This messes with the cluster size and density calculations. We
+ // would also end up moving input sections in other output sections without
+ // moving them closer to what calls them.
+ if (FromSB->getOutputSection() != ToSB->getOutputSection())
+ continue;
+
+ int From = GetOrCreateNode(FromSB);
+ int To = GetOrCreateNode(ToSB);
+
+ Clusters[To].Weight += Weight;
+
+ if (From == To)
+ continue;
+
+ // Add an edge
+ Clusters[To].Preds.push_back({From, Weight});
+ }
+ for (Cluster &C : Clusters)
+ C.InitialWeight = C.Weight;
+}
+
+// It's bad to merge clusters which would degrade the density too much.
+static bool isNewDensityBad(Cluster &A, Cluster &B) {
+ double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
+ if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION)
+ return true;
+ return false;
+}
+
+static void mergeClusters(Cluster &Into, Cluster &From) {
+ Into.Sections.insert(Into.Sections.end(), From.Sections.begin(),
+ From.Sections.end());
+ Into.Size += From.Size;
+ Into.Weight += From.Weight;
+ From.Sections.clear();
+ From.Size = 0;
+ From.Weight = 0;
+}
+
+// Group InputSections into clusters using the Call-Chain Clustering heuristic
+// then sort the clusters by density.
+void CallGraphSort::groupClusters() {
+ std::vector<int> SortedSecs(Clusters.size());
+ std::vector<Cluster *> SecToCluster(Clusters.size());
+
+ for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) {
+ SortedSecs[SI] = SI;
+ SecToCluster[SI] = &Clusters[SI];
+ }
+
+ std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
+ return Clusters[B].getDensity() < Clusters[A].getDensity();
+ });
+
+ for (int SI : SortedSecs) {
+ // Clusters[SI] is the same as SecToClusters[SI] here because it has not
+ // been merged into another cluster yet.
+ Cluster &C = Clusters[SI];
+
+ int BestPred = -1;
+ uint64_t BestWeight = 0;
+
+ for (Edge &E : C.Preds) {
+ if (BestPred == -1 || E.Weight > BestWeight) {
+ BestPred = E.From;
+ BestWeight = E.Weight;
+ }
+ }
+
+ // don't consider merging if the edge is unlikely.
+ if (BestWeight * 10 <= C.InitialWeight)
+ continue;
+
+ Cluster *PredC = SecToCluster[BestPred];
+ if (PredC == &C)
+ continue;
+
+ if (C.Size + PredC->Size > MAX_CLUSTER_SIZE)
+ continue;
+
+ if (isNewDensityBad(*PredC, C))
+ continue;
+
+ // NOTE: Consider using a disjoint-set to track section -> cluster mapping
+ // if this is ever slow.
+ for (int SI : C.Sections)
+ SecToCluster[SI] = PredC;
+
+ mergeClusters(*PredC, C);
+ }
+
+ // Remove empty or dead nodes. Invalidates all cluster indices.
+ llvm::erase_if(Clusters, [](const Cluster &C) {
+ return C.Size == 0 || C.Sections.empty();
+ });
+
+ // Sort by density.
+ std::stable_sort(Clusters.begin(), Clusters.end(),
+ [](const Cluster &A, const Cluster &B) {
+ return A.getDensity() > B.getDensity();
+ });
+}
+
+DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
+ groupClusters();
+
+ // Generate order.
+ llvm::DenseMap<const InputSectionBase *, int> OrderMap;
+ ssize_t CurOrder = 1;
+
+ for (const Cluster &C : Clusters)
+ for (int SecIndex : C.Sections)
+ OrderMap[Sections[SecIndex]] = CurOrder++;
+
+ return OrderMap;
+}
+
+// Sort sections by the profile data provided by -callgraph-profile-file
+//
+// This first builds a call graph based on the profile data then merges sections
+// according to the C³ huristic. All clusters are then sorted by a density
+// metric to further improve locality.
+DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
+ return CallGraphSort().run();
+}
diff --git a/ELF/CallGraphSort.h b/ELF/CallGraphSort.h
new file mode 100644
index 000000000000..3f96dc88f435
--- /dev/null
+++ b/ELF/CallGraphSort.h
@@ -0,0 +1,23 @@
+//===- CallGraphSort.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_CALL_GRAPH_SORT_H
+#define LLD_ELF_CALL_GRAPH_SORT_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+
+llvm::DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Config.h b/ELF/Config.h
index 74c325cb7cb1..ec804c5296bc 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_ELF_CONFIG_H
#define LLD_ELF_CONFIG_H
+#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -17,13 +18,13 @@
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Endian.h"
-
#include <vector>
namespace lld {
namespace elf {
class InputFile;
+class InputSectionBase;
enum ELFKind {
ELFNoneKind,
@@ -39,6 +40,9 @@ enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
+// For --icf={none,safe,all}.
+enum class ICFLevel { None, Safe, All };
+
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
@@ -79,21 +83,27 @@ struct Configuration {
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef Chroot;
llvm::StringRef DynamicLinker;
+ llvm::StringRef DwoDir;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef LTOObjPath;
+ llvm::StringRef LTOSampleProfile;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
+ llvm::StringRef ProgName;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef ThinLTOIndexOnlyArg;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
- std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> FilterList;
std::vector<llvm::StringRef> SearchPaths;
@@ -103,15 +113,20 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t>
+ CallGraphProfile;
bool AllowMultipleDefinition;
- bool AndroidPackDynRelocs = false;
+ bool AndroidPackDynRelocs;
bool ARMHasBlx = false;
bool ARMHasMovtMovw = false;
bool ARMJ1J2BranchEncoding = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool CheckSections;
bool CompressDebugSections;
+ bool Cref;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
@@ -123,14 +138,15 @@ struct Configuration {
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
+ bool GnuUnique;
bool HasDynamicList = false;
bool HasDynSymTab;
- bool ICF;
- bool ICFData;
+ bool IgnoreDataAddressEquality;
+ bool IgnoreFunctionAddressEquality;
+ bool LTODebugPassManager;
+ bool LTONewPassManager;
bool MergeArmExidx;
bool MipsN32Abi = false;
- bool NoGnuUnique;
- bool NoUndefinedVersion;
bool NoinhibitExec;
bool Nostdlib;
bool OFormatBinary;
@@ -138,7 +154,9 @@ struct Configuration {
bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
+ bool PrintIcfSections;
bool Relocatable;
+ bool RelrPackDynRelocs;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
@@ -146,12 +164,21 @@ struct Configuration {
bool SysvHash = false;
bool Target1Rel;
bool Trace;
- bool Verbose;
+ bool ThinLTOEmitImportsFiles;
+ bool ThinLTOIndexOnly;
+ bool UndefinedVersion;
+ bool UseAndroidRelrTags = false;
+ bool WarnBackrefs;
bool WarnCommon;
bool WarnMissingEntry;
+ bool WarnSymbolOrdering;
+ bool WriteAddends;
bool ZCombreloc;
+ bool ZCopyreloc;
bool ZExecstack;
- bool ZNocopyreloc;
+ bool ZHazardplt;
+ bool ZInitfirst;
+ bool ZKeepTextSectionPrefix;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
@@ -159,9 +186,10 @@ struct Configuration {
bool ZRelro;
bool ZRodynamic;
bool ZText;
- bool ExitEarly;
+ bool ZRetpolineplt;
bool ZWxneeded;
DiscardPolicy Discard;
+ ICFLevel ICF;
OrphanHandlingPolicy OrphanHandling;
SortSectionPolicy SortSection;
StripPolicy Strip;
@@ -173,6 +201,7 @@ struct Configuration {
uint16_t EMachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> ImageBase;
uint64_t MaxPageSize;
+ uint64_t MipsGotSize;
uint64_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
@@ -238,6 +267,12 @@ struct Configuration {
// The only instance of Configuration struct.
extern Configuration *Config;
+static inline void errorOrWarn(const Twine &Msg) {
+ if (!Config->NoinhibitExec)
+ error(Msg);
+ else
+ warn(Msg);
+}
} // namespace elf
} // namespace lld
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index cc76fea2ad5e..1fc552f011b6 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -30,9 +30,9 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
+#include "MarkLive.h"
#include "OutputSections.h"
#include "ScriptParser.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
@@ -42,12 +42,16 @@
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -66,16 +70,18 @@ using namespace lld::elf;
Configuration *elf::Config;
LinkerDriver *elf::Driver;
-static void setConfigs();
+static void setConfigs(opt::InputArgList &Args);
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
errorHandler().ColorDiagnostics = Error.has_colors();
+
InputSections.clear();
OutputSections.clear();
Tar = nullptr;
@@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
Symtab = make<SymbolTable>();
- Config->Argv = {Args.begin(), Args.end()};
+ Config->ProgName = Args[0];
- Driver->main(Args, CanExitEarly);
+ Driver->main(Args);
// Exit immediately if we don't need to return to the caller.
// This saves time because the overhead of calling destructors
// for all globally-allocated objects is not negligible.
- if (Config->ExitEarly)
+ if (CanExitEarly)
exitLld(errorCount() ? 1 : 0);
freeArena();
@@ -113,7 +119,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
std::pair<ELFKind, uint16_t> Ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(S)
- .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
+ {ELF64LEKind, EM_AARCH64})
.Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
@@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64lppc", {ELF64LEKind, EM_PPC64})
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
.Case("elf_i386", {ELF32LEKind, EM_386})
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
@@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
Files.push_back(
createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
- default:
+ case file_magic::bitcode:
+ case file_magic::elf_relocatable:
if (InLib)
Files.push_back(make<LazyObjFile>(MBRef, "", 0));
else
Files.push_back(createObjectFile(MBRef));
+ break;
+ default:
+ error(Path + ": unknown file type");
}
}
@@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) {
// 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) {
+static void initLLVM() {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
-
- // 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.
@@ -290,7 +295,9 @@ static void checkOptions(opt::InputArgList &Args) {
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)
+ if (Config->GdbIndex)
+ error("-r and --gdb-index may not be used together");
+ if (Config->ICF != ICFLevel::None)
error("-r and --icf may not be used together");
if (Config->Pie)
error("-r and -pie may not be used together");
@@ -310,7 +317,37 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
return false;
}
-void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
+static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
+ bool Default) {
+ for (auto *Arg : Args.filtered_reverse(OPT_z)) {
+ if (K1 == Arg->getValue())
+ return true;
+ if (K2 == Arg->getValue())
+ return false;
+ }
+ return Default;
+}
+
+static bool isKnown(StringRef S) {
+ return S == "combreloc" || S == "copyreloc" || S == "defs" ||
+ S == "execstack" || S == "hazardplt" || S == "initfirst" ||
+ S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" ||
+ S == "nodlopen" || S == "noexecstack" ||
+ S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
+ S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
+ S == "rodynamic" || S == "text" || S == "wxneeded" ||
+ S.startswith("max-page-size=") || S.startswith("stack-size=");
+}
+
+// Report an error for an unknown -z option.
+static void checkZOptions(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_z))
+ if (!isKnown(Arg->getValue()))
+ error("unknown -z value: " + StringRef(Arg->getValue()));
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
ELFOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -319,7 +356,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
// Handle -help
if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ printHelp();
return;
}
@@ -348,9 +385,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
if (Args.hasArg(OPT_version))
return;
- Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);
- errorHandler().ExitEarly = Config->ExitEarly;
-
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.
@@ -368,10 +402,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
readConfigs(Args);
- initLLVM(Args);
+ checkZOptions(Args);
+ initLLVM();
createFiles(Args);
+ if (errorCount())
+ return;
+
inferMachineType();
- setConfigs();
+ setConfigs(Args);
checkOptions(Args);
if (errorCount())
return;
@@ -482,6 +520,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) {
return Arg->getValue();
}
+static ICFLevel getICF(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all);
+ if (!Arg || Arg->getOption().getID() == OPT_icf_none)
+ return ICFLevel::None;
+ if (Arg->getOption().getID() == OPT_icf_safe)
+ return ICFLevel::Safe;
+ return ICFLevel::All;
+}
+
static StripPolicy getStrip(opt::InputArgList &Args) {
if (Args.hasArg(OPT_relocatable))
return StripPolicy::None;
@@ -556,6 +603,8 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::Fast, {}};
StringRef S = Arg->getValue();
+ if (S == "fast")
+ return {BuildIdKind::Fast, {}};
if (S == "md5")
return {BuildIdKind::Md5, {}};
if (S == "sha1" || S == "tree")
@@ -570,6 +619,57 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::None, {}};
}
+static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none");
+ if (S == "android")
+ return {true, false};
+ if (S == "relr")
+ return {false, true};
+ if (S == "android+relr")
+ return {true, true};
+
+ if (S != "none")
+ error("unknown -pack-dyn-relocs format: " + S);
+ return {false, false};
+}
+
+static void readCallGraph(MemoryBufferRef MB) {
+ // Build a map from symbol name to section
+ DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ SymbolNameToSymbol[Sym->getName()] = Sym;
+
+ for (StringRef L : args::getLines(MB)) {
+ SmallVector<StringRef, 3> Fields;
+ L.split(Fields, ' ');
+ uint64_t Count;
+ if (Fields.size() != 3 || !to_integer(Fields[2], Count))
+ fatal(MB.getBufferIdentifier() + ": parse error");
+ const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]);
+ const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]);
+ if (Config->WarnSymbolOrdering) {
+ if (!FromSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]);
+ if (!ToSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]);
+ }
+ if (!FromSym || !ToSym || Count == 0)
+ continue;
+ warnUnorderableSymbol(FromSym);
+ warnUnorderableSymbol(ToSym);
+ const Defined *FromSymD = dyn_cast<Defined>(FromSym);
+ const Defined *ToSymD = dyn_cast<Defined>(ToSym);
+ if (!FromSymD || !ToSymD)
+ continue;
+ const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section);
+ const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section);
+ if (!FromSB || !ToSB)
+ continue;
+ Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count;
+ }
+}
+
static bool getCompressDebugSections(opt::InputArgList &Args) {
StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
if (S == "none")
@@ -581,54 +681,98 @@ static bool getCompressDebugSections(opt::InputArgList &Args) {
return true;
}
-static int parseInt(StringRef S, opt::Arg *Arg) {
- int V = 0;
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- return V;
+static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args,
+ unsigned Id) {
+ auto *Arg = Args.getLastArg(Id);
+ if (!Arg)
+ return {"", ""};
+
+ StringRef S = Arg->getValue();
+ std::pair<StringRef, StringRef> Ret = S.split(';');
+ if (Ret.second.empty())
+ error(Arg->getSpelling() + " expects 'old;new' format, but got " + S);
+ return Ret;
+}
+
+// Parse the symbol ordering file and warn for any duplicate entries.
+static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) {
+ SetVector<StringRef> Names;
+ for (StringRef S : args::getLines(MB))
+ if (!Names.insert(S) && Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S);
+
+ return Names.takeVector();
+}
+
+static void parseClangOption(StringRef Opt, const Twine &Msg) {
+ std::string Err;
+ raw_string_ostream OS(Err);
+
+ const char *Argv[] = {Config->ProgName.data(), Opt.data()};
+ if (cl::ParseCommandLineOptions(2, Argv, "", &OS))
+ return;
+ OS.flush();
+ error(Msg + ": " + StringRef(Err).trim());
}
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+ errorHandler().Verbose = Args.hasArg(OPT_verbose);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+
Config->AllowMultipleDefinition =
- Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs");
+ Args.hasFlag(OPT_allow_multiple_definition,
+ OPT_no_allow_multiple_definition, false) ||
+ hasZOption(Args, "muldefs");
Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CheckSections =
+ Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
Config->Chroot = Args.getLastArgValue(OPT_chroot);
Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false);
Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Discard = getDiscard(Args);
+ Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr =
Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
- Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
+ Config->EnableNewDtags =
+ Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
Config->ExportDynamic =
Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
- errorHandler().FatalWarnings =
- Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->FilterList = args::getStrings(Args, OPT_filter);
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
+ Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
- Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false);
- Config->ICFData = Args.hasArg(OPT_icf_data);
+ Config->ICF = getICF(Args);
+ Config->IgnoreDataAddressEquality =
+ Args.hasArg(OPT_ignore_data_address_equality);
+ Config->IgnoreFunctionAddressEquality =
+ Args.hasArg(OPT_ignore_function_address_equality);
Config->Init = Args.getLastArgValue(OPT_init, "_init");
Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager);
+ Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);
Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
Config->MapFile = Args.getLastArgValue(OPT_Map);
- Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+ Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
Config->MergeArmExidx =
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
- Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
Config->OFormatBinary = isOutputFormatBinary(Args);
@@ -638,7 +782,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->Optimize = args::getInteger(Args, OPT_O, 1);
Config->OrphanHandling = getOrphanHandling(Args);
Config->OutputFile = Args.getLastArgValue(OPT_o);
- Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false);
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
+ Config->PrintIcfSections =
+ Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
Config->PrintGcSections =
Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
Config->Rpath = getRpath(Args);
@@ -658,46 +804,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ThinLTOCachePolicy = CHECK(
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOEmitImportsFiles =
+ Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
+ Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
+ Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOIndexOnlyArg =
+ Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
- ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+ Config->ThinLTOObjectSuffixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ Config->ThinLTOPrefixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);
Config->Trace = Args.hasArg(OPT_trace);
Config->Undefined = args::getStrings(Args, OPT_undefined);
+ Config->UndefinedVersion =
+ Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
+ Config->UseAndroidRelrTags = Args.hasFlag(
+ OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
- Config->Verbose = Args.hasArg(OPT_verbose);
- errorHandler().Verbose = Config->Verbose;
- Config->WarnCommon = Args.hasArg(OPT_warn_common);
- Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecstack = hasZOption(Args, "execstack");
- Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->WarnBackrefs =
+ Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
+ Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
+ Config->WarnSymbolOrdering =
+ Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
+ Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
+ Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
+ Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
+ Config->ZHazardplt = hasZOption(Args, "hazardplt");
+ Config->ZInitfirst = hasZOption(Args, "initfirst");
+ Config->ZKeepTextSectionPrefix = getZFlag(
+ Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
- Config->ZNow = hasZOption(Args, "now");
+ Config->ZNow = getZFlag(Args, "now", "lazy", false);
Config->ZOrigin = hasZOption(Args, "origin");
- Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZRelro = getZFlag(Args, "relro", "norelro", true);
+ Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");
Config->ZRodynamic = hasZOption(Args, "rodynamic");
Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0);
- Config->ZText = !hasZOption(Args, "notext");
+ Config->ZText = getZFlag(Args, "text", "notext", true);
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- // Parse LTO plugin-related options for compatibility with gold.
- for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) {
- StringRef S = Arg->getValue();
- if (S == "disable-verify")
- Config->DisableVerify = true;
- else if (S == "save-temps")
- Config->SaveTemps = true;
- else if (S.startswith("O"))
- Config->LTOO = parseInt(S.substr(1), Arg);
- else if (S.startswith("lto-partitions="))
- Config->LTOPartitions = parseInt(S.substr(15), Arg);
- else if (S.startswith("jobs="))
- Config->ThinLTOJobs = parseInt(S.substr(5), Arg);
- else if (!S.startswith("/") && !S.startswith("-fresolution=") &&
- !S.startswith("-pass-through=") && !S.startswith("mcpu=") &&
- !S.startswith("thinlto") && S != "-function-sections" &&
- S != "-data-sections")
- error(Arg->getSpelling() + ": unknown option: " + S);
- }
+ // Parse LTO options.
+ if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq))
+ parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())),
+ Arg->getSpelling());
+
+ for (auto *Arg : Args.filtered(OPT_plugin_opt))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
+
+ // Parse -mllvm options.
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + Twine(Config->LTOO));
@@ -740,17 +898,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
- if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) {
- StringRef S = Arg->getValue();
- if (S == "android")
- Config->AndroidPackDynRelocs = true;
- else if (S != "none")
- error("unknown -pack-dyn-relocs format: " + S);
- }
+ std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) =
+ getPackDynRelocs(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- Config->SymbolOrderingFile = args::getLines(*Buffer);
+ Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer);
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
@@ -778,32 +931,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
{Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
+ // If --export-dynamic-symbol=foo is given and symbol foo is defined in
+ // an object file in an archive file, that object file should be pulled
+ // out and linked. (It doesn't have to behave like that from technical
+ // point of view, but this is needed for compatibility with GNU.)
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->Undefined.push_back(Arg->getValue());
+
for (auto *Arg : Args.filtered(OPT_version_script))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readVersionScript(*Buffer);
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
+ if (Optional<MemoryBufferRef> Buffer = readFile(*Path))
+ readVersionScript(*Buffer);
+ } else {
+ error(Twine("cannot find version script ") + Arg->getValue());
+ }
}
// Some Config members do not directly correspond to any particular
// command line options, but computed based on other Config values.
// This function initialize such members. See Config.h for the details
// of these values.
-static void setConfigs() {
+static void setConfigs(opt::InputArgList &Args) {
ELFKind Kind = Config->EKind;
uint16_t Machine = Config->EMachine;
- // There is an ILP32 ABI for x86-64, although it's not very popular.
- // It is called the x32 ABI.
- bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
-
Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
Config->Endianness =
Config->IsLE ? support::endianness::little : support::endianness::big;
Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
- Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
Config->Pic = Config->Pie || Config->Shared;
Config->Wordsize = Config->Is64 ? 8 : 4;
+
+ // There is an ILP32 ABI for x86-64, although it's not very popular.
+ // It is called the x32 ABI.
+ bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+ // ELF defines two different ways to store relocation addends as shown below:
+ //
+ // Rel: Addends are stored to the location where relocations are applied.
+ // Rela: Addends are stored as part of relocation entry.
+ //
+ // In other words, Rela makes it easy to read addends at the price of extra
+ // 4 or 8 byte for each relocation entry. We don't know why ELF defined two
+ // different mechanisms in the first place, but this is how the spec is
+ // defined.
+ //
+ // You cannot choose which one, Rel or Rela, you want to use. Instead each
+ // ABI defines which one you need to use. The following expression expresses
+ // that.
+ Config->IsRela =
+ (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS;
+
+ // If the output uses REL relocations we must store the dynamic relocation
+ // addends to the output sections. We also store addends for RELA relocations
+ // if --apply-dynamic-relocs is used.
+ // We default to not writing the addends when using RELA relocations since
+ // any standard conforming tool can find it in r_addend.
+ Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
+ OPT_no_apply_dynamic_relocs, false) ||
+ !Config->IsRela;
}
// Returns a value of "-format" option.
@@ -818,6 +1006,10 @@ static bool getBinaryOption(StringRef S) {
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
+ // For --{push,pop}-state.
+ std::vector<std::tuple<bool, bool, bool>> Stack;
+
+ // Iterate over argv to process input files and positional arguments.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_library:
@@ -826,8 +1018,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_INPUT:
addFile(Arg->getValue(), /*WithLOption=*/false);
break;
+ case OPT_defsym: {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ break;
+ }
case OPT_script:
- if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) {
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
if (Optional<MemoryBufferRef> MB = readFile(*Path))
readLinkerScript(*MB);
break;
@@ -855,11 +1054,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_no_whole_archive:
InWholeArchive = false;
break;
+ case OPT_just_symbols:
+ if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) {
+ Files.push_back(createObjectFile(*MB));
+ Files.back()->JustSymbols = true;
+ }
+ break;
+ case OPT_start_group:
+ if (InputFile::IsInGroup)
+ error("nested --start-group");
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_group:
+ if (!InputFile::IsInGroup)
+ error("stray --end-group");
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
case OPT_start_lib:
+ if (InLib)
+ error("nested --start-lib");
+ if (InputFile::IsInGroup)
+ error("may not nest --start-lib in --start-group");
InLib = true;
+ InputFile::IsInGroup = true;
break;
case OPT_end_lib:
+ if (!InLib)
+ error("stray --end-lib");
InLib = false;
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_push_state:
+ Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+ break;
+ case OPT_pop_state:
+ if (Stack.empty()) {
+ error("unbalanced --push-state/--pop-state");
+ break;
+ }
+ std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+ Stack.pop_back();
break;
}
}
@@ -932,14 +1168,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
return Ret;
}
-static Optional<StringRef> getArchiveName(InputFile *File) {
- if (isa<ArchiveFile>(File))
- return File->getName();
- if (!File->ArchiveName.empty())
- return File->ArchiveName;
- return None;
-}
-
// Handles the -exclude-libs option. If a static library file is specified
// by the -exclude-libs option, all public symbols from the archive become
// private unless otherwise specified by version scripts or something.
@@ -947,16 +1175,132 @@ static Optional<StringRef> getArchiveName(InputFile *File) {
//
// This is not a popular option, but some programs such as bionic libc use it.
template <class ELFT>
-static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+static void excludeLibs(opt::InputArgList &Args) {
DenseSet<StringRef> Libs = getExcludeLibs(Args);
bool All = Libs.count("ALL");
- for (InputFile *File : Files)
- if (Optional<StringRef> Archive = getArchiveName(File))
- if (All || Libs.count(path::filename(*Archive)))
+ auto Visit = [&](InputFile *File) {
+ if (!File->ArchiveName.empty())
+ if (All || Libs.count(path::filename(File->ArchiveName)))
for (Symbol *Sym : File->getSymbols())
- if (!Sym->isLocal())
+ if (!Sym->isLocal() && Sym->File == File)
Sym->VersionId = VER_NDX_LOCAL;
+ };
+
+ for (InputFile *File : ObjectFiles)
+ Visit(File);
+
+ for (BitcodeFile *File : BitcodeFiles)
+ Visit(File);
+}
+
+// Force Sym to be entered in the output. Used for -u or equivalent.
+template <class ELFT> static void handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return;
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ Sym->IsUsedInRegularObj = true;
+
+ if (Sym->isLazy())
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+template <class ELFT> static bool shouldDemote(Symbol &Sym) {
+ // If all references to a DSO happen to be weak, the DSO is not added to
+ // DT_NEEDED. If that happens, we need to eliminate shared symbols created
+ // from the DSO. Otherwise, they become dangling references that point to a
+ // non-existent DSO.
+ if (auto *S = dyn_cast<SharedSymbol>(&Sym))
+ return !S->getFile<ELFT>().IsNeeded;
+
+ // We are done processing archives, so lazy symbols that were used but not
+ // found can be converted to undefined. We could also just delete the other
+ // lazy symbols, but that seems to be more work than it is worth.
+ return Sym.isLazy() && Sym.IsUsedInRegularObj;
+}
+
+// Some files, such as .so or files between -{start,end}-lib may be removed
+// after their symbols are added to the symbol table. If that happens, we
+// need to remove symbols that refer files that no longer exist, so that
+// they won't appear in the symbol table of the output file.
+//
+// We remove symbols by demoting them to undefined symbol.
+template <class ELFT> static void demoteSymbols() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (shouldDemote<ELFT>(*Sym)) {
+ bool Used = Sym->Used;
+ replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding,
+ Sym->StOther, Sym->Type);
+ Sym->Used = Used;
+ }
+ }
+}
+
+// The section referred to by S is considered address-significant. Set the
+// KeepUnique flag on the section if appropriate.
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (D->Section)
+ // We don't need to keep text sections unique under --icf=all even if they
+ // are address-significant.
+ if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR))
+ D->Section->KeepUnique = true;
+}
+
+// Record sections that define symbols mentioned in --keep-unique <symbol>
+// and symbols referred to by address-significance tables. These sections are
+// ineligible for ICF.
+template <class ELFT>
+static void findKeepUniqueSections(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_keep_unique)) {
+ StringRef Name = Arg->getValue();
+ auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name));
+ if (!D || !D->Section) {
+ warn("could not find symbol " + Name + " to keep unique");
+ continue;
+ }
+ D->Section->KeepUnique = true;
+ }
+
+ // --icf=all --ignore-data-address-equality means that we can ignore
+ // the dynsym and address-significance tables entirely.
+ if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality)
+ return;
+
+ // Symbols in the dynsym could be address-significant in other executables
+ // or DSOs, so we conservatively mark them as address-significant.
+ for (Symbol *S : Symtab->getSymbols())
+ if (S->includeInDynsym())
+ markAddrsig(S);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (InputFile *F : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(F);
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents =
+ check(Obj->getObj().getSectionContents(Obj->AddrsigSec));
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(F) + ": could not decode addrsig section: " + Err);
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
}
// Do actual linking. Note that when this function is called,
@@ -1007,14 +1351,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (InputFile *F : Files)
Symtab->addFile<ELFT>(F);
- // Process -defsym option.
- for (auto *Arg : Args.filtered(OPT_defsym)) {
- StringRef From;
- StringRef To;
- std::tie(From, To) = StringRef(Arg->getValue()).split('=');
- readDefsym(From, MemoryBufferRef(To, "-defsym"));
- }
-
// Now that we have every file, we can decide if we will need a
// dynamic symbol table.
// We need one if we were asked to export dynamic symbols or if we are
@@ -1031,23 +1367,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
- Symtab->fetchIfLazy<ELFT>(S);
+ handleUndefined<ELFT>(S);
// If an entry symbol is in a static archive, pull out that file now
// to complete the symbol table. After this, no new names except a
// few linker-synthesized ones will be added to the symbol table.
- Symtab->fetchIfLazy<ELFT>(Config->Entry);
+ handleUndefined<ELFT>(Config->Entry);
// Return if there were name resolution errors.
if (errorCount())
return;
- // Handle undefined symbols in DSOs.
- Symtab->scanShlibUndefined<ELFT>();
+ // Now when we read all script files, we want to finalize order of linker
+ // script commands, which can be not yet final because of INSERT commands.
+ Script->processInsertCommands();
+
+ // We want to declare linker script's symbols early,
+ // so that we can version them.
+ // They also might be exported if referenced by DSOs.
+ Script->declareSymbols();
// Handle the -exclude-libs option.
if (Args.hasArg(OPT_exclude_libs))
- excludeLibs<ELFT>(Args, Files);
+ excludeLibs<ELFT>(Args);
// Create ElfHeader early. We need a dummy section in
// addReservedSymbols to mark the created symbols as not absolute.
@@ -1059,16 +1401,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
addReservedSymbols();
// Apply version scripts.
- Symtab->scanVersionScript();
+ //
+ // For a relocatable output, version scripts don't make sense, and
+ // parsing a symbol version string (e.g. dropping "@ver1" from a symbol
+ // name "foo@ver1") rather do harm, so we don't call this if -r is given.
+ if (!Config->Relocatable)
+ Symtab->scanVersionScript();
// Create wrapped symbols for -wrap option.
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab->addSymbolWrap<ELFT>(Arg->getValue());
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (Config->ThinLTOIndexOnly)
+ return;
+
// Apply symbol renames for -wrap.
Symtab->applySymbolWrap();
@@ -1115,11 +1470,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- markLive<ELFT>();
decompressSections();
+ splitSections<ELFT>();
+ markLive<ELFT>();
+ demoteSymbols<ELFT>();
mergeSections();
- if (Config->ICF)
+ if (Config->ICF != ICFLevel::None) {
+ findKeepUniqueSections<ELFT>(Args);
doIcf<ELFT>();
+ }
+
+ // Read the callgraph now that we know what was gced or icfed
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 351d7926de71..99e194d9b66c 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -26,7 +26,7 @@ extern class LinkerDriver *Driver;
class LinkerDriver {
public:
- void main(ArrayRef<const char *> Args, bool CanExitEarly);
+ void main(ArrayRef<const char *> Args);
void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
@@ -63,11 +63,11 @@ enum {
#undef OPTION
};
-void printHelp(const char *Argv0);
+void printHelp();
std::string createResponseFile(const llvm::opt::InputArgList &Args);
llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
-llvm::Optional<std::string> searchLinkerScript(StringRef Path);
+llvm::Optional<std::string> searchScript(StringRef Path);
llvm::Optional<std::string> searchLibrary(StringRef Path);
} // namespace elf
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 2f7c9228851a..698e06edfe63 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -29,6 +29,7 @@
using namespace llvm;
using namespace llvm::sys;
+using namespace llvm::opt;
using namespace lld;
using namespace lld::elf;
@@ -58,18 +59,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) {
OPT_no_color_diagnostics);
if (!Arg)
return;
- else if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
else if (S == "never")
errorHandler().ColorDiagnostics = false;
else if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -87,6 +88,29 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
return cl::TokenizeGNUCommandLine;
}
+// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
+// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
+// option name and `bar` as a value. Unfortunately, OptParser cannot
+// handle an option with a space in it.
+//
+// In this function, we concatenate command line arguments so that
+// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
+// bit hacky, but looks like it is still better than handling --plugin-opt
+// options by hand.
+static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) {
+ SmallVector<const char *, 256> V;
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ StringRef S = Args[I];
+ if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) {
+ V.push_back(Saver.save(S + "=" + Args[I + 1]).data());
+ ++I;
+ } else {
+ V.push_back(Args[I]);
+ }
+ }
+ Args = std::move(V);
+}
+
// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
@@ -102,6 +126,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ concatLTOPluginOptions(Vec);
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
@@ -113,9 +138,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
return Args;
}
-void elf::printHelp(const char *Argv0) {
- ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/,
- true /*ShowAllAliases*/);
+void elf::printHelp() {
+ ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
@@ -123,13 +148,7 @@ void elf::printHelp(const char *Argv0) {
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
- // Here, we print out all the targets that we support.
- outs() << Argv0 << ": supported targets: "
- << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
- << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
- << "elf32-tradlittlemips elf32-x86-64 "
- << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
- << "elf64-tradlittlemips elf64-x86-64\n";
+ outs() << Config->ProgName << ": supported targets: elf\n";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -208,10 +227,10 @@ Optional<std::string> elf::searchLibrary(StringRef Name) {
return None;
}
-// If a linker script doesn't exist in the current directory, we also look for
-// the script in the '-L' search paths. This matches the behaviour of both '-T'
-// and linker script INPUT() directives in ld.bfd.
-Optional<std::string> elf::searchLinkerScript(StringRef Name) {
+// If a linker/version script doesn't exist in the current directory, we also
+// look for the script in the '-L' search paths. This matches the behaviour of
+// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
+Optional<std::string> elf::searchScript(StringRef Name) {
if (fs::exists(Name))
return Name.str();
return findFromSearchPaths(Name);
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 62abc3973e7e..20b32c0a96e6 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -20,18 +20,16 @@
#include "Config.h"
#include "InputSection.h"
#include "Relocations.h"
-#include "Strings.h"
-
+#include "Target.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.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;
using namespace lld;
using namespace lld::elf;
@@ -73,7 +71,7 @@ size_t EhReader::readEhRecordSize() {
// 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(D.data(), Config->Endianness);
+ uint64_t V = read32(D.data());
if (V == UINT32_MAX)
failOn(D.data(), "CIE/FDE too large");
uint64_t Size = V + 4;
diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp
index 8d0b5d8a2f1c..5cf240eeca56 100644
--- a/ELF/Filesystem.cpp
+++ b/ELF/Filesystem.cpp
@@ -44,7 +44,7 @@ using namespace lld::elf;
// The calling thread returns almost immediately.
void elf::unlinkAsync(StringRef Path) {
// Removing a file is async on windows.
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
sys::fs::remove(Path);
#else
if (!ThreadsEnabled || !sys::fs::exists(Path) ||
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp
index d27b57f95938..85449a200647 100644
--- a/ELF/GdbIndex.cpp
+++ b/ELF/GdbIndex.cpp
@@ -34,7 +34,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
.Case(".debug_ranges", &RangeSection)
.Case(".debug_line", &LineSection)
.Default(nullptr)) {
- Sec->maybeUncompress();
+ Sec->maybeDecompress();
M->Data = toStringRef(Sec->Data);
M->Sec = Sec;
continue;
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
index 41ae9d793c11..eba1ba22f879 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/GdbIndex.h
@@ -49,7 +49,6 @@ public:
return LineSection;
}
StringRef getFileName() const override { return ""; }
- StringRef getCUIndexSection() const override { return ""; }
StringRef getAbbrevSection() const override { return AbbrevSection; }
StringRef getStringSection() const override { return StrSection; }
StringRef getGnuPubNamesSection() const override {
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index b1e12e0590d5..ba413b132658 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -77,6 +77,8 @@
#include "Config.h"
#include "SymbolTable.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Writer.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -112,9 +114,9 @@ private:
size_t findBoundary(size_t Begin, size_t End);
void forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn);
+ llvm::function_ref<void(size_t, size_t)> Fn);
- void forEachClass(std::function<void(size_t, size_t)> Fn);
+ void forEachClass(llvm::function_ref<void(size_t, size_t)> Fn);
std::vector<InputSection *> Sections;
@@ -161,15 +163,38 @@ template <class ELFT> static uint32_t getHash(InputSection *S) {
// Returns true if section S is subject of ICF.
static bool isEligible(InputSection *S) {
- // Don't merge read only data sections unless --icf-data was passed.
- if (!(S->Flags & SHF_EXECINSTR) && !Config->ICFData)
+ if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC))
return false;
- // .init and .fini contains instructions that must be executed to
- // initialize and finalize the process. They cannot and should not
- // be merged.
- return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
- S->Name != ".init" && S->Name != ".fini";
+ // Don't merge writable sections. .data.rel.ro sections are marked as writable
+ // but are semantically read-only.
+ if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" &&
+ !S->Name.startswith(".data.rel.ro."))
+ return false;
+
+ // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections,
+ // so we don't consider them for ICF individually.
+ if (S->Flags & SHF_LINK_ORDER)
+ return false;
+
+ // Don't merge synthetic sections as their Data member is not valid and empty.
+ // The Data member needs to be valid for ICF as it is used by ICF to determine
+ // the equality of section contents.
+ if (isa<SyntheticSection>(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.
+ if (S->Name == ".init" || S->Name == ".fini")
+ return false;
+
+ // A user program may enumerate sections named with a C identifier using
+ // __start_* and __stop_* symbols. We cannot ICF any such sections because
+ // that could change program semantics.
+ if (isValidCIdentifier(S->Name))
+ return false;
+
+ return true;
}
// Split an equivalence class into smaller classes.
@@ -214,9 +239,6 @@ template <class ELFT>
template <class RelTy>
bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
const InputSection *SecB, ArrayRef<RelTy> RB) {
- if (RA.size() != RB.size())
- return false;
-
for (size_t I = 0; I < RA.size(); ++I) {
if (RA[I].r_offset != RB[I].r_offset ||
RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL))
@@ -284,6 +306,13 @@ bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
A->getSize() != B->getSize() || A->Data != B->Data)
return false;
+ // If two sections have different output sections, we cannot merge them.
+ // FIXME: This doesn't do the right thing in the case where there is a linker
+ // script. We probably need to move output section assignment before ICF to
+ // get the correct behaviour here.
+ if (getOutputSectionName(A) != getOutputSectionName(B))
+ return false;
+
if (A->AreRelocsRela)
return constantEq(A, A->template relas<ELFT>(), B,
B->template relas<ELFT>());
@@ -350,17 +379,12 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
// vector. Therefore, Sections vector can be considered as contiguous
// groups of sections, grouped by the class.
//
-// This function calls Fn on every group that starts within [Begin, End).
-// Note that a group must start in that range but doesn't necessarily
-// have to end before End.
+// This function calls Fn on every group within [Begin, End).
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn) {
- if (Begin > 0)
- Begin = findBoundary(Begin - 1, End);
-
+ llvm::function_ref<void(size_t, size_t)> Fn) {
while (Begin < End) {
- size_t Mid = findBoundary(Begin, Sections.size());
+ size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
}
@@ -368,7 +392,7 @@ void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
// Call Fn on each equivalence class.
template <class ELFT>
-void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
+void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
// If threading is disabled or the number of sections are
// too small to use threading, call Fn sequentially.
if (!ThreadsEnabled || Sections.size() < 1024) {
@@ -380,16 +404,32 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
Current = Cnt % 2;
Next = (Cnt + 1) % 2;
- // Split sections into 256 shards and call Fn in parallel.
- size_t NumShards = 256;
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- parallelForEachN(0, NumShards, [&](size_t I) {
- size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
- forEachClassRange(I * Step, End, Fn);
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Sections.size();
+
+ parallelForEachN(1, NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Sections.size());
+ });
+
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I])
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
});
++Cnt;
}
+static void print(const Twine &S) {
+ if (Config->PrintIcfSections)
+ message(S);
+}
+
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
@@ -401,7 +441,7 @@ template <class ELFT> void ICF<ELFT>::run() {
// Initially, we use hash values to partition sections.
parallelForEach(Sections, [&](InputSection *S) {
// Set MSB to 1 to avoid collisions with non-hash IDs.
- S->Class[0] = getHash<ELFT>(S) | (1 << 31);
+ S->Class[0] = getHash<ELFT>(S) | (1U << 31);
});
// From now on, sections in Sections vector are ordered so that sections
@@ -424,25 +464,21 @@ template <class ELFT> void ICF<ELFT>::run() {
log("ICF needed " + Twine(Cnt) + " iterations");
// Merge sections by the equivalence class.
- forEachClass([&](size_t Begin, size_t End) {
+ forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) {
if (End - Begin == 1)
return;
-
- log("selected " + Sections[Begin]->Name);
+ print("selected section " + toString(Sections[Begin]));
for (size_t I = Begin + 1; I < End; ++I) {
- log(" removed " + Sections[I]->Name);
+ print(" removing identical section " + toString(Sections[I]));
Sections[Begin]->replace(Sections[I]);
+
+ // At this point we know sections merged are fully identical and hence
+ // we want to remove duplicate implicit dependencies such as link order
+ // and relocation sections.
+ for (InputSection *IS : Sections[I]->DependentSections)
+ IS->Live = false;
}
});
-
- // Mark ARM Exception Index table sections that refer to folded code
- // sections as not live. These sections have an implict dependency
- // via the link order dependency.
- if (Config->EMachine == EM_ARM)
- for (InputSectionBase *Sec : InputSections)
- if (auto *S = dyn_cast<InputSection>(Sec))
- if (S->Flags & SHF_LINK_ORDER)
- S->Live = S->getLinkOrderDep()->Live;
}
// ICF entry point function.
diff --git a/ELF/ICF.h b/ELF/ICF.h
index 24219855fc17..a6c8636ead6d 100644
--- a/ELF/ICF.h
+++ b/ELF/ICF.h
@@ -12,8 +12,10 @@
namespace lld {
namespace elf {
+
template <class ELFT> void doIcf();
-}
+
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index f514870ca84a..6da722f6f30e 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -38,14 +38,23 @@ using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf;
+bool InputFile::IsInGroup;
+uint32_t InputFile::NextGroupId;
std::vector<BinaryFile *> elf::BinaryFiles;
std::vector<BitcodeFile *> elf::BitcodeFiles;
+std::vector<LazyObjFile *> elf::LazyObjFiles;
std::vector<InputFile *> elf::ObjectFiles;
std::vector<InputFile *> elf::SharedFiles;
TarWriter *elf::Tar;
-InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+InputFile::InputFile(Kind K, MemoryBufferRef M)
+ : MB(M), GroupId(NextGroupId), FileKind(K) {
+ // All files within the same --{start,end}-group get the same group ID.
+ // Otherwise, a new file will get a new group ID.
+ if (!IsInGroup)
+ ++NextGroupId;
+}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
// The --chroot option changes our virtual root directory.
@@ -55,7 +64,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
log(Path);
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path, -1, false);
if (auto EC = MBOrErr.getError()) {
error("cannot open " + Path + ": " + EC.message());
return None;
@@ -115,51 +124,60 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
}
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this));
- const DWARFObject &Obj = Dwarf.getDWARFObj();
- DwarfLine.reset(new DWARFDebugLine);
+ Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
+ const DWARFObject &Obj = Dwarf->getDWARFObj();
DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
Config->Wordsize);
- // The second parameter is offset in .debug_line section
- // for compilation unit (CU) of interest. We have only one
- // CU (object file), so offset is always 0.
- // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5
- // needs it in order to find indirect strings.
- const DWARFDebugLine::LineTable *LT =
- DwarfLine->getOrParseLineTable(LineData, 0, nullptr);
-
- // Return if there is no debug information about CU available.
- if (!Dwarf.getNumCompileUnits())
- return;
-
- // Loop over variable records and insert them to VariableLoc.
- DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0);
- for (const auto &Entry : CU->dies()) {
- DWARFDie Die(CU, &Entry);
- // Skip all tags that are not variables.
- if (Die.getTag() != dwarf::DW_TAG_variable)
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) {
+ auto Report = [](Error Err) {
+ handleAllErrors(std::move(Err),
+ [](ErrorInfoBase &Info) { warn(Info.message()); });
+ };
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLT =
+ Dwarf->getLineTableForUnit(CU.get(), Report);
+ const DWARFDebugLine::LineTable *LT = nullptr;
+ if (ExpectedLT)
+ LT = *ExpectedLT;
+ else
+ Report(ExpectedLT.takeError());
+ if (!LT)
continue;
+ LineTables.push_back(LT);
- // Skip if a local variable because we don't need them for generating error
- // messages. In general, only non-local symbols can fail to be linked.
- if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
- continue;
+ // Loop over variable records and insert them to VariableLoc.
+ for (const auto &Entry : CU->dies()) {
+ DWARFDie Die(CU.get(), &Entry);
+ // Skip all tags that are not variables.
+ if (Die.getTag() != dwarf::DW_TAG_variable)
+ continue;
- // Get the source filename index for the variable.
- unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
- if (!LT->hasFileAtIndex(File))
- continue;
+ // Skip if a local variable because we don't need them for generating
+ // error messages. In general, only non-local symbols can fail to be
+ // linked.
+ if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
+ continue;
- // Get the line number on which the variable is declared.
- unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+ // Get the source filename index for the variable.
+ unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
+ if (!LT->hasFileAtIndex(File))
+ continue;
- // Get the name of the variable and add the collected information to
- // VariableLoc. Usually Name is non-empty, but it can be empty if the input
- // object file lacks some debug info.
- StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), "");
- if (!Name.empty())
- VariableLoc.insert({Name, {File, Line}});
+ // Get the line number on which the variable is declared.
+ unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+
+ // Here we want to take the variable name to add it into VariableLoc.
+ // Variable can have regular and linkage name associated. At first, we try
+ // to get linkage name as it can be different, for example when we have
+ // two variables in different namespaces of the same object. Use common
+ // name otherwise, but handle the case when it also absent in case if the
+ // input object file lacks some debug info.
+ StringRef Name =
+ dwarf::toString(Die.find(dwarf::DW_AT_linkage_name),
+ dwarf::toString(Die.find(dwarf::DW_AT_name), ""));
+ if (!Name.empty())
+ VariableLoc.insert({Name, {LT, File, Line}});
+ }
}
}
@@ -170,11 +188,6 @@ Optional<std::pair<std::string, unsigned>>
ObjFile<ELFT>::getVariableLoc(StringRef Name) {
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
- // There is always only one CU so it's offset is 0.
- const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0);
- if (!LT)
- return None;
-
// Return if we have no debug information about data object.
auto It = VariableLoc.find(Name);
if (It == VariableLoc.end())
@@ -182,12 +195,12 @@ ObjFile<ELFT>::getVariableLoc(StringRef Name) {
// Take file name string from line table.
std::string FileName;
- if (!LT->getFileNameByIndex(
- It->second.first /* File */, nullptr,
+ if (!It->second.LT->getFileNameByIndex(
+ It->second.File, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName))
return None;
- return std::make_pair(FileName, It->second.second /*Line*/);
+ return std::make_pair(FileName, It->second.Line);
}
// Returns source line information for a given offset
@@ -197,29 +210,15 @@ Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S,
uint64_t Offset) {
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
- // The offset to CU is 0.
- const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
- if (!Tbl)
- return None;
-
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
DILineInfo Info;
- Tbl->getFileLineInfoForAddress(
- S->getOffsetInFile() + Offset, nullptr,
- DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
- if (Info.Line == 0)
- return None;
- return Info;
-}
-
-// Returns source line information for a given offset
-// using DWARF debug info.
-template <class ELFT>
-std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) {
- if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
- return Info->FileName + ":" + std::to_string(Info->Line);
- return "";
+ for (const llvm::DWARFDebugLine::LineTable *LT : LineTables)
+ if (LT->getFileLineInfoForAddress(
+ S->getOffsetInFile() + Offset, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info))
+ return Info;
+ return None;
}
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
@@ -249,7 +248,7 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
template <class ELFT>
typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() {
- return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end());
+ return makeArrayRef(ELFSyms.begin() + FirstGlobal, ELFSyms.end());
}
template <class ELFT>
@@ -260,9 +259,9 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
- FirstNonLocal = Symtab->sh_info;
+ FirstGlobal = Symtab->sh_info;
ELFSyms = CHECK(getObj().symbols(Symtab), this);
- if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size())
+ if (FirstGlobal == 0 || FirstGlobal > ELFSyms.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
StringTable =
@@ -278,13 +277,22 @@ ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName)
template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
if (this->Symbols.empty())
return {};
- return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1);
+ return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1);
+}
+
+template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() {
+ return makeArrayRef(this->Symbols).slice(this->FirstGlobal);
}
template <class ELFT>
void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
- // Read section and symbol tables.
- initializeSections(ComdatGroups);
+ // Read a section table. JustSymbols is usually false.
+ if (this->JustSymbols)
+ initializeJustSymbols();
+ else
+ initializeSections(ComdatGroups);
+
+ // Read a symbol table.
initializeSymbols();
}
@@ -308,7 +316,7 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
// we use a section name as a signature.
//
// Such SHT_GROUP sections are invalid from the perspective of the ELF
- // standard, but GNU gold 1.14 (the neweset version as of July 2017) or
+ // standard, but GNU gold 1.14 (the newest version as of July 2017) or
// older produce such sections as outputs for the -r option, so we need
// a bug-compatibility.
if (Signature.empty() && Sym->getType() == STT_SECTION)
@@ -328,9 +336,19 @@ ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
}
template <class ELFT> bool ObjFile<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)
+ // On a regular link we don't merge sections if -O0 (default is -O1). This
+ // sometimes makes the linker significantly faster, although the output will
+ // be bigger.
+ //
+ // Doing the same for -r would create a problem as it would combine sections
+ // with different sh_entsize. One option would be to just copy every SHF_MERGE
+ // section as is to the output. While this would produce a valid ELF file with
+ // usable SHF_MERGE sections, tools like (llvm-)?dwarfdump get confused when
+ // they see two .debug_str. We could have separate logic for combining
+ // SHF_MERGE sections based both on their name and sh_entsize, but that seems
+ // to be more trouble than it is worth. Instead, we just use the regular (-O1)
+ // logic for -r.
+ if (Config->Optimize == 0 && !Config->Relocatable)
return false;
// A mergeable section with size 0 is useless because they don't have
@@ -361,12 +379,33 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
return true;
}
+// This is for --just-symbols.
+//
+// --just-symbols is a very minor feature that allows you to link your
+// output against other existing program, so that if you load both your
+// program and the other program into memory, your output can refer the
+// other program's symbols.
+//
+// When the option is given, we link "just symbols". The section table is
+// initialized with null pointers.
+template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ this->Sections.resize(ObjSections.size());
+
+ for (const Elf_Shdr &Sec : ObjSections) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+ this->initSymtab(ObjSections, &Sec);
+ return;
+ }
+}
+
template <class ELFT>
void ObjFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this);
uint64_t Size = ObjSections.size();
this->Sections.resize(Size);
this->SectionStringTable =
@@ -381,6 +420,17 @@ void ObjFile<ELFT>::initializeSections(
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
+ if (Sec.sh_type == SHT_LLVM_ADDRSIG) {
+ // We ignore the address-significance table if we know that the object
+ // file was created by objcopy or ld -r. This is because these tools
+ // will reorder the symbols in the symbol table, invalidating the data
+ // in the address-significance table, which refers to symbols by index.
+ if (Sec.sh_link != 0)
+ this->AddrsigSec = &Sec;
+ else if (Config->ICF == ICFLevel::Safe)
+ warn(toString(this) + ": --icf=safe is incompatible with object "
+ "files created using objcopy or ld -r");
+ }
this->Sections[I] = &InputSection::Discarded;
continue;
}
@@ -431,8 +481,15 @@ void ObjFile<ELFT>::initializeSections(
if (Sec.sh_link >= this->Sections.size())
fatal(toString(this) +
": invalid sh_link index: " + Twine(Sec.sh_link));
- this->Sections[Sec.sh_link]->DependentSections.push_back(
- cast<InputSection>(this->Sections[I]));
+
+ InputSectionBase *LinkSec = this->Sections[Sec.sh_link];
+ InputSection *IS = cast<InputSection>(this->Sections[I]);
+ LinkSec->DependentSections.push_back(IS);
+ if (!isa<InputSection>(LinkSec))
+ error("a section " + IS->Name +
+ " with SHF_LINK_ORDER should not refer a non-regular "
+ "section: " +
+ toString(LinkSec));
}
}
}
@@ -527,10 +584,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
}
case SHT_RELA:
case SHT_REL: {
- // Find the relocation target section and associate this
- // section with it. Target can be discarded, for example
- // if it is a duplicated member of SHT_GROUP section, we
- // do not create or proccess relocatable sections then.
+ // Find a relocation target section and associate this section with that.
+ // Target may have been discarded if it is in a different section group
+ // and the group is discarded, even though it's a violation of the
+ // spec. We handle that situation gracefully by discarding dangling
+ // relocation sections.
InputSectionBase *Target = getRelocTarget(Sec);
if (!Target)
return nullptr;
@@ -545,32 +603,28 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
- // Mergeable sections with relocations are tricky because relocations
- // need to be taken into account when comparing section contents for
- // merging. It's not worth supporting such mergeable sections because
- // they are rare and it'd complicates the internal design (we usually
- // have to determine if two sections are mergeable early in the link
- // process much before applying relocations). We simply handle mergeable
- // sections with relocations as non-mergeable.
+ // ELF spec allows mergeable sections with relocations, but they are
+ // rare, and it is in practice hard to merge such sections by contents,
+ // because applying relocations at end of linking changes section
+ // contents. So, we simply handle such sections as non-mergeable ones.
+ // Degrading like this is acceptable because section merging is optional.
if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
Target = toRegularSection(MS);
this->Sections[Sec.sh_info] = Target;
}
- size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this);
Target->FirstRelocation = Rels.begin();
- NumRelocations = Rels.size();
+ Target->NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this);
Target->FirstRelocation = Rels.begin();
- NumRelocations = Rels.size();
+ Target->NumRelocations = Rels.size();
Target->AreRelocsRela = false;
}
- assert(isUInt<31>(NumRelocations));
- Target->NumRelocations = NumRelocations;
+ assert(isUInt<31>(Target->NumRelocations));
// Relocation sections processed by the linker are usually removed
// from the output, so returning `nullptr` for the normal case.
@@ -602,13 +656,24 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
if (Name == ".note.GNU-stack")
return &InputSection::Discarded;
- // Split stacks is a feature to support a discontiguous stack. At least
- // as of 2017, it seems that the feature is not being used widely.
- // Only GNU gold supports that. We don't. For the details about that,
- // see https://gcc.gnu.org/wiki/SplitStacks
+ // Split stacks is a feature to support a discontiguous stack,
+ // commonly used in the programming language Go. For the details,
+ // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
+ // for split stack will include a .note.GNU-split-stack section.
if (Name == ".note.GNU-split-stack") {
- error(toString(this) +
- ": object file compiled with -fsplit-stack is not supported");
+ if (Config->Relocatable) {
+ error("Cannot mix split-stack and non-split-stack in a relocatable link");
+ return &InputSection::Discarded;
+ }
+ this->SplitStack = true;
+ return &InputSection::Discarded;
+ }
+
+ // An object file cmpiled for split stack, but where some of the
+ // functions were compiled with the no_split_stack_attribute will
+ // include a .note.GNU-no-split-stack section.
+ if (Name == ".note.GNU-no-split-stack") {
+ this->SomeNoSplitStack = true;
return &InputSection::Discarded;
}
@@ -620,6 +685,14 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
if (Name.startswith(".gnu.linkonce."))
return &InputSection::Discarded;
+ // If we are creating a new .build-id section, strip existing .build-id
+ // sections so that the output won't have more than one .build-id.
+ // This is not usually a problem because input object files normally don't
+ // have .build-id sections, but you can create such files by
+ // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
+ if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None)
+ return &InputSection::Discarded;
+
// 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.
@@ -701,33 +774,33 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
File(std::move(File)) {}
template <class ELFT> void ArchiveFile::parse() {
- Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym));
+ Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
-std::pair<MemoryBufferRef, uint64_t>
-ArchiveFile::getMember(const Archive::Symbol *Sym) {
+InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) {
Archive::Child C =
- CHECK(Sym->getMember(), toString(this) +
- ": could not get the member for symbol " +
- Sym->getName());
+ CHECK(Sym.getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym.getName());
if (!Seen.insert(C.getChildOffset()).second)
- return {MemoryBufferRef(), 0};
+ return nullptr;
- MemoryBufferRef Ret =
+ MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
toString(this) +
": could not get the buffer for the member defining symbol " +
- Sym->getName());
+ Sym.getName());
+
+ if (Tar && C.getParent()->isThin())
+ Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer());
- if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer());
- if (C.getParent()->isThin())
- return {Ret, 0};
- return {Ret, C.getChildOffset()};
+ InputFile *File = createObjectFile(
+ MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset());
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT>
@@ -784,34 +857,42 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
}
}
+// Parses ".gnu.version" section which is a parallel array for the symbol table.
+// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL.
+template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() {
+ size_t Size = this->ELFSyms.size() - this->FirstGlobal;
+ if (!VersymSec)
+ return std::vector<uint32_t>(Size, VER_NDX_GLOBAL);
+
+ const char *Base = this->MB.getBuffer().data();
+ const Elf_Versym *Versym =
+ reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
+ this->FirstGlobal;
+
+ std::vector<uint32_t> Ret(Size);
+ for (size_t I = 0; I < Size; ++I)
+ Ret[I] = Versym[I].vs_index;
+ return Ret;
+}
+
// 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.
+// n. Version identifiers that are not definitions map to nullptr.
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.
- const char *Base = this->MB.getBuffer().data();
- Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
- this->FirstNonLocal;
+std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
+ if (!VerdefSec)
+ return {};
// 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);
+ std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1);
// Build the Verdefs array by following the chain of Elf_Verdef objects
// from the start of the .gnu.version_d section.
+ const char *Base = this->MB.getBuffer().data();
const char *Verdef = Base + VerdefSec->sh_offset;
for (unsigned I = 0; I != VerdefCount; ++I) {
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
@@ -825,74 +906,99 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
return Verdefs;
}
+// We do not usually care about alignments of data in shared object
+// files because the loader takes care of it. However, if we promote a
+// DSO symbol to point to .bss due to copy relocation, we need to keep
+// the original alignment requirements. We infer it in this function.
+template <class ELFT>
+uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Sym &Sym) {
+ uint64_t Ret = UINT64_MAX;
+ if (Sym.st_value)
+ Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
+ if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size())
+ Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign);
+ return (Ret > UINT32_MAX) ? 0 : Ret;
+}
+
// Fully parse the shared object file. This must be called after parseSoName().
+//
+// This function parses symbol versions. If a DSO has version information,
+// the file has a ".gnu.version_d" section which contains symbol version
+// definitions. Each symbol is associated to one version through a table in
+// ".gnu.version" section. That table is a parallel array for the symbol
+// table, and each table entry contains an index in ".gnu.version_d".
+//
+// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for
+// VER_NDX_GLOBAL. There's no table entry for these special versions in
+// ".gnu.version_d".
+//
+// The file format for symbol versioning is perhaps a bit more complicated
+// than necessary, but you can easily understand the code if you wrap your
+// head around the data structure described above.
template <class ELFT> void SharedFile<ELFT>::parseRest() {
- // Create mapping from version identifiers to Elf_Verdef entries.
- const Elf_Versym *Versym = nullptr;
- Verdefs = parseVerdefs(Versym);
-
+ Verdefs = parseVerdefs(); // parse .gnu.version_d
+ std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version
ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this);
+ // System libraries can have a lot of symbols with versions. Using a
+ // fixed buffer for computing the versions name (foo@ver) can save a
+ // lot of allocations.
+ SmallString<0> VersionedNameBuffer;
+
// Add symbols to the symbol table.
- Elf_Sym_Range Syms = this->getGlobalELFSyms();
- for (const Elf_Sym &Sym : Syms) {
- unsigned VersymIndex = VER_NDX_GLOBAL;
- if (Versym) {
- VersymIndex = Versym->vs_index;
- ++Versym;
- }
- bool Hidden = VersymIndex & VERSYM_HIDDEN;
- VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
+ ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms();
+ for (size_t I = 0; I < Syms.size(); ++I) {
+ const Elf_Sym &Sym = Syms[I];
StringRef Name = CHECK(Sym.getName(this->StringTable), this);
if (Sym.isUndefined()) {
- Undefs.push_back(Name);
+ Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType(),
+ /*CanOmitFromDynSym=*/false, this);
+ S->ExportDynamic = true;
continue;
}
+ // ELF spec requires that all local symbols precede weak or global
+ // symbols in each symbol table, and the index of first non-local symbol
+ // is stored to sh_info. If a local symbol appears after some non-local
+ // symbol, that's a violation of the spec.
if (Sym.getBinding() == STB_LOCAL) {
warn("found local symbol '" + Name +
"' in global part of symbol table in file " + toString(this));
continue;
}
- const Elf_Verdef *Ver = nullptr;
- if (VersymIndex != VER_NDX_GLOBAL) {
- if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) {
- error("corrupt input file: version definition index " +
- Twine(VersymIndex) + " for symbol " + Name +
- " is out of bounds\n>>> defined in " + toString(this));
- continue;
- }
- Ver = Verdefs[VersymIndex];
- } else {
- VersymIndex = 0;
- }
-
- // We do not usually care about alignments of data in shared object
- // files because the loader takes care of it. However, if we promote a
- // DSO symbol to point to .bss due to copy relocation, we need to keep
- // the original alignment requirements. We infer it here.
- uint64_t Alignment = 1;
- if (Sym.st_value)
- Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
- if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) {
- uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign;
- Alignment = std::min(Alignment, SecAlign);
- }
- if (Alignment > UINT32_MAX)
- error(toString(this) + ": alignment too large: " + Name);
+ // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly
+ // assigns VER_NDX_LOCAL to this section global symbol. Here is a
+ // workaround for this bug.
+ uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN;
+ if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL &&
+ Name == "_gp_disp")
+ continue;
- if (!Hidden)
- Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex);
+ uint64_t Alignment = getAlignment(Sections, Sym);
+ if (!(Versyms[I] & VERSYM_HIDDEN))
+ Symtab->addShared(Name, *this, Sym, Alignment, Idx);
// Also add the symbol with the versioned name to handle undefined symbols
// with explicit versions.
- if (Ver) {
- StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name;
- Name = Saver.save(Name + "@" + VerName);
- Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex);
+ if (Idx == VER_NDX_GLOBAL)
+ continue;
+
+ if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) {
+ error("corrupt input file: version definition index " + Twine(Idx) +
+ " for symbol " + Name + " is out of bounds\n>>> defined in " +
+ toString(this));
+ continue;
}
+
+ StringRef VerName =
+ this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name;
+ VersionedNameBuffer.clear();
+ Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
+ Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx);
}
}
@@ -925,8 +1031,9 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
case Triple::x86_64:
return EM_X86_64;
default:
- fatal(Path + ": could not infer e_machine from bitcode target triple " +
+ error(Path + ": could not infer e_machine from bitcode target triple " +
T.str());
+ return EM_NONE;
}
}
@@ -935,17 +1042,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
: InputFile(BitcodeKind, MB) {
this->ArchiveName = ArchiveName;
- // Here we pass a new MemoryBufferRef which is identified by ArchiveName
- // (the fully resolved path of the archive) + member name + offset of the
- // member in the archive.
- // ThinLTO uses the MemoryBufferRef identifier to access its internal
- // data structures and if two archives define two members with the same name,
- // this causes a collision which result in only one of the objects being
- // taken into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage).
- MemoryBufferRef MBRef(MB.getBuffer(),
- Saver.save(ArchiveName + MB.getBufferIdentifier() +
- utostr(OffsetInArchive)));
+ std::string Path = MB.getBufferIdentifier().str();
+ if (Config->ThinLTOIndexOnly)
+ Path = replaceThinLTOSuffix(MB.getBufferIdentifier());
+
+ // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
+ // name. If two archives define two members with the same name, this
+ // causes a collision which result in only one of the objects being taken
+ // into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage). So we append file offset to make
+ // filename unique.
+ MemoryBufferRef MBRef(
+ MB.getBuffer(),
+ Saver.save(ArchiveName + Path +
+ (ArchiveName.empty() ? "" : utostr(OffsetInArchive))));
+
Obj = CHECK(lto::InputFile::create(MBRef), this);
Triple T(Obj->getTargetTriple());
@@ -969,7 +1080,7 @@ template <class ELFT>
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile &F) {
- StringRef NameRef = Saver.save(ObjSym.getName());
+ StringRef Name = Saver.save(ObjSym.getName());
uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
@@ -978,20 +1089,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isUndefined())
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isCommon())
- return Symtab->addCommon(NameRef, ObjSym.getCommonSize(),
+ return Symtab->addCommon(Name, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding, Visibility,
STT_OBJECT, F);
- return Symtab->addBitcode(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, F);
+ return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym,
+ F);
}
template <class ELFT>
@@ -1026,8 +1137,8 @@ static ELFKind getELFKind(MemoryBufferRef MB) {
void BinaryFile::parse() {
ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
- auto *Section = make<InputSection>(nullptr, SHF_ALLOC | SHF_WRITE,
- SHT_PROGBITS, 8, Data, ".data");
+ auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ 8, Data, ".data");
Sections.push_back(Section);
// For each input file foo that is embedded to a result as a binary
@@ -1047,11 +1158,6 @@ void BinaryFile::parse() {
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
-static bool isBitcode(MemoryBufferRef MB) {
- using namespace sys::fs;
- return identify_magic(MB.getBuffer()) == file_magic::bitcode;
-}
-
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
if (isBitcode(MB))
@@ -1087,9 +1193,9 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
}
MemoryBufferRef LazyObjFile::getBuffer() {
- if (Seen)
+ if (AddedToLink)
return MemoryBufferRef();
- Seen = true;
+ AddedToLink = true;
return MB;
}
@@ -1097,66 +1203,72 @@ InputFile *LazyObjFile::fetch() {
MemoryBufferRef MBRef = getBuffer();
if (MBRef.getBuffer().empty())
return nullptr;
- return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+
+ InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT> void LazyObjFile::parse() {
- for (StringRef Sym : getSymbolNames())
- Symtab->addLazyObject<ELFT>(Sym, *this);
+ // A lazy object file wraps either a bitcode file or an ELF file.
+ if (isBitcode(this->MB)) {
+ std::unique_ptr<lto::InputFile> Obj =
+ CHECK(lto::InputFile::create(this->MB), this);
+ for (const lto::InputFile::Symbol &Sym : Obj->symbols())
+ if (!Sym.isUndefined())
+ Symtab->addLazyObject<ELFT>(Saver.save(Sym.getName()), *this);
+ return;
+ }
+
+ switch (getELFKind(this->MB)) {
+ case ELF32LEKind:
+ addElfSymbols<ELF32LE>();
+ return;
+ case ELF32BEKind:
+ addElfSymbols<ELF32BE>();
+ return;
+ case ELF64LEKind:
+ addElfSymbols<ELF64LE>();
+ return;
+ case ELF64BEKind:
+ addElfSymbols<ELF64BE>();
+ return;
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
-template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() {
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::SymRange Elf_Sym_Range;
+template <class ELFT> void LazyObjFile::addElfSymbols() {
+ ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer()));
+ ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
- ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer()));
- ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
- for (const Elf_Shdr &Sec : Sections) {
+ for (const typename ELFT::Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this);
- uint32_t FirstNonLocal = Sec.sh_info;
+ typename ELFT::SymRange Syms = CHECK(Obj.symbols(&Sec), this);
+ uint32_t FirstGlobal = Sec.sh_info;
StringRef StringTable =
CHECK(Obj.getStringTableForSymtab(Sec, Sections), this);
- std::vector<StringRef> V;
- for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+ for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal))
if (Sym.st_shndx != SHN_UNDEF)
- V.push_back(CHECK(Sym.getName(StringTable), this));
- return V;
+ Symtab->addLazyObject<ELFT>(CHECK(Sym.getName(StringTable), this),
+ *this);
+ return;
}
- return {};
}
-std::vector<StringRef> LazyObjFile::getBitcodeSymbols() {
- std::unique_ptr<lto::InputFile> Obj =
- CHECK(lto::InputFile::create(this->MB), this);
- std::vector<StringRef> V;
- for (const lto::InputFile::Symbol &Sym : Obj->symbols())
- if (!Sym.isUndefined())
- V.push_back(Saver.save(Sym.getName()));
- return V;
-}
+std::string elf::replaceThinLTOSuffix(StringRef Path) {
+ StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
+ StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
-// Returns a vector of globally-visible defined symbol names.
-std::vector<StringRef> LazyObjFile::getSymbolNames() {
- if (isBitcode(this->MB))
- return getBitcodeSymbols();
-
- switch (getELFKind(this->MB)) {
- case ELF32LEKind:
- return getElfSymbols<ELF32LE>();
- case ELF32BEKind:
- return getElfSymbols<ELF32BE>();
- case ELF64LEKind:
- return getElfSymbols<ELF64LE>();
- case ELF64BEKind:
- return getElfSymbols<ELF64BE>();
- default:
- llvm_unreachable("getELFKind");
+ if (!Path.endswith(Suffix)) {
+ error("-thinlto-object-suffix-replace=" + Suffix + ";" + Repl +
+ " was given, but " + Path + " does not end with the suffix");
+ return "";
}
+ return (Path.drop_back(Suffix.size()) + Repl).str();
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index dda1de81570c..0db3203b0ba2 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -12,22 +12,20 @@
#include "Config.h"
#include "lld/Common/ErrorHandler.h"
-
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/Threading.h"
-
#include <map>
namespace llvm {
-class DWARFDebugLine;
class TarWriter;
struct DILineInfo;
namespace lto {
@@ -48,7 +46,6 @@ namespace elf {
using llvm::object::Archive;
-class Lazy;
class Symbol;
// If -reproduce option is given, all input files are written
@@ -90,15 +87,15 @@ public:
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
ArrayRef<Symbol *> getSymbols() {
- assert(FileKind == ObjKind || FileKind == BitcodeKind ||
- FileKind == ArchiveKind);
+ assert(FileKind == BinaryKind || FileKind == ObjKind ||
+ FileKind == BitcodeKind);
return Symbols;
}
// 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;
+ std::string 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.
@@ -112,6 +109,20 @@ public:
std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
uint64_t Offset);
+ // True if this is an argument for --just-symbols. Usually false.
+ bool JustSymbols = false;
+
+ // GroupId is used for --warn-backrefs which is an optional error
+ // checking feature. All files within the same --{start,end}-group or
+ // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+ // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+ uint32_t GroupId;
+ static bool IsInGroup;
+ static uint32_t NextGroupId;
+
+ // Index of MIPS GOT built for this file.
+ llvm::Optional<size_t> MipsGotIndex;
+
protected:
InputFile(Kind K, MemoryBufferRef M);
std::vector<InputSectionBase *> Sections;
@@ -144,7 +155,7 @@ public:
protected:
ArrayRef<Elf_Sym> ELFSyms;
- uint32_t FirstNonLocal = 0;
+ uint32_t FirstGlobal = 0;
ArrayRef<Elf_Word> SymtabSHNDX;
StringRef StringTable;
void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab);
@@ -167,6 +178,7 @@ public:
static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
ArrayRef<Symbol *> getLocalSymbols();
+ ArrayRef<Symbol *> getGlobalSymbols();
ObjFile(MemoryBufferRef M, StringRef ArchiveName);
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@@ -182,9 +194,6 @@ public:
return getSymbol(SymIndex);
}
- // Returns source line information for a given offset.
- // If no information is available, returns "".
- std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name);
@@ -198,10 +207,22 @@ public:
// symbol table.
StringRef SourceFile;
+ // True if the file defines functions compiled with
+ // -fsplit-stack. Usually false.
+ bool SplitStack = false;
+
+ // True if the file defines functions compiled with -fsplit-stack,
+ // but had one or more functions with the no_split_stack attribute.
+ bool SomeNoSplitStack = false;
+
+ // Pointer to this input file's .llvm_addrsig section, if it has one.
+ const Elf_Shdr *AddrsigSec = nullptr;
+
private:
void
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
+ void initializeJustSymbols();
void initializeDwarf();
InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase *createInputSection(const Elf_Shdr &Sec);
@@ -217,8 +238,14 @@ private:
// reporting. Linker may find reasonable number of errors in a
// single object file, so we cache debugging information in order to
// parse it only once for each object file we link.
- std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
- llvm::DenseMap<StringRef, std::pair<unsigned, unsigned>> VariableLoc;
+ std::unique_ptr<llvm::DWARFContext> Dwarf;
+ std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables;
+ struct VarLoc {
+ const llvm::DWARFDebugLine::LineTable *LT;
+ unsigned File;
+ unsigned Line;
+ };
+ llvm::DenseMap<StringRef, VarLoc> VariableLoc;
llvm::once_flag InitDwarfLine;
};
@@ -242,13 +269,11 @@ public:
template <class ELFT> void parse();
MemoryBufferRef getBuffer();
InputFile *fetch();
+ bool AddedToLink = false;
private:
- std::vector<StringRef> getSymbolNames();
- template <class ELFT> std::vector<StringRef> getElfSymbols();
- std::vector<StringRef> getBitcodeSymbols();
+ template <class ELFT> void addElfSymbols();
- bool Seen = false;
uint64_t OffsetInArchive;
};
@@ -259,11 +284,11 @@ public:
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
- // Returns a memory buffer for a given symbol and the offset in the archive
- // for the member. An empty memory buffer and an offset of zero
- // is returned if we have already returned the same memory buffer.
- // (So that we don't instantiate same members more than once.)
- std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
+ // Pulls out an object file that contains a definition for Sym and
+ // returns it. If the same file was instantiated before, this
+ // function returns a nullptr (so we don't instantiate the same file
+ // more than once.)
+ InputFile *fetch(const Archive::Symbol &Sym);
private:
std::unique_ptr<Archive> File;
@@ -290,7 +315,6 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Versym Elf_Versym;
- std::vector<StringRef> Undefs;
const Elf_Shdr *VersymSec = nullptr;
const Elf_Shdr *VerdefSec = nullptr;
@@ -298,8 +322,6 @@ public:
std::vector<const Elf_Verdef *> Verdefs;
std::string SoName;
- llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
-
static bool classof(const InputFile *F) {
return F->kind() == Base::SharedKind;
}
@@ -308,7 +330,9 @@ public:
void parseSoName();
void parseRest();
- std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+ uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym);
+ std::vector<const Elf_Verdef *> parseVerdefs();
+ std::vector<uint32_t> parseVersyms();
struct NeededVer {
// The string table offset of the version name in the output file.
@@ -337,8 +361,15 @@ InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
uint64_t OffsetInArchive = 0);
InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
+inline bool isBitcode(MemoryBufferRef MB) {
+ return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode;
+}
+
+std::string replaceThinLTOSuffix(StringRef Path);
+
extern std::vector<BinaryFile *> BinaryFiles;
extern std::vector<BitcodeFile *> BitcodeFiles;
+extern std::vector<LazyObjFile *> LazyObjFiles;
extern std::vector<InputFile *> ObjectFiles;
extern std::vector<InputFile *> SharedFiles;
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 93baefadce6e..d6e9a19051e0 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -14,6 +14,7 @@
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -26,7 +27,10 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/xxhash.h"
+#include <algorithm>
#include <mutex>
+#include <set>
+#include <vector>
using namespace llvm;
using namespace llvm::ELF;
@@ -45,32 +49,6 @@ std::string lld::toString(const InputSectionBase *Sec) {
return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
}
-DenseMap<SectionBase *, int> elf::buildSectionOrder() {
- DenseMap<SectionBase *, int> SectionOrder;
- if (Config->SymbolOrderingFile.empty())
- return SectionOrder;
-
- // Build a map from symbols to their priorities. Symbols that didn't
- // appear in the symbol ordering file have the lowest priority 0.
- // All explicitly mentioned symbols have negative (higher) priorities.
- DenseMap<StringRef, int> SymbolOrder;
- int Priority = -Config->SymbolOrderingFile.size();
- for (StringRef S : Config->SymbolOrderingFile)
- SymbolOrder.insert({S, Priority++});
-
- // Build a map from sections to their priorities.
- for (InputFile *File : ObjectFiles) {
- for (Symbol *Sym : File->getSymbols()) {
- auto *D = dyn_cast<Defined>(Sym);
- if (!D || !D->Section)
- continue;
- int &Priority = SectionOrder[D->Section];
- Priority = std::min(Priority, SymbolOrder.lookup(D->getName()));
- }
- }
- return SectionOrder;
-}
-
template <class ELFT>
static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File,
const typename ELFT::Shdr &Hdr) {
@@ -168,12 +146,8 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const {
return Offset == uint64_t(-1) ? OS->Size : Offset;
}
case Regular:
- return cast<InputSection>(this)->OutSecOff + Offset;
- case Synthetic: {
- auto *IS = cast<InputSection>(this);
- // For synthetic sections we treat offset -1 as the end of the section.
- return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
- }
+ case Synthetic:
+ return cast<InputSection>(this)->getOffset(Offset);
case EHFrame:
// 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
@@ -182,16 +156,21 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const {
case Merge:
const MergeInputSection *MS = cast<MergeInputSection>(this);
if (InputSection *IS = MS->getParent())
- return IS->OutSecOff + MS->getOffset(Offset);
- return MS->getOffset(Offset);
+ return IS->getOffset(MS->getParentOffset(Offset));
+ return MS->getParentOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
+uint64_t SectionBase::getVA(uint64_t Offset) const {
+ const OutputSection *Out = getOutputSection();
+ return (Out ? Out->Addr : 0) + getOffset(Offset);
+}
+
OutputSection *SectionBase::getOutputSection() {
InputSection *Sec;
if (auto *IS = dyn_cast<InputSection>(this))
- return IS->getParent();
+ Sec = IS;
else if (auto *MS = dyn_cast<MergeInputSection>(this))
Sec = MS->getParent();
else if (auto *EH = dyn_cast<EhInputSection>(this))
@@ -201,34 +180,50 @@ OutputSection *SectionBase::getOutputSection() {
return Sec ? Sec->getParent() : nullptr;
}
-// Uncompress section contents if required. Note that this function
+// Decompress section contents if required. Note that this function
// is called from parallelForEach, so it must be thread-safe.
-void InputSectionBase::maybeUncompress() {
- if (UncompressBuf || !Decompressor::isCompressedELFSection(Flags, Name))
+void InputSectionBase::maybeDecompress() {
+ if (DecompressBuf)
+ return;
+ if (!(Flags & SHF_COMPRESSED) && !Name.startswith(".zdebug"))
return;
+ // Decompress a section.
Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
Config->IsLE, Config->Is64));
size_t Size = Dec.getDecompressedSize();
- UncompressBuf.reset(new char[Size]());
- if (Error E = Dec.decompress({UncompressBuf.get(), Size}))
+ DecompressBuf.reset(new char[Size + Name.size()]());
+ if (Error E = Dec.decompress({DecompressBuf.get(), Size}))
fatal(toString(this) +
": decompress failed: " + llvm::toString(std::move(E)));
- Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size);
+ Data = makeArrayRef((uint8_t *)DecompressBuf.get(), Size);
Flags &= ~(uint64_t)SHF_COMPRESSED;
+
+ // A section name may have been altered if compressed. If that's
+ // the case, restore the original name. (i.e. ".zdebug_" -> ".debug_")
+ if (Name.startswith(".zdebug")) {
+ DecompressBuf[Size] = '.';
+ memcpy(&DecompressBuf[Size + 1], Name.data() + 2, Name.size() - 2);
+ Name = StringRef(&DecompressBuf[Size], Name.size() - 1);
+ }
}
InputSection *InputSectionBase::getLinkOrderDep() const {
- if ((Flags & SHF_LINK_ORDER) && Link != 0) {
- InputSectionBase *L = File->getSections()[Link];
- if (auto *IS = dyn_cast<InputSection>(L))
- return IS;
- error("a section with SHF_LINK_ORDER should not refer a non-regular "
- "section: " +
- toString(L));
- }
+ assert(Link);
+ assert(Flags & SHF_LINK_ORDER);
+ return cast<InputSection>(File->getSections()[Link]);
+}
+
+// Find a function symbol that encloses a given location.
+template <class ELFT>
+Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
+ for (Symbol *B : File->getSymbols())
+ if (Defined *D = dyn_cast<Defined>(B))
+ if (D->Section == this && D->Type == STT_FUNC &&
+ D->Value <= Offset && Offset < D->Value + D->Size)
+ return D;
return nullptr;
}
@@ -241,9 +236,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
.str();
// First check if we can get desired values from debugging information.
- std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset);
- if (!LineInfo.empty())
- return LineInfo;
+ if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset))
+ return Info->FileName + ":" + std::to_string(Info->Line);
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
@@ -251,12 +245,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
if (SrcFile.empty())
SrcFile = toString(File);
- // Find a function symbol that encloses a given location.
- for (Symbol *B : File->getSymbols())
- if (auto *D = dyn_cast<Defined>(B))
- if (D->Section == this && D->Type == STT_FUNC)
- if (D->Value <= Offset && Offset < D->Value + D->Size)
- return SrcFile + ":(function " + toString(*D) + ")";
+ if (Defined *D = getEnclosingFunction<ELFT>(Offset))
+ return SrcFile + ":(function " + toString(*D) + ")";
// If there's no symbol, print out the offset in the section.
return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
@@ -292,7 +282,7 @@ std::string InputSectionBase::getObjMsg(uint64_t Off) {
std::string Archive;
if (!File->ArchiveName.empty())
- Archive = (" in archive " + File->ArchiveName).str();
+ Archive = " in archive " + File->ArchiveName;
// Find a symbol that encloses a given location.
for (Symbol *B : File->getSymbols())
@@ -345,8 +335,9 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
*To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
-InputSectionBase *InputSection::getRelocatedSection() {
- assert(Type == SHT_RELA || Type == SHT_REL);
+InputSectionBase *InputSection::getRelocatedSection() const {
+ if (!File || (Type != SHT_RELA && Type != SHT_REL))
+ return nullptr;
ArrayRef<InputSectionBase *> Sections = File->getSections();
return Sections[Info];
}
@@ -365,12 +356,12 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
Buf += sizeof(RelTy);
- if (Config->IsRela)
+ if (RelTy::IsRela)
P->r_addend = getAddend<ELFT>(Rel);
// Output section VA is zero for -r, so r_offset is an offset within the
// section, but for --emit-relocs it is an virtual address.
- P->r_offset = Sec->getOutputSection()->Addr + Sec->getOffset(Rel.r_offset);
+ P->r_offset = Sec->getVA(Rel.r_offset);
P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type,
Config->IsMips64EL);
@@ -395,17 +386,32 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
continue;
}
- if (Config->IsRela) {
- P->r_addend =
- Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr;
- } else if (Config->Relocatable) {
- const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
- Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset,
- Target->getImplicitAddend(BufLoc, Type),
- &Sym});
+ int64_t Addend = getAddend<ELFT>(Rel);
+ const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
+ if (!RelTy::IsRela)
+ Addend = Target->getImplicitAddend(BufLoc, Type);
+
+ if (Config->EMachine == EM_MIPS && Config->Relocatable &&
+ Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
+ // Some MIPS relocations depend on "gp" value. By default,
+ // this value has 0x7ff0 offset from a .got section. But
+ // relocatable files produced by a complier or a linker
+ // might redefine this default value and we must use it
+ // for a calculation of the relocation result. When we
+ // generate EXE or DSO it's trivial. Generating a relocatable
+ // output is more difficult case because the linker does
+ // not calculate relocations in this mode and loses
+ // individual "gp" values used by each input object file.
+ // As a workaround we add the "gp" value to the relocation
+ // addend and save it back to the file.
+ Addend += Sec->getFile<ELFT>()->MipsGp0;
}
- }
+ if (RelTy::IsRela)
+ P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
+ else if (Config->Relocatable)
+ Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
+ }
}
}
@@ -481,14 +487,17 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
return OS->PtLoad->FirstSec->Addr;
}
-static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
- const Symbol &Sym, RelExpr Expr) {
+static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
+ uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
case R_INVALID:
return 0;
case R_ABS:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Sym.getVA(A);
+ case R_ADDEND:
+ return A;
case R_ARM_SBREL:
return Sym.getVA(A) - getARMStaticBase(Sym);
case R_GOT:
@@ -505,7 +514,9 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
return Sym.getGotOffset() + A - InX::Got->getSize();
+ case R_TLSLD_GOT_OFF:
case R_GOT_OFF:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;
case R_GOT_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
@@ -516,11 +527,12 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_HINT:
case R_NONE:
case R_TLSDESC_CALL:
+ case R_TLSLD_HINT:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
- return Sym.getVA(A) - InX::MipsGot->getGp();
+ return Sym.getVA(A) - InX::MipsGot->getGp(File);
case R_MIPS_GOT_GP:
- return InX::MipsGot->getGp() + A;
+ return InX::MipsGot->getGp(File) + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
@@ -529,7 +541,7 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// microMIPS variants of these relocations use slightly different
// expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
// to correctly handle less-sugnificant bit of the microMIPS symbol.
- uint64_t V = InX::MipsGot->getGp() + A - P;
+ uint64_t V = InX::MipsGot->getGp(File) + A - P;
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
@@ -540,21 +552,23 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// 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 InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getPageEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(File);
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// 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 InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getSymEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(File);
case R_MIPS_TLSGD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getGlobalDynOffset(File, Sym) -
+ InX::MipsGot->getGp(File);
case R_MIPS_TLSLD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
+ InX::MipsGot->getGp(File);
case R_PAGE_PC:
case R_PLT_PAGE_PC: {
uint64_t Dest;
@@ -583,25 +597,27 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_PLT:
return Sym.getPltVA() + A;
case R_PLT_PC:
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL_PLT:
return Sym.getPltVA() + A - P;
- case R_PPC_OPD: {
+ case R_PPC_CALL: {
uint64_t SymVA = Sym.getVA(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::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::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out::Opd->Size;
- bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
- if (InOpd)
- SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
- }
- return SymVA - P;
+
+ // PPC64 V2 ABI describes two entry points to a function. The global entry
+ // point sets up the TOC base pointer. When calling a local function, the
+ // call should branch to the local entry point rather than the global entry
+ // point. Section 3.4.1 describes using the 3 most significant bits of the
+ // st_other field to find out how many instructions there are between the
+ // local and global entry point.
+ uint8_t StOther = (Sym.StOther >> 5) & 7;
+ if (StOther == 0 || StOther == 1)
+ return SymVA - P;
+
+ return SymVA - P + (1LL << StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
@@ -618,25 +634,44 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
- if (Target->TcbSize)
+
+ // For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the
+ // TCB is on unspecified size and content. Targets that implement variant 1
+ // should set TcbSize.
+ if (Target->TcbSize) {
+ // PPC64 V2 ABI has the thread pointer offset into the middle of the TLS
+ // storage area by TlsTpOffset for efficient addressing TCB and up to
+ // 4KB – 8 B of other thread library information (placed before the TCB).
+ // Subtracting this offset will get the address of the first TLS block.
+ if (Target->TlsTpOffset)
+ return Sym.getVA(A) - Target->TlsTpOffset;
+
+ // If thread pointer is not offset into the middle, the first thing in the
+ // TLS storage area is the TCB. Add the TcbSize to get the address of the
+ // first TLS block.
return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+ }
return Sym.getVA(A) - Out::TlsPhdr->p_memsz;
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
case R_SIZE:
- return A; // Sym.getSize was already folded into the addend.
+ return Sym.getSize() + A;
case R_TLSDESC:
return InX::Got->getGlobalDynAddr(Sym) + A;
case R_TLSDESC_PAGE:
return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
- case R_TLSGD:
+ case R_TLSGD_GOT:
+ return InX::Got->getGlobalDynOffset(Sym) + A;
+ case R_TLSGD_GOT_FROM_END:
return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize();
case R_TLSGD_PC:
return InX::Got->getGlobalDynAddr(Sym) + A - P;
- case R_TLSLD:
+ case R_TLSLD_GOT_FROM_END:
return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+ case R_TLSLD_GOT:
+ return InX::Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
return InX::Got->getTlsIndexVA() + A - P;
}
@@ -656,6 +691,14 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
for (const RelTy &Rel : Rels) {
RelType Type = Rel.getType(Config->IsMips64EL);
+
+ // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
+ // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
+ // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
+ // need to keep this bug-compatible code for a while.
+ if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
+ continue;
+
uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
int64_t Addend = getAddend<ELFT>(Rel);
@@ -666,17 +709,27 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
if (Expr == R_NONE)
continue;
+
if (Expr != R_ABS) {
- // GCC 8.0 or earlier have a bug that it emits R_386_GOTPC relocations
- // against _GLOBAL_OFFSET_TABLE for .debug_info. The bug seems to have
- // been fixed in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630,
- // but we need to keep this bug-compatible code for a while.
- if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
- continue;
+ std::string Msg = getLocation<ELFT>(Offset) +
+ ": has non-ABS relocation " + toString(Type) +
+ " against symbol '" + toString(Sym) + "'";
+ if (Expr != R_PC) {
+ error(Msg);
+ return;
+ }
- error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " +
- toString(Type) + " against symbol '" + toString(Sym) + "'");
- return;
+ // If the control reaches here, we found a PC-relative relocation in a
+ // non-ALLOC section. Since non-ALLOC section is not loaded into memory
+ // at runtime, the notion of PC-relative doesn't make sense here. So,
+ // this is a usage error. However, GNU linkers historically accept such
+ // relocations without any errors and relocate them as if they were at
+ // address 0. For bug-compatibilty, we accept them with warnings. We
+ // know Steel Bank Common Lisp as of 2018 have this bug.
+ warn(Msg);
+ Target->relocateOne(BufLoc, Type,
+ SignExtend64<Bits>(Sym.getVA(Addend - Offset)));
+ continue;
}
if (Sym.isTls() && !Out::TlsPhdr)
@@ -686,15 +739,37 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
}
}
+// This is used when '-r' is given.
+// For REL targets, InputSection::copyRelocations() may store artificial
+// relocations aimed to update addends. They are handled in relocateAlloc()
+// for allocatable sections, and this function does the same for
+// non-allocatable sections, such as sections with debug information.
+static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) {
+ const unsigned Bits = Config->Is64 ? 64 : 32;
+
+ for (const Relocation &Rel : Sec->Relocations) {
+ // InputSection::copyRelocations() adds only R_ABS relocations.
+ assert(Rel.Expr == R_ABS);
+ uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff;
+ uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits);
+ Target->relocateOne(BufLoc, Rel.Type, TargetVA);
+ }
+}
+
template <class ELFT>
void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+ if (Flags & SHF_EXECINSTR)
+ adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd);
+
if (Flags & SHF_ALLOC) {
relocateAlloc(Buf, BufEnd);
return;
}
auto *Sec = cast<InputSection>(this);
- if (Sec->AreRelocsRela)
+ if (Config->Relocatable)
+ relocateNonAllocForRelocatable(Sec, Buf);
+ else if (Sec->AreRelocsRela)
Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>());
else
Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>());
@@ -705,14 +780,17 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
const unsigned Bits = Config->Wordsize * 8;
for (const Relocation &Rel : Relocations) {
- uint64_t Offset = getOffset(Rel.Offset);
+ uint64_t Offset = Rel.Offset;
+ if (auto *Sec = dyn_cast<InputSection>(this))
+ Offset += Sec->OutSecOff;
uint8_t *BufLoc = Buf + Offset;
RelType Type = Rel.Type;
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64(
- getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
+ getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
+ Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
@@ -723,6 +801,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
@@ -731,15 +810,28 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
break;
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL:
+ // If this is a call to __tls_get_addr, it may be part of a TLS
+ // sequence that has been relaxed and turned into a nop. In this
+ // case, we don't want to handle it as a call.
+ if (read32(BufLoc) == 0x60000000) // nop
+ break;
+
// Patch a nop (0x60000000) to a ld.
- if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
- write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- LLVM_FALLTHROUGH;
+ if (Rel.Sym->NeedsTocRestore) {
+ if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
+ error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
+ break;
+ }
+ write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
+ }
+ Target->relocateOne(BufLoc, Type, TargetVA);
+ break;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
@@ -747,6 +839,103 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
}
}
+// For each function-defining prologue, find any calls to __morestack,
+// and replace them with calls to __morestack_non_split.
+static void switchMorestackCallsToMorestackNonSplit(
+ llvm::DenseSet<Defined *>& Prologues,
+ std::vector<Relocation *>& MorestackCalls) {
+
+ // If the target adjusted a function's prologue, all calls to
+ // __morestack inside that function should be switched to
+ // __morestack_non_split.
+ Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+
+ // Sort both collections to compare addresses efficiently.
+ llvm::sort(MorestackCalls.begin(), MorestackCalls.end(),
+ [](const Relocation *L, const Relocation *R) {
+ return L->Offset < R->Offset;
+ });
+ std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
+ llvm::sort(
+ Functions.begin(), Functions.end(),
+ [](const Defined *L, const Defined *R) { return L->Value < R->Value; });
+
+ auto It = MorestackCalls.begin();
+ for (Defined *F : Functions) {
+ // Find the first call to __morestack within the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value)
+ ++It;
+ // Adjust all calls inside the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) {
+ (*It)->Sym = MoreStackNonSplit;
+ ++It;
+ }
+ }
+}
+
+static bool
+enclosingPrologueAdjusted(uint64_t Offset,
+ const llvm::DenseSet<Defined *> &Prologues) {
+ for (Defined *F : Prologues)
+ if (F->Value <= Offset && Offset < F->Value + F->Size)
+ return true;
+ return false;
+}
+
+// If a function compiled for split stack calls a function not
+// compiled for split stack, then the caller needs its prologue
+// adjusted to ensure that the called function will have enough stack
+// available. Find those functions, and adjust their prologues.
+template <class ELFT>
+void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
+ uint8_t *End) {
+ if (!getFile<ELFT>()->SplitStack)
+ return;
+ llvm::DenseSet<Defined *> AdjustedPrologues;
+ std::vector<Relocation *> MorestackCalls;
+
+ for (Relocation &Rel : Relocations) {
+ // Local symbols can't possibly be cross-calls, and should have been
+ // resolved long before this line.
+ if (Rel.Sym->isLocal())
+ continue;
+
+ Defined *D = dyn_cast<Defined>(Rel.Sym);
+ // A reference to an undefined symbol was an error, and should not
+ // have gotten to this point.
+ if (!D)
+ continue;
+
+ // Ignore calls into the split-stack api.
+ if (D->getName().startswith("__morestack")) {
+ if (D->getName().equals("__morestack"))
+ MorestackCalls.push_back(&Rel);
+ continue;
+ }
+
+ // A relocation to non-function isn't relevant. Sometimes
+ // __morestack is not marked as a function, so this check comes
+ // after the name check.
+ if (D->Type != STT_FUNC)
+ continue;
+
+ if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues))
+ continue;
+
+ if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
+ if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) {
+ AdjustedPrologues.insert(F);
+ continue;
+ }
+ }
+ if (!getFile<ELFT>()->SomeNoSplitStack)
+ error("function call at " + getErrorLocation(Buf + Rel.Offset) +
+ "crosses a split-stack boundary, but unable " +
+ "to adjust the enclosing function's prologue");
+ }
+ switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls);
+}
+
template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
if (Type == SHT_NOBITS)
return;
@@ -818,10 +1007,6 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
// .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::split() {
- // Early exit if already split.
- if (!Pieces.empty())
- return;
-
if (AreRelocsRela)
split<ELFT>(relas<ELFT>());
else
@@ -916,15 +1101,9 @@ void MergeInputSection::splitIntoPieces() {
else
splitNonStrings(Data, Entsize);
- if (Config->GcSections && (Flags & SHF_ALLOC))
- for (uint64_t Off : LiveOffsets)
- getSectionPiece(Off)->Live = true;
-}
-
-// Do binary search to get a section piece at a given input offset.
-SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
- auto *This = static_cast<const MergeInputSection *>(this);
- return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+ OffsetMap.reserve(Pieces.size());
+ for (size_t I = 0, E = Pieces.size(); I != E; ++I)
+ OffsetMap[Pieces[I].InputOff] = I;
}
template <class It, class T, class Compare>
@@ -940,32 +1119,34 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
return Comp(Value, *First) ? First : First + 1;
}
-const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
- if (Data.size() <= Offset)
- fatal(toString(this) + ": entry is past the end of the section");
+// Do binary search to get a section piece at a given input offset.
+static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) {
+ if (Sec->Data.size() <= Offset)
+ fatal(toString(Sec) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
- Pieces.begin(), Pieces.end(), Offset,
+ Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
[](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ // Find a piece starting at a given offset.
+ auto It = OffsetMap.find(Offset);
+ if (It != OffsetMap.end())
+ return &Pieces[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.
+ return findSectionPiece(this, Offset);
+}
+
// 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.
-uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
- if (!Live)
- return 0;
-
- // Initialize OffsetMap lazily.
- llvm::call_once(InitOffsetMap, [&] {
- OffsetMap.reserve(Pieces.size());
- for (size_t I = 0; I < Pieces.size(); ++I)
- OffsetMap[Pieces[I].InputOff] = I;
- });
-
+uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
// Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
@@ -973,10 +1154,8 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
// 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 = *getSectionPiece(Offset);
- if (!Piece.Live)
- return 0;
-
+ const SectionPiece &Piece =
+ *findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 8c114ae71948..4db01e035e32 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -18,8 +18,6 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Threading.h"
-#include <mutex>
namespace lld {
namespace elf {
@@ -63,6 +61,9 @@ public:
unsigned Bss : 1;
+ // Set for sections that should not be folded by ICF.
+ unsigned KeepUnique : 1;
+
// These corresponds to the fields in Elf_Shdr.
uint32_t Alignment;
uint64_t Flags;
@@ -80,13 +81,15 @@ public:
// section.
uint64_t getOffset(uint64_t Offset) const;
+ uint64_t getVA(uint64_t Offset = 0) const;
+
protected:
SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
uint64_t Entsize, uint64_t Alignment, uint32_t Type,
uint32_t Info, uint32_t Link)
: Name(Name), Repl(this), SectionKind(SectionKind), Live(false),
- Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize),
- Type(Type), Link(Link), Info(Info) {}
+ Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags),
+ Entsize(Entsize), Type(Type), Link(Link), Info(Info) {}
};
// This corresponds to a section of an input file.
@@ -103,7 +106,7 @@ public:
static bool classof(const SectionBase *S) { return S->kind() != Output; }
- // The file which contains this section. It's dynamic type is always
+ // The file which contains this section. Its dynamic type is always
// ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as
// its static type.
InputFile *File;
@@ -161,10 +164,15 @@ public:
InputSection *getLinkOrderDep() const;
+ // Get the function symbol that encloses this offset from within the
+ // section.
+ template <class ELFT>
+ Defined *getEnclosingFunction(uint64_t Offset);
+
// Compilers emit zlib-compressed debug sections if the -gz option
// is given. This function checks if this section is compressed, and
// if so, decompress in memory.
- void maybeUncompress();
+ void maybeDecompress();
// Returns a source location string. Used to construct an error message.
template <class ELFT> std::string getLocation(uint64_t Offset);
@@ -182,6 +190,15 @@ public:
// This vector contains such "cooked" relocations.
std::vector<Relocation> Relocations;
+ // A function compiled with -fsplit-stack calling a function
+ // compiled without -fsplit-stack needs its prologue adjusted. Find
+ // such functions and adjust their prologues. This is very similar
+ // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more
+ // information.
+ template <typename ELFT>
+ void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End);
+
+
template <typename T> llvm::ArrayRef<T> getDataAs() const {
size_t S = Data.size();
assert(S % sizeof(T) == 0);
@@ -189,9 +206,9 @@ public:
}
private:
- // A pointer that owns uncompressed data if a section is compressed by zlib.
+ // A pointer that owns decompressed data if a section is compressed by zlib.
// Since the feature is not used often, this is usually a nullptr.
- std::unique_ptr<char[]> UncompressBuf;
+ std::unique_ptr<char[]> DecompressBuf;
};
// SectionPiece represents a piece of splittable section contents.
@@ -200,7 +217,7 @@ private:
// be found by looking at the next one).
struct SectionPiece {
SectionPiece(size_t Off, uint32_t Hash, bool Live)
- : InputOff(Off), Hash(Hash), OutputOff(-1),
+ : InputOff(Off), Hash(Hash), OutputOff(0),
Live(Live || !Config->GcSections) {}
uint32_t InputOff;
@@ -223,19 +240,14 @@ public:
static bool classof(const SectionBase *S) { return S->kind() == Merge; }
void splitIntoPieces();
- // Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uint64_t Offset) {
- if (this->Flags & llvm::ELF::SHF_ALLOC)
- LiveOffsets.insert(Offset);
- }
-
- // Translate an offset in the input section to an offset
- // in the output section.
- uint64_t getOffset(uint64_t Offset) const;
+ // Translate an offset in the input section to an offset in the parent
+ // MergeSyntheticSection.
+ uint64_t getParentOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<SectionPiece> Pieces;
+ llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
// Returns I'th piece's data. This function is very hot when
// string merging is enabled, so we want to inline.
@@ -249,18 +261,15 @@ public:
// Returns the SectionPiece at a given input section offset.
SectionPiece *getSectionPiece(uint64_t Offset);
- const SectionPiece *getSectionPiece(uint64_t Offset) const;
+ const SectionPiece *getSectionPiece(uint64_t Offset) const {
+ return const_cast<MergeInputSection *>(this)->getSectionPiece(Offset);
+ }
SyntheticSection *getParent() const;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
-
- mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
- mutable llvm::once_flag InitOffsetMap;
-
- llvm::DenseSet<uint64_t> LiveOffsets;
};
struct EhSectionPiece {
@@ -310,6 +319,8 @@ public:
// beginning of the output section.
template <class ELFT> void writeTo(uint8_t *Buf);
+ uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; }
+
OutputSection *getParent() const;
// This variable has two usages. Initially, it represents an index in the
@@ -320,7 +331,7 @@ public:
static bool classof(const SectionBase *S);
- InputSectionBase *getRelocatedSection();
+ InputSectionBase *getRelocatedSection() const;
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
@@ -342,10 +353,6 @@ private:
// The list of all input sections.
extern std::vector<InputSectionBase *> InputSections;
-
-// Builds section order for handling --symbol-ordering-file.
-llvm::DenseMap<SectionBase *, int> buildSectionOrder();
-
} // namespace elf
std::string toString(const elf::InputSectionBase *);
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index bfd85288d186..ef58932e86cc 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -20,6 +20,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
@@ -29,7 +31,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <memory>
@@ -44,70 +45,92 @@ 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) {
+// Creates an empty file to store a list of object files for final
+// linking of distributed ThinLTO.
+static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) {
std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
-}
-
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
+ auto Ret =
+ llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None);
+ if (EC) {
+ error("cannot open " + File + ": " + EC.message());
+ return nullptr;
+ }
+ return Ret;
}
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+static std::string getThinLTOOutputFile(StringRef ModulePath) {
+ return lto::getThinLTOOutputFile(ModulePath,
+ Config->ThinLTOPrefixReplace.first,
+ Config->ThinLTOPrefixReplace.second);
}
-static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
+static lto::Config createConfig() {
+ lto::Config C;
// LLD supports the new relocations.
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
- Conf.Options.RelaxELFRelocations = true;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+ C.Options.RelaxELFRelocations = true;
// Always emit a section per function/datum with LTO.
- Conf.Options.FunctionSections = true;
- Conf.Options.DataSections = true;
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
if (Config->Relocatable)
- Conf.RelocModel = None;
+ C.RelocModel = None;
else if (Config->Pic)
- Conf.RelocModel = Reloc::PIC_;
+ C.RelocModel = Reloc::PIC_;
else
- Conf.RelocModel = Reloc::Static;
- Conf.CodeModel = GetCodeModelFromCMModel();
- Conf.DisableVerify = Config->DisableVerify;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOO;
+ C.RelocModel = Reloc::Static;
+
+ C.CodeModel = GetCodeModelFromCMModel();
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
// Set up a custom pipeline if we've been asked to.
- Conf.OptPipeline = Config->LTONewPmPasses;
- Conf.AAPipeline = Config->LTOAAPipeline;
+ C.OptPipeline = Config->LTONewPmPasses;
+ C.AAPipeline = Config->LTOAAPipeline;
// Set up optimization remarks if we've been asked to.
- Conf.RemarksFilename = Config->OptRemarksFilename;
- Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+ C.RemarksFilename = Config->OptRemarksFilename;
+ C.RemarksWithHotness = Config->OptRemarksWithHotness;
+
+ C.SampleProfile = Config->LTOSampleProfile;
+ C.UseNewPM = Config->LTONewPassManager;
+ C.DebugPassManager = Config->LTODebugPassManager;
+ C.DwoDir = Config->DwoDir;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+ return C;
+}
+BitcodeCompiler::BitcodeCompiler() {
+ // Initialize LTOObj.
lto::ThinBackend Backend;
- if (Config->ThinLTOJobs != -1u)
+
+ if (Config->ThinLTOIndexOnly) {
+ StringRef Path = Config->ThinLTOIndexOnlyArg;
+ if (!Path.empty())
+ IndexFile = openFile(Path);
+
+ auto OnIndexWrite = [&](const std::string &Identifier) {
+ ObjectToIndexFileState[Identifier] = true;
+ };
+
+ Backend = lto::createWriteIndexesThinBackend(
+ Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
+ Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
+ } else if (Config->ThinLTOJobs != -1U) {
Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
- Config->LTOPartitions);
-}
+ }
-BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {
+ LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend,
+ Config->LTOPartitions);
+
+ // Initialize UsedStartStop.
for (Symbol *Sym : Symtab->getSymbols()) {
StringRef Name = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
@@ -125,20 +148,20 @@ static void undefine(Symbol *S) {
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
- unsigned SymNum = 0;
- std::vector<Symbol *> Syms = F.getSymbols();
- std::vector<lto::SymbolResolution> Resols(Syms.size());
+ bool IsExec = !Config->Shared && !Config->Relocatable;
- DenseSet<StringRef> ScriptSymbols;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
- ScriptSymbols.insert(Cmd->Name);
+ if (Config->ThinLTOIndexOnly)
+ ObjectToIndexFileState.insert({Obj.getName(), false});
+
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
// Provide a resolution to the LTO API for each symbol.
- for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- Symbol *Sym = Syms[SymNum];
- lto::SymbolResolution &R = Resols[SymNum];
- ++SymNum;
+ for (size_t I = 0, E = Syms.size(); I != E; ++I) {
+ Symbol *Sym = Syms[I];
+ const lto::InputFile::Symbol &ObjSym = ObjSyms[I];
+ lto::SymbolResolution &R = Resols[I];
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
@@ -156,25 +179,46 @@ void BitcodeCompiler::add(BitcodeFile &F) {
R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
(R.Prevailing && Sym->includeInDynsym()) ||
UsedStartStop.count(ObjSym.getSectionName());
+ const auto *DR = dyn_cast<Defined>(Sym);
+ R.FinalDefinitionInLinkageUnit =
+ (IsExec || Sym->Visibility != STV_DEFAULT) && DR &&
+ // Skip absolute symbols from ELF objects, otherwise PC-rel relocations
+ // will be generated by for them, triggering linker errors.
+ // Symbol section is always null for bitcode symbols, hence the check
+ // for isElf(). Skip linker script defined symbols as well: they have
+ // no File defined.
+ !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf()));
+
if (R.Prevailing)
undefine(Sym);
- // We tell LTO to not apply interprocedural optimization for following
- // symbols because otherwise LTO would inline them while their values are
- // still not final:
- // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols.
- // 2) Symbols redefined in linker script.
- R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName());
+ // We tell LTO to not apply interprocedural optimization for wrapped
+ // (with --wrap) symbols because otherwise LTO would inline them while
+ // their values are still not final.
+ R.LinkerRedefined = !Sym->CanInline;
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
+static void createEmptyIndex(StringRef ModulePath) {
+ std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath));
+ std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc");
+ if (!OS)
+ return;
+
+ ModuleSummaryIndex M(/*HaveGVs*/ false);
+ M.setSkipModuleByDistributedBackend();
+ WriteIndexToFile(M, *OS);
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+}
+
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting ObjectFile(s).
std::vector<InputFile *> BitcodeCompiler::compile() {
- std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The --thinlto-cache-dir option specifies the path to a directory in which
@@ -184,35 +228,67 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
if (!Config->ThinLTOCacheDir.empty())
Cache = check(
lto::localCache(Config->ThinLTOCacheDir,
- [&](size_t Task, std::unique_ptr<MemoryBuffer> MB,
- StringRef Path) { Files[Task] = std::move(MB); }));
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
+ // Emit empty index files for non-indexed files
+ if (Config->ThinLTOIndexOnly) {
+ for (auto &Identifier : ObjectToIndexFileState)
+ if (!Identifier.getValue()) {
+ std::string Path = getThinLTOOutputFile(Identifier.getKey());
+ openFile(Path + ".thinlto.bc");
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+ }
+ }
+
+ // If LazyObjFile has not been added to link, emit empty index files.
+ // This is needed because this is what GNU gold plugin does and we have a
+ // distributed build system that depends on that behavior.
+ if (Config->ThinLTOIndexOnly) {
+ for (LazyObjFile *F : LazyObjFiles)
+ if (!F->AddedToLink && isBitcode(F->MB))
+ createEmptyIndex(F->getName());
+
+ if (!Config->LTOObjPath.empty())
+ saveBuffer(Buf[0], Config->LTOObjPath);
+
+ // ThinLTO with index only option is required to generate only the index
+ // files. After that, we exit from linker and ThinLTO backend runs in a
+ // distributed environment.
+ if (IndexFile)
+ IndexFile->close();
+ return {};
+ }
+
if (!Config->ThinLTOCacheDir.empty())
pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+ std::vector<InputFile *> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
}
- InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
+ InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp"));
Ret.push_back(Obj);
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(createObjectFile(*File));
-
return Ret;
}
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 223af507a97d..8803078eb1df 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -24,6 +24,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>
@@ -38,6 +39,7 @@ namespace elf {
class BitcodeFile;
class InputFile;
+class LazyObjFile;
class BitcodeCompiler {
public:
@@ -49,9 +51,11 @@ public:
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
llvm::DenseSet<StringRef> UsedStartStop;
+ std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
+ llvm::StringMap<bool> ObjectToIndexFileState;
};
} // namespace elf
} // namespace lld
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 8f50a977fd75..abdd899da487 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -15,13 +15,13 @@
#include "Config.h"
#include "InputSection.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -74,7 +74,7 @@ uint64_t ExprValue::getSectionOffset() const {
// If the alignment is trivial, we don't have to compute the full
// value to know the offset. This allows this function to succeed in
// cases where the output section is not yet known.
- if (Alignment == 1)
+ if (Alignment == 1 && (!Sec || !Sec->getOutputSection()))
return Val;
return getValue() - getSecAddr();
}
@@ -102,28 +102,67 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) {
return CmdRef;
}
+// Expands the memory region by the specified size.
+static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size,
+ StringRef RegionName, StringRef SecName) {
+ MemRegion->CurPos += Size;
+ uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin;
+ if (NewSize > MemRegion->Length)
+ error("section '" + SecName + "' will not fit in region '" + RegionName +
+ "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes");
+}
+
+void LinkerScript::expandMemoryRegions(uint64_t Size) {
+ if (Ctx->MemRegion)
+ expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
+ Ctx->OutSec->Name);
+ if (Ctx->LMARegion)
+ expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
+ Ctx->OutSec->Name);
+}
+
+void LinkerScript::expandOutputSection(uint64_t Size) {
+ Ctx->OutSec->Size += Size;
+ expandMemoryRegions(Size);
+}
+
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
uint64_t Val = E().getValue();
if (Val < Dot && InSec)
error(Loc + ": unable to move location counter backward for: " +
Ctx->OutSec->Name);
- Dot = Val;
// Update to location counter means update to section size.
if (InSec)
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
+ expandOutputSection(Val - Dot);
+ else
+ expandMemoryRegions(Val - Dot);
+
+ Dot = Val;
}
-// This function is called from processSectionCommands,
-// while we are fixing the output section layout.
-void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+// Used for handling linker symbol assignments, for both finalizing
+// their values and doing early declarations. Returns true if symbol
+// should be defined from linker script.
+static bool shouldDefineSym(SymbolAssignment *Cmd) {
if (Cmd->Name == ".")
- return;
+ return false;
- // If a symbol was in PROVIDE(), we need to define it only when
- // it is a referenced undefined symbol.
+ if (!Cmd->Provide)
+ return true;
+
+ // If a symbol was in PROVIDE(), we need to define it only
+ // when it is a referenced undefined symbol.
Symbol *B = Symtab->find(Cmd->Name);
- if (Cmd->Provide && (!B || B->isDefined()))
+ if (B && !B->isDefined())
+ return true;
+ return false;
+}
+
+// This function is called from processSectionCommands,
+// while we are fixing the output section layout.
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
return;
// Define a symbol.
@@ -153,6 +192,76 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
Cmd->Sym = cast<Defined>(Sym);
}
+// This function is called from LinkerScript::declareSymbols.
+// It creates a placeholder symbol if needed.
+static void declareSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
+ return;
+
+ // We can't calculate final value right now.
+ Symbol *Sym;
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
+ STT_NOTYPE, 0, 0, nullptr);
+ Cmd->Sym = cast<Defined>(Sym);
+ Cmd->Provide = false;
+}
+
+// This method is used to handle INSERT AFTER statement. Here we rebuild
+// the list of script commands to mix sections inserted into.
+void LinkerScript::processInsertCommands() {
+ std::vector<BaseCommand *> V;
+ auto Insert = [&](std::vector<BaseCommand *> &From) {
+ V.insert(V.end(), From.begin(), From.end());
+ From.clear();
+ };
+
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *OS = dyn_cast<OutputSection>(Base)) {
+ Insert(InsertBeforeCommands[OS->Name]);
+ V.push_back(Base);
+ Insert(InsertAfterCommands[OS->Name]);
+ continue;
+ }
+ V.push_back(Base);
+ }
+
+ for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands})
+ for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds)
+ if (!P.second.empty())
+ error("unable to INSERT AFTER/BEFORE " + P.first +
+ ": section not defined");
+
+ SectionCommands = std::move(V);
+}
+
+// Symbols defined in script should not be inlined by LTO. At the same time
+// we don't know their final values until late stages of link. Here we scan
+// over symbol assignment commands and create placeholder symbols if needed.
+void LinkerScript::declareSymbols() {
+ assert(!Ctx);
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ declareSymbol(Cmd);
+ continue;
+ }
+
+ // If the output section directive has constraints,
+ // we can't say for sure if it is going to be included or not.
+ // Skip such sections for now. Improve the checks if we ever
+ // need symbols from that sections to be declared early.
+ auto *Sec = cast<OutputSection>(Base);
+ if (Sec->Constraint != ConstraintKind::NoConstraint)
+ continue;
+ for (BaseCommand *Base2 : Sec->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2))
+ declareSymbol(Cmd);
+ }
+}
+
// This function is called from assignAddresses, while we are
// fixing the output section addresses. This function is supposed
// to set the final value for a given symbol assignment.
@@ -249,23 +358,11 @@ static void sortSections(MutableArrayRef<InputSection *> Vec,
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
-// 5. If no SORT commands are given and --sort-section is not specified,
-// apply sorting provided by --symbol-ordering-file if any exist.
-static void sortInputSections(
- MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat,
- const DenseMap<SectionBase *, int> &Order) {
+static void sortInputSections(MutableArrayRef<InputSection *> Vec,
+ const SectionPattern &Pat) {
if (Pat.SortOuter == SortSectionPolicy::None)
return;
- if (Pat.SortOuter == SortSectionPolicy::Default &&
- Config->SortSection == SortSectionPolicy::Default) {
- // If -symbol-ordering-file was given, sort accordingly.
- // Usually, Order is empty.
- if (!Order.empty())
- sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); });
- return;
- }
-
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Vec, Config->SortSection);
else
@@ -275,8 +372,7 @@ static void sortInputSections(
// Compute and remember which sections the InputSectionDescription matches.
std::vector<InputSection *>
-LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
- const DenseMap<SectionBase *, int> &Order) {
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
std::vector<InputSection *> Ret;
// Collects all sections that satisfy constraints of Cmd.
@@ -290,8 +386,11 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
// For -emit-relocs we have to ignore entries like
// .rela.dyn : { *(.rela.data) }
// which are common because they are in the default bfd script.
- if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
- continue;
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
+ // want to support scripts that do custom layout for them.
+ if (auto *IS = dyn_cast<InputSection>(Sec))
+ if (IS->getRelocatedSection())
+ continue;
std::string Filename = getFilename(Sec->File);
if (!Cmd->FilePat.match(Filename) ||
@@ -307,7 +406,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
}
sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore),
- Pat, Order);
+ Pat);
}
return Ret;
}
@@ -315,22 +414,31 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
void LinkerScript::discard(ArrayRef<InputSection *> V) {
for (InputSection *S : V) {
if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
- S == InX::DynStrTab)
+ S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
+ S == InX::RelrDyn)
error("discarding " + S->Name + " section is not allowed");
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (S == InX::GnuHashTab)
+ InX::GnuHashTab = nullptr;
+ if (S == InX::HashTab)
+ InX::HashTab = nullptr;
+
S->Assigned = false;
S->Live = false;
discard(S->DependentSections);
}
}
-std::vector<InputSection *> LinkerScript::createInputSectionList(
- OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) {
+std::vector<InputSection *>
+LinkerScript::createInputSectionList(OutputSection &OutCmd) {
std::vector<InputSection *> Ret;
for (BaseCommand *Base : OutCmd.SectionCommands) {
if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) {
- Cmd->Sections = computeInputSections(Cmd, Order);
+ Cmd->Sections = computeInputSections(Cmd);
Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
}
}
@@ -359,7 +467,6 @@ void LinkerScript::processSectionCommands() {
Ctx->OutSec = Aether;
size_t I = 0;
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
// Add input sections to output sections.
for (BaseCommand *Base : SectionCommands) {
// Handle symbol assignments outside of any output section.
@@ -369,12 +476,13 @@ void LinkerScript::processSectionCommands() {
}
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- std::vector<InputSection *> V = createInputSectionList(*Sec, Order);
+ std::vector<InputSection *> V = createInputSectionList(*Sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (Sec->Name == "/DISCARD/") {
discard(V);
+ Sec->SectionCommands.clear();
continue;
}
@@ -414,6 +522,8 @@ void LinkerScript::processSectionCommands() {
Sec->SectionIndex = I++;
if (Sec->Noload)
Sec->Type = SHT_NOBITS;
+ if (Sec->NonAlloc)
+ Sec->Flags &= ~(uint64_t)SHF_ALLOC;
}
}
Ctx = nullptr;
@@ -484,7 +594,7 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
// ignored. We should not have two output .text sections just because one was
// in a group and another was not for example.
//
- // It also seems that that wording was a late addition and didn't get the
+ // It also seems that wording was a late addition and didn't get the
// necessary scrutiny.
//
// Merging sections with different flags is expected by some users. One
@@ -529,11 +639,11 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
void LinkerScript::addOrphanSections() {
unsigned End = SectionCommands.size();
StringMap<OutputSection *> Map;
-
std::vector<OutputSection *> V;
- for (InputSectionBase *S : InputSections) {
+
+ auto Add = [&](InputSectionBase *S) {
if (!S->Live || S->Parent)
- continue;
+ return;
StringRef Name = getOutputSectionName(S);
@@ -545,12 +655,24 @@ void LinkerScript::addOrphanSections() {
if (OutputSection *Sec =
findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) {
Sec->addSection(cast<InputSection>(S));
- continue;
+ return;
}
if (OutputSection *OS = addInputSec(Map, S, Name))
V.push_back(OS);
- assert(S->getOutputSection()->SectionIndex == INT_MAX);
+ assert(S->getOutputSection()->SectionIndex == UINT32_MAX);
+ };
+
+ // For futher --emit-reloc handling code we need target output section
+ // to be created before we create relocation output section, so we want
+ // to create target sections first. We do not want priority handling
+ // for synthetic sections because them are special.
+ for (InputSectionBase *IS : InputSections) {
+ if (auto *Sec = dyn_cast<InputSection>(IS))
+ if (InputSectionBase *Rel = Sec->getRelocatedSection())
+ if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent))
+ Add(RelIS);
+ Add(IS);
}
// If no SECTIONS command was given, we should insert sections commands
@@ -585,36 +707,15 @@ void LinkerScript::output(InputSection *S) {
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
- Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr;
-
- // If there is a memory region associated with this input section, then
- // place the section in that region and update the region index.
- if (Ctx->MemRegion) {
- uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion];
- CurOffset += Pos - Before;
- uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin;
- if (CurSize > Ctx->MemRegion->Length) {
- uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length;
- error("section '" + Ctx->OutSec->Name + "' will not fit in region '" +
- Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
- " bytes");
- }
- }
+ expandOutputSection(Pos - Before);
}
void LinkerScript::switchTo(OutputSection *Sec) {
- if (Ctx->OutSec == Sec)
- return;
-
Ctx->OutSec = Sec;
- Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment);
- // If neither AT nor AT> is specified for an allocatable section, the linker
- // will set the LMA such that the difference between VMA and LMA for the
- // section is the same as the preceding output section in the same region
- // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
- if (Ctx->LMAOffset)
- Ctx->OutSec->LMAOffset = Ctx->LMAOffset();
+ uint64_t Before = advance(0, 1);
+ Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment);
+ expandMemoryRegions(Ctx->OutSec->Addr - Before);
}
// This function searches for a memory region to place the given output
@@ -624,9 +725,8 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
// If a memory region name was specified in the output section command,
// then try to find that region first.
if (!Sec->MemoryRegionName.empty()) {
- auto It = MemoryRegions.find(Sec->MemoryRegionName);
- if (It != MemoryRegions.end())
- return It->second;
+ if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName))
+ return M;
error("memory region '" + Sec->MemoryRegionName + "' not declared");
return nullptr;
}
@@ -659,24 +759,27 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
setDot(Sec->AddrExpr, Sec->Location, false);
Ctx->MemRegion = Sec->MemRegion;
+ Ctx->LMARegion = Sec->LMARegion;
if (Ctx->MemRegion)
- Dot = Ctx->MemRegionOffset[Ctx->MemRegion];
-
- if (Sec->LMAExpr) {
- uint64_t D = Dot;
- Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; };
- }
+ Dot = Ctx->MemRegion->CurPos;
switchTo(Sec);
- // We do not support custom layout for compressed debug sectons.
- // At this point we already know their size and have compressed content.
- if (Ctx->OutSec->Flags & SHF_COMPRESSED)
- return;
+ if (Sec->LMAExpr)
+ Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot;
+
+ if (MemoryRegion *MR = Sec->LMARegion)
+ Ctx->LMAOffset = MR->CurPos - Dot;
+
+ // If neither AT nor AT> is specified for an allocatable section, the linker
+ // will set the LMA such that the difference between VMA and LMA for the
+ // section is the same as the preceding output section in the same region
+ // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+ if (PhdrEntry *L = Ctx->OutSec->PtLoad)
+ L->LMAOffset = Ctx->LMAOffset;
- // The Size previously denoted how many InputSections had been added to this
- // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to
- // compute the actual size value.
+ // We can call this method multiple times during the creation of
+ // thunks and want to start over calculation each time.
Sec->Size = 0;
// We visited SectionsCommands from processSectionCommands to
@@ -685,7 +788,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
for (BaseCommand *Base : Sec->SectionCommands) {
// This handles the assignments to symbol or to the dot.
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, true);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
@@ -693,15 +798,7 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
Cmd->Offset = Dot - Ctx->OutSec->Addr;
Dot += Cmd->Size;
- if (Ctx->MemRegion)
- Ctx->MemRegionOffset[Ctx->MemRegion] += Cmd->Size;
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
- continue;
- }
-
- // Handle ASSERT().
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
+ expandOutputSection(Cmd->Size);
continue;
}
@@ -726,24 +823,28 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
}
}
-void LinkerScript::removeEmptyCommands() {
- // It is common practice to use very generic linker scripts. So for any
- // given run some of the output sections in the script will be empty.
- // We could create corresponding empty output sections, but that would
- // clutter the output.
- // We instead remove trivially empty sections. The bfd linker seems even
- // more aggressive at removing them.
- llvm::erase_if(SectionCommands, [&](BaseCommand *Base) {
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- return !Sec->Live;
+static bool isDiscardable(OutputSection &Sec) {
+ // We do not remove empty sections that are explicitly
+ // assigned to any segment.
+ if (!Sec.Phdrs.empty())
return false;
- });
-}
-static bool isAllSectionDescription(const OutputSection &Cmd) {
- for (BaseCommand *Base : Cmd.SectionCommands)
+ // We do not want to remove sections that reference symbols in address and
+ // other expressions. We add script symbols as undefined, and want to ensure
+ // all of them are defined in the output, hence have to keep them.
+ if (Sec.ExpressionsUseSymbols)
+ return false;
+
+ for (BaseCommand *Base : Sec.SectionCommands) {
+ if (auto Cmd = dyn_cast<SymbolAssignment>(Base))
+ // Don't create empty output sections just for unreferenced PROVIDE
+ // symbols.
+ if (Cmd->Name != "." && !Cmd->Sym)
+ continue;
+
if (!isa<InputSectionDescription>(*Base))
return false;
+ }
return true;
}
@@ -759,7 +860,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// Given that we want to create the section, we have to worry what impact
// it will have on the link. For example, if we just create a section with
// 0 for flags, it would change which PT_LOADs are created.
- // We could remember that that particular section is dummy and ignore it in
+ // We could remember that particular section is dummy and ignore it in
// other parts of the linker, but unfortunately there are quite a few places
// that would need to change:
// * The program header creation.
@@ -770,34 +871,54 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// the previous sections. Only a few flags are needed to keep the impact low.
uint64_t Flags = SHF_ALLOC;
- for (BaseCommand *Cmd : SectionCommands) {
+ for (BaseCommand *&Cmd : SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Cmd);
if (!Sec)
continue;
- if (Sec->Live) {
- Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
- continue;
- }
-
- if (isAllSectionDescription(*Sec))
- continue;
- Sec->Live = true;
- Sec->Flags = Flags;
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Sec->AlignExpr)
+ Sec->Alignment =
+ std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
+
+ // A live output section means that some input section was added to it. It
+ // might have been removed (if it was empty synthetic section), but we at
+ // least know the flags.
+ if (Sec->Live)
+ Flags = Sec->Flags;
+
+ // We do not want to keep any special flags for output section
+ // in case it is empty.
+ bool IsEmpty = getInputSections(Sec).empty();
+ if (IsEmpty)
+ Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+
+ if (IsEmpty && isDiscardable(*Sec)) {
+ Sec->Live = false;
+ Cmd = nullptr;
+ }
}
+
+ // It is common practice to use very generic linker scripts. So for any
+ // given run some of the output sections in the script will be empty.
+ // We could create corresponding empty output sections, but that would
+ // clutter the output.
+ // We instead remove trivially empty sections. The bfd linker seems even
+ // more aggressive at removing them.
+ llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });
}
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
for (BaseCommand *Base : SectionCommands) {
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- if (!Sec->Live)
- continue;
+ if (!Sec->LMARegionName.empty()) {
+ if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName))
+ Sec->LMARegion = M;
+ else
+ error("memory region '" + Sec->LMARegionName + "' not declared");
+ }
Sec->MemRegion = findMemoryRegion(Sec);
- // Handle align (e.g. ".foo : ALIGN(16) { ... }").
- if (Sec->AlignExpr)
- Sec->Alignment =
- std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
}
}
@@ -808,9 +929,9 @@ void LinkerScript::adjustSectionsAfterSorting() {
// PHDRS { seg PT_LOAD; }
// SECTIONS { .aaa : { *(.aaa) } }
std::vector<StringRef> DefPhdrs;
- auto FirstPtLoad =
- std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(),
- [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+ auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.Type == PT_LOAD;
+ });
if (FirstPtLoad != PhdrsCommands.end())
DefPhdrs.push_back(FirstPtLoad->Name);
@@ -839,6 +960,15 @@ static OutputSection *findFirstSection(PhdrEntry *Load) {
return nullptr;
}
+static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) {
+ // If there is no SECTIONS or if the linkerscript is explicit about program
+ // headers, do our best to allocate them.
+ if (!Script->HasSectionsCommand || AllocateHeaders)
+ return 0;
+ // Otherwise only allocate program headers if that would not add a page.
+ return alignDown(Min, Config->MaxPageSize);
+}
+
// Try to find an address for the file and program headers output sections,
// which were unconditionally added to the first PT_LOAD segment earlier.
//
@@ -862,17 +992,22 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
return;
PhdrEntry *FirstPTLoad = *It;
+ bool HasExplicitHeaders =
+ llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.HasPhdrs || Cmd.HasFilehdr;
+ });
uint64_t HeaderSize = getHeaderSize();
- // When linker script with SECTIONS is being used, don't output headers
- // unless there's a space for them.
- uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0;
- if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) {
+ if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
Out::ElfHeader->Addr = Min;
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
return;
}
+ // Error if we were explicitly asked to allocate headers.
+ if (HasExplicitHeaders)
+ error("could not allocate headers");
+
Out::ElfHeader->PtLoad = nullptr;
Out::ProgramHeaders->PtLoad = nullptr;
FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad);
@@ -883,8 +1018,8 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
LinkerScript::AddressState::AddressState() {
for (auto &MRI : Script->MemoryRegions) {
- const MemoryRegion *MR = MRI.second;
- MemRegionOffset[MR] = MR->Origin;
+ MemoryRegion *MR = MRI.second;
+ MR->CurPos = MR->Origin;
}
}
@@ -916,15 +1051,11 @@ void LinkerScript::assignAddresses() {
for (BaseCommand *Base : SectionCommands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, false);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
-
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
- continue;
- }
-
assignOffsets(cast<OutputSection>(Base));
}
Ctx = nullptr;
@@ -988,9 +1119,9 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) {
if (Symbol *Sym = Symtab->find(Name)) {
if (auto *DS = dyn_cast<Defined>(Sym))
return {DS->Section, false, DS->Value, Loc};
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (!ErrorOnMissingSection || SS->CopyRelSec)
- return {SS->CopyRelSec, false, 0, Loc};
+ if (isa<SharedSymbol>(Sym))
+ if (!ErrorOnMissingSection)
+ return {nullptr, false, 0, Loc};
}
error(Loc + ": symbol not found: " + Name);
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 11131dda8e26..3b790dd4669f 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -11,9 +11,9 @@
#define LLD_ELF_LINKER_SCRIPT_H
#include "Config.h"
-#include "Strings.h"
#include "Writer.h"
#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -75,7 +75,6 @@ enum SectionsCommandKind {
AssignmentKind, // . = expr or <sym> = expr
OutputSectionKind,
InputSectionKind,
- AssertKind, // ASSERT(expr)
ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
};
@@ -106,6 +105,16 @@ struct SymbolAssignment : BaseCommand {
// Holds file name and line number for error reporting.
std::string Location;
+
+ // A string representation of this command. We use this for -Map.
+ std::string CommandString;
+
+ // Address of this assignment command.
+ unsigned Addr;
+
+ // Size of this assignment command. This is usually 0, but if
+ // you move '.' this may be greater than 0.
+ unsigned Size;
};
// Linker scripts allow additional constraints to be put on ouput sections.
@@ -118,11 +127,17 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
// target memory. Instances of the struct are created by parsing the
// MEMORY command.
struct MemoryRegion {
+ MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags,
+ uint32_t NegFlags)
+ : Name(Name), Origin(Origin), Length(Length), Flags(Flags),
+ NegFlags(NegFlags) {}
+
std::string Name;
uint64_t Origin;
uint64_t Length;
uint32_t Flags;
uint32_t NegFlags;
+ uint64_t CurPos = 0;
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -161,24 +176,23 @@ struct InputSectionDescription : BaseCommand {
std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections;
};
-// Represents an ASSERT().
-struct AssertCommand : BaseCommand {
- AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
-
- static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; }
-
- Expr Expression;
-};
-
// Represents BYTE(), SHORT(), LONG(), or QUAD().
struct ByteCommand : BaseCommand {
- ByteCommand(Expr E, unsigned Size)
- : BaseCommand(ByteKind), Expression(E), Size(Size) {}
+ ByteCommand(Expr E, unsigned Size, std::string CommandString)
+ : BaseCommand(ByteKind), CommandString(CommandString), Expression(E),
+ Size(Size) {}
static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; }
+ // Keeps string representing the command. Used for -Map" is perhaps better.
+ std::string CommandString;
+
Expr Expression;
+
+ // This is just an offset of this assignment command in the output section.
unsigned Offset;
+
+ // Size of this data command.
unsigned Size;
};
@@ -200,8 +214,8 @@ class LinkerScript final {
uint64_t ThreadBssOffset = 0;
OutputSection *OutSec = nullptr;
MemoryRegion *MemRegion = nullptr;
- llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset;
- std::function<uint64_t()> LMAOffset;
+ MemoryRegion *LMARegion = nullptr;
+ uint64_t LMAOffset = 0;
};
llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection;
@@ -209,14 +223,13 @@ class LinkerScript final {
void addSymbol(SymbolAssignment *Cmd);
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
+ void expandOutputSection(uint64_t Size);
+ void expandMemoryRegions(uint64_t Size);
std::vector<InputSection *>
- computeInputSections(const InputSectionDescription *,
- const llvm::DenseMap<SectionBase *, int> &Order);
+ computeInputSections(const InputSectionDescription *);
- std::vector<InputSection *>
- createInputSectionList(OutputSection &Cmd,
- const llvm::DenseMap<SectionBase *, int> &Order);
+ std::vector<InputSection *> createInputSectionList(OutputSection &Cmd);
std::vector<size_t> getPhdrIndices(OutputSection *Sec);
@@ -251,7 +264,6 @@ public:
ExprValue getSymbolValue(StringRef Name, const Twine &Loc);
void addOrphanSections();
- void removeEmptyCommands();
void adjustSectionsBeforeSorting();
void adjustSectionsAfterSorting();
@@ -262,6 +274,10 @@ public:
void assignAddresses();
void allocateHeaders(std::vector<PhdrEntry *> &Phdrs);
void processSectionCommands();
+ void declareSymbols();
+
+ // Used to handle INSERT AFTER statements.
+ void processInsertCommands();
// SECTIONS command list.
std::vector<BaseCommand *> SectionCommands;
@@ -281,6 +297,11 @@ public:
// A list of symbols referenced by the script.
std::vector<llvm::StringRef> ReferencedSymbols;
+
+ // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need
+ // to be inserted into SECTIONS commands list.
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands;
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertBeforeCommands;
};
extern LinkerScript *Script;
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index dcc829315e64..54fddfb7b299 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -23,11 +23,13 @@
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -36,57 +38,46 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
-typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy;
+typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy;
+
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
// Print out the first three columns of a line.
-static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
- uint64_t Align) {
- int W = Config->Is64 ? 16 : 8;
- OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
+static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
+ uint64_t Size, uint64_t Align) {
+ if (Config->Is64)
+ OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align);
+ else
+ OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align);
}
-static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
-
// Returns a list of all symbols that we want to print out.
-static std::vector<Symbol *> getSymbols() {
- std::vector<Symbol *> V;
- for (InputFile *File : ObjectFiles) {
- for (Symbol *B : File->getSymbols()) {
- if (auto *SS = dyn_cast<SharedSymbol>(B))
- if (SS->CopyRelSec || SS->NeedsPltAddr)
- V.push_back(SS);
+static std::vector<Defined *> getSymbols() {
+ std::vector<Defined *> V;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *B : File->getSymbols())
if (auto *DR = dyn_cast<Defined>(B))
- if (DR->File == File && !DR->isSection() && DR->Section &&
- DR->Section->Live)
+ if (!DR->isSection() && DR->Section && DR->Section->Live &&
+ (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
V.push_back(DR);
- }
- }
return V;
}
// Returns a map from sections to their symbols.
-static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
+static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
SymbolMapTy Ret;
- for (Symbol *S : Syms) {
- if (auto *DR = dyn_cast<Defined>(S)) {
- Ret[DR->Section].push_back(S);
- continue;
- }
-
- SharedSymbol *SS = cast<SharedSymbol>(S);
- if (SS->CopyRelSec)
- Ret[SS->CopyRelSec].push_back(S);
- else
- Ret[InX::Plt].push_back(S);
- }
+ for (Defined *DR : Syms)
+ Ret[DR->Section].push_back(DR);
// Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared
// in the input files.
for (auto &It : Ret) {
- SmallVectorImpl<Symbol *> &V = It.second;
- std::sort(V.begin(), V.end(),
- [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); });
+ SmallVectorImpl<Defined *> &V = It.second;
+ std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
+ return A->getVA() < B->getVA();
+ });
}
return Ret;
}
@@ -95,12 +86,15 @@ static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
// Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for.
static DenseMap<Symbol *, std::string>
-getSymbolStrings(ArrayRef<Symbol *> Syms) {
+getSymbolStrings(ArrayRef<Defined *> Syms) {
std::vector<std::string> Str(Syms.size());
parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
- writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0);
- OS << indent(2) << toString(*Syms[I]);
+ OutputSection *OSec = Syms[I]->getOutputSection();
+ uint64_t VMA = Syms[I]->getVA();
+ uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0;
+ writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1);
+ OS << Indent16 << toString(*Syms[I]);
});
DenseMap<Symbol *, std::string> Ret;
@@ -109,6 +103,44 @@ getSymbolStrings(ArrayRef<Symbol *> Syms) {
return Ret;
}
+// Print .eh_frame contents. Since the section consists of EhSectionPieces,
+// we need a specialized printer for that section.
+//
+// .eh_frame tend to contain a lot of section pieces that are contiguous
+// both in input file and output file. Such pieces are squashed before
+// being displayed to make output compact.
+static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
+ std::vector<EhSectionPiece> Pieces;
+
+ auto Add = [&](const EhSectionPiece &P) {
+ // If P is adjacent to Last, squash the two.
+ if (!Pieces.empty()) {
+ EhSectionPiece &Last = Pieces.back();
+ if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff &&
+ Last.OutputOff + Last.Size == P.OutputOff) {
+ Last.Size += P.Size;
+ return;
+ }
+ }
+ Pieces.push_back(P);
+ };
+
+ // Gather section pieces.
+ for (const CieRecord *Rec : InX::EhFrame->getCieRecords()) {
+ Add(*Rec->Cie);
+ for (const EhSectionPiece *Fde : Rec->Fdes)
+ Add(*Fde);
+ }
+
+ // Print out section pieces.
+ for (EhSectionPiece &P : Pieces) {
+ writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff,
+ P.Size, 1);
+ OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x"
+ << Twine::utohexstr(P.InputOff) + ")\n";
+ }
+}
+
void elf::writeMapFile() {
if (Config->MapFile.empty())
return;
@@ -122,32 +154,109 @@ void elf::writeMapFile() {
}
// Collect symbol info that we want to print out.
- std::vector<Symbol *> Syms = getSymbols();
+ std::vector<Defined *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
// Print out the header line.
int W = Config->Is64 ? 16 : 8;
- OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
- << " Align Out In Symbol\n";
+ OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
+ << " Size Align Out In Symbol\n";
+
+ for (BaseCommand *Base : Script->SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ //FIXME: calculate and print LMA.
+ writeHeader(OS, Cmd->Addr, 0, Cmd->Size, 1);
+ OS << Cmd->CommandString << '\n';
+ continue;
+ }
- // Print out file contents.
- for (OutputSection *OSec : OutputSections) {
- writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+ auto *OSec = cast<OutputSection>(Base);
+ writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
// Dump symbols for each input section.
for (BaseCommand *Base : OSec->SectionCommands) {
- auto *ISD = dyn_cast<InputSectionDescription>(Base);
- if (!ISD)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
+ for (InputSection *IS : ISD->Sections) {
+ if (IS == InX::EhFrame) {
+ printEhFrame(OS, OSec);
+ continue;
+ }
+
+ writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0),
+ IS->getSize(), IS->Alignment);
+ OS << Indent8 << toString(IS) << '\n';
+ for (Symbol *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
+ writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset,
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0),
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
continue;
- for (InputSection *IS : ISD->Sections) {
- writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
- IS->Alignment);
- OS << indent(1) << toString(IS) << '\n';
- for (Symbol *Sym : SectionSyms[IS])
- OS << SymStr[Sym] << '\n';
}
}
}
}
+
+static void print(StringRef A, StringRef B) {
+ outs() << left_justify(A, 49) << " " << B << "\n";
+}
+
+// Output a cross reference table to stdout. This is for --cref.
+//
+// For each global symbol, we print out a file that defines the symbol
+// followed by files that uses that symbol. Here is an example.
+//
+// strlen /lib/x86_64-linux-gnu/libc.so.6
+// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
+// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
+//
+// In this case, strlen is defined by libc.so.6 and used by other two
+// files.
+void elf::writeCrossReferenceTable() {
+ if (!Config->Cref)
+ return;
+
+ // Collect symbols and files.
+ MapVector<Symbol *, SetVector<InputFile *>> Map;
+ for (InputFile *File : ObjectFiles) {
+ for (Symbol *Sym : File->getSymbols()) {
+ if (isa<SharedSymbol>(Sym))
+ Map[Sym].insert(File);
+ if (auto *D = dyn_cast<Defined>(Sym))
+ if (!D->isLocal() && (!D->Section || D->Section->Live))
+ Map[D].insert(File);
+ }
+ }
+
+ // Print out a header.
+ outs() << "Cross Reference Table\n\n";
+ print("Symbol", "File");
+
+ // Print out a table.
+ for (auto KV : Map) {
+ Symbol *Sym = KV.first;
+ SetVector<InputFile *> &Files = KV.second;
+
+ print(toString(*Sym), toString(Sym->File));
+ for (InputFile *File : Files)
+ if (File != Sym->File)
+ print("", toString(File));
+ }
+}
diff --git a/ELF/MapFile.h b/ELF/MapFile.h
index 2d93e26d4cf8..0282425888b7 100644
--- a/ELF/MapFile.h
+++ b/ELF/MapFile.h
@@ -13,6 +13,7 @@
namespace lld {
namespace elf {
void writeMapFile();
+void writeCrossReferenceTable();
} // namespace elf
} // namespace lld
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 88f558c7a3c6..a8371e212c3e 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -20,15 +20,15 @@
//
//===----------------------------------------------------------------------===//
+#include "MarkLive.h"
#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 "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
#include <functional>
@@ -60,8 +60,9 @@ static typename ELFT::uint getAddend(InputSectionBase &Sec,
static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
template <class ELFT, class RelT>
-static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+static void
+resolveReloc(InputSectionBase &Sec, RelT &Rel,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
// If a symbol is referenced in a live section, it is used.
@@ -90,7 +91,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
template <class ELFT>
static void
forEachSuccessor(InputSection &Sec,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
if (Sec.AreRelocsRela) {
for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
resolveReloc<ELFT>(Sec, Rel, Fn);
@@ -120,7 +121,7 @@ forEachSuccessor(InputSection &Sec,
template <class ELFT, class RelTy>
static void
scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
const endianness E = ELFT::TargetEndianness;
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
@@ -155,14 +156,10 @@ scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
template <class ELFT>
static void
scanEhFrameSection(EhInputSection &EH,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
if (!EH.NumRelocations)
return;
- // Unfortunately we need to split .eh_frame early since some relocations in
- // .eh_frame keep other section alive and some don't.
- EH.split<ELFT>();
-
if (EH.AreRelocsRela)
scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn);
else
@@ -207,7 +204,7 @@ template <class ELFT> static void doGcSections() {
// (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>(Sec))
- MS->markLiveAt(Offset);
+ MS->getSectionPiece(Offset)->Live = true;
if (Sec->Live)
return;
@@ -279,13 +276,18 @@ template <class ELFT> void elf::markLive() {
// The -gc-sections option works only for SHF_ALLOC sections
// (sections that are memory-mapped at runtime). So we can
- // unconditionally make non-SHF_ALLOC sections alive.
+ // unconditionally make non-SHF_ALLOC sections alive except
+ // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections.
//
- // Non SHF_ALLOC sections are not removed even if they are
+ // Usually, SHF_ALLOC sections are not removed even if they are
// unreachable through relocations because reachability is not
// a good signal whether they are garbage or not (e.g. there is
// usually no section referring to a .comment section, but we
- // want to keep it.)
+ // want to keep it.).
+ //
+ // Note on SHF_LINK_ORDER: Such sections contain metadata and they
+ // have a reverse dependency on the InputSection they are linked with.
+ // We are able to garbage collect them.
//
// Note on SHF_REL{,A}: Such sections reach here only when -r
// or -emit-reloc were given. And they are subject of garbage
@@ -293,8 +295,9 @@ template <class ELFT> void elf::markLive() {
// remove its relocation section.
for (InputSectionBase *Sec : InputSections) {
bool IsAlloc = (Sec->Flags & SHF_ALLOC);
+ bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER);
bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
- if (!IsAlloc && !IsRel)
+ if (!IsAlloc && !IsLinkOrder && !IsRel)
Sec->Live = true;
}
@@ -305,8 +308,7 @@ template <class ELFT> void elf::markLive() {
if (Config->PrintGcSections)
for (InputSectionBase *Sec : InputSections)
if (!Sec->Live)
- message("removing unused section from '" + Sec->Name + "' in file '" +
- Sec->File->getName() + "'");
+ message("removing unused section " + toString(Sec));
}
template void elf::markLive<ELF32LE>();
diff --git a/ELF/MarkLive.h b/ELF/MarkLive.h
new file mode 100644
index 000000000000..c9b99add34de
--- /dev/null
+++ b/ELF/MarkLive.h
@@ -0,0 +1,21 @@
+//===- MarkLive.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_MARKLIVE_H
+#define LLD_ELF_MARKLIVE_H
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> void markLive();
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_ELF_MARKLIVE_H
diff --git a/ELF/Options.td b/ELF/Options.td
index 20027e90aefd..73457db8332f 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -4,66 +4,91 @@ include "llvm/Option/OptParser.td"
// 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>;
-multiclass Eq<string name> {
- def "": Separate<["--", "-"], name>;
- def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+multiclass Eq<string name, string help> {
+ def NAME: Separate<["--", "-"], name>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
-def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">;
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--", "-"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+}
+
+defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified 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 Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
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: F<"build-id">, HelpText<"Alias for --build-id=fast">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+ MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">;
-def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+defm check_sections: B<"check-sections",
+ "Check section addresses for overlaps (default)",
+ "Do not check section addresses for overlaps">;
-defm compress_debug_sections : Eq<"compress-debug-sections">,
- HelpText<"Compress DWARF debug sections">;
+defm compress_debug_sections:
+ Eq<"compress-debug-sections", "Compress DWARF debug sections">,
+ MetaVarName<"[none,zlib]">;
-defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">;
+defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
-defm library_path: Eq<"library-path">,
- HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">;
+defm library_path:
+ Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-defm Tbss: Eq<"Tbss">,
- HelpText<"Same as --section-start with .bss as the sectionname">;
+defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
-defm Tdata: Eq<"Tdata">,
- HelpText<"Same as --section-start with .data as the sectionname">;
+defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
-defm Ttext: Eq<"Ttext">,
- HelpText<"Same as --section-start with .text as the sectionname">;
+defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">;
-def allow_multiple_definition: F<"allow-multiple-definition">,
- HelpText<"Allow multiple definitions">;
+defm allow_multiple_definition: B<"allow-multiple-definition",
+ "Allow multiple definitions",
+ "Do not allow multiple definitions (default)">;
-def as_needed: F<"as-needed">,
- HelpText<"Only set DT_NEEDED for shared libraries if used">;
+defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
+ "Apply dynamic relocations to place",
+ "Do not apply dynamic relocations to place">;
+
+defm as_needed: B<"as-needed",
+ "Only set DT_NEEDED for shared libraries if used",
+ "Always set DT_NEEDED for shared libraries (default)">;
+
+defm call_graph_ordering_file:
+ Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
// -chroot doesn't have a help text because it is an internal option.
-def chroot: S<"chroot">;
+def chroot: Separate<["--", "-"], "chroot">;
def color_diagnostics: F<"color-diagnostics">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Alias for --color-diagnostics=always">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics">,
+ MetaVarName<"[auto,always,never]">;
+
+defm cref: B<"cref",
+ "Output cross reference table",
+ "Do not output cross reference table">;
-def define_common: F<"define-common">,
- HelpText<"Assign space to common symbols">;
+defm define_common: B<"define-common",
+ "Assign space to common symbols",
+ "Do not assign space to common symbols">;
-def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+defm demangle: B<"demangle",
+ "Demangle symbol names (default)",
+ "Do not demangle symbol names">;
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -76,158 +101,126 @@ def discard_locals: F<"discard-locals">,
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">;
+defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
-defm dynamic_list: Eq<"dynamic-list">,
- HelpText<"Read a list of dynamic symbols">;
+defm dynamic_list: Eq<"dynamic-list", "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">;
+defm eh_frame_hdr: B<"eh-frame-hdr",
+ "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
+ "Do not create .eh_frame_hdr section">;
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
def enable_new_dtags: F<"enable-new-dtags">,
- HelpText<"Enable new dynamic tags">;
+ HelpText<"Enable new dynamic tags (default)">;
+
+def end_group: F<"end-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def end_lib: F<"end-lib">,
HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
-defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">,
+defm entry: Eq<"entry", "Name of entry point symbol">,
MetaVarName<"<entry>">;
-defm error_limit: Eq<"error-limit">,
- HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+defm error_limit:
+ Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
-defm exclude_libs: Eq<"exclude-libs">,
- HelpText<"Exclude static libraries from automatic export">;
+defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
-def export_dynamic: F<"export-dynamic">,
- HelpText<"Put symbols in the dynamic symbol table">;
+defm export_dynamic: B<"export-dynamic",
+ "Put symbols in the dynamic symbol table",
+ "Do not put symbols in the dynamic symbol table (default)">;
-defm export_dynamic_symbol: Eq<"export-dynamic-symbol">,
- HelpText<"Put a symbol in the dynamic symbol table">;
+defm export_dynamic_symbol:
+ Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
-def fatal_warnings: F<"fatal-warnings">,
- HelpText<"Treat warnings as errors">;
+defm fatal_warnings: B<"fatal-warnings",
+ "Treat warnings as errors",
+ "Do not treat warnings as errors (default)">;
-defm filter: Eq<"filter">,
- HelpText<"Set DT_FILTER field to the specified name">;
+defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">;
-defm fini: Eq<"fini">,
- HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">;
+defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
-def full_shutdown : F<"full-shutdown">,
- HelpText<"Perform a full shutdown instead of calling _exit">;
+defm format: Eq<"format", "Change the input format of the inputs following this option">,
+ MetaVarName<"[default,elf,binary]">;
-defm format: Eq<"format">,
- HelpText<"Change the input format of the inputs following this option">,
- MetaVarName<"<input-format>">;
+defm gc_sections: B<"gc-sections",
+ "Enable garbage collection of unused sections",
+ "Disable garbage collection of unused sections (default)">;
-def gc_sections: F<"gc-sections">,
- HelpText<"Enable garbage collection of unused sections">;
+defm gdb_index: B<"gdb-index",
+ "Generate .gdb_index section",
+ "Do not generate .gdb_index section (default)">;
-def gdb_index: F<"gdb-index">,
- HelpText<"Generate .gdb_index section">;
+defm gnu_unique: B<"gnu-unique",
+ "Enable STB_GNU_UNIQUE symbol binding (default)",
+ "Disable STB_GNU_UNIQUE symbol binding">;
-defm hash_style: Eq<"hash-style">,
- HelpText<"Specify hash style (sysv, gnu or both)">;
+defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">;
def help: F<"help">, HelpText<"Print option help">;
def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
-def icf_data: F<"icf-data">,
- HelpText<"Enable ICF to also fold identical read only data">;
+def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
+
+def ignore_function_address_equality: F<"ignore-function-address-equality">,
+ HelpText<"lld can break the address equality of functions">;
-def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
+def ignore_data_address_equality: F<"ignore-data-address-equality">,
+ HelpText<"lld can break the address equality of data">;
-defm image_base : Eq<"image-base">, HelpText<"Set the base address">;
+defm image_base: Eq<"image-base", "Set the base address">;
-defm init: Eq<"init">, HelpText<"Specify an initializer function">,
+defm init: Eq<"init", "Specify an initializer function">,
MetaVarName<"<symbol>">;
-defm library: Eq<"library">, HelpText<"Root name of library to use">,
- MetaVarName<"<libName>">;
+defm just_symbols: Eq<"just-symbols", "Just link symbols">;
-def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
- HelpText<"Optimization level for LTO">;
+defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
+
+defm library: Eq<"library", "Root name of library to use">,
+ MetaVarName<"<libName>">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
-defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">;
+defm Map: Eq<"Map", "Print a link map to the specified file">;
-def merge_exidx_entries: F<"merge-exidx-entries">,
- HelpText<"Enable merging .ARM.exidx entries">;
+defm merge_exidx_entries: B<"merge-exidx-entries",
+ "Enable merging .ARM.exidx entries (default)",
+ "Disable merging .ARM.exidx entries">;
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
-def no_as_needed: F<"no-as-needed">,
- HelpText<"Always DT_NEEDED for shared libraries">;
-
def no_color_diagnostics: F<"no-color-diagnostics">,
HelpText<"Do not use colors in diagnostics">;
-def no_define_common: F<"no-define-common">,
- HelpText<"Do not assign space to common symbols">;
-
-def no_demangle: F<"no-demangle">,
- HelpText<"Do not demangle symbol names">;
-
def no_dynamic_linker: F<"no-dynamic-linker">,
HelpText<"Inhibit output of .interp section">;
-def no_eh_frame_hdr: F<"no-eh-frame-hdr">,
- HelpText<"Do not create .eh_frame_hdr section">;
-
-def no_export_dynamic: F<"no-export-dynamic">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
-
-def no_gc_sections: F<"no-gc-sections">,
- HelpText<"Disable garbage collection of unused sections">;
-
-def no_gdb_index: F<"no-gdb-index">,
- HelpText<"Do not generate .gdb_index section">;
-
-def no_gnu_unique: F<"no-gnu-unique">,
- HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
-
-def no_merge_exidx_entries: F<"no-merge-exidx-entries">,
- HelpText<"Disable merging .ARM.exidx entries">;
-
-def no_threads: F<"no-threads">,
- HelpText<"Do not run the linker multi-threaded">;
-
-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 nopie: F<"nopie">, HelpText<"Do not create a position independent executable">;
-
-def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">,
+def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">,
HelpText<"Do not set the text data sections to be writable">;
-def no_print_gc_sections: F<"no-print-gc-sections">,
- HelpText<"Do not list removed unused sections">;
-
def no_rosegment: F<"no-rosegment">,
HelpText<"Do not put read-only non-executable sections in their own segment">;
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">;
@@ -237,42 +230,62 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
-defm orphan_handling: Eq<"orphan-handling">,
- HelpText<"Control how orphan sections are handled when linker script used">;
+defm orphan_handling:
+ Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
+
+defm pack_dyn_relocs:
+ Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
+ MetaVarName<"[none,android,relr,android+relr]">;
+
+defm use_android_relr_tags: B<"use-android-relr-tags",
+ "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
+ "Use SHT_RELR / DT_RELR* tags (default)">;
+
+defm pie: B<"pie",
+ "Create a position independent executable",
+ "Do not create a position independent executable (default)">;
+
+defm print_gc_sections: B<"print-gc-sections",
+ "List removed unused sections",
+ "Do not list removed unused sections (default)">;
-def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">,
- HelpText<"Pack dynamic relocations in the given format (none or android)">;
+defm print_icf_sections: B<"print-icf-sections",
+ "List identical folded sections",
+ "Do not list identical folded sections (default)">;
-def pie: F<"pie">, HelpText<"Create a position independent executable">;
+def pop_state: F<"pop-state">,
+ HelpText<"Undo the effect of -push-state">;
-def print_gc_sections: F<"print-gc-sections">,
- HelpText<"List removed unused sections">;
+def push_state: F<"push-state">,
+ HelpText<"Save the current state of -as-needed, -static and -whole-archive">;
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce">,
- HelpText<"Dump linker invocation and input files for debugging">;
+defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
-defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
-defm retain_symbols_file: Eq<"retain-symbols-file">,
- HelpText<"Retain only the symbols listed in the file">,
+defm retain_symbols_file:
+ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
MetaVarName<"<file>">;
-defm script: Eq<"script">, HelpText<"Read linker script">;
+defm script: Eq<"script", "Read linker script">;
-def section_start: S<"section-start">, MetaVarName<"<address>">,
- HelpText<"Set address of section">;
+defm section_start: Eq<"section-start", "Set address of section">,
+ MetaVarName<"<address>">;
def shared: F<"shared">, HelpText<"Build a shared object">;
-defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">;
+defm soname: Eq<"soname", "Set DT_SONAME">;
-defm sort_section: Eq<"sort-section">,
- HelpText<"Specifies sections sorting rule when linkerscript is used">;
+defm sort_section:
+ Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">;
+
+def start_group: F<"start-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
@@ -281,33 +294,39 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
-def symbol_ordering_file: S<"symbol-ordering-file">,
- HelpText<"Layout sections in the order specified by symbol file">;
+defm symbol_ordering_file:
+ Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">;
-defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">;
+defm sysroot: Eq<"sysroot", "Set the system root">;
def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
-def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">;
-defm target2: Eq<"target2">,
- HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
+defm target2:
+ Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
MetaVarName<"<type>">;
-def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+defm threads: B<"threads",
+ "Run the linker multi-threaded (default)",
+ "Do not run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">;
+defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
+
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
+ MetaVarName<"<symbol>">;
-defm undefined: Eq<"undefined">,
- HelpText<"Force undefined symbol during linking">;
+defm unresolved_symbols:
+ Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">;
-defm unresolved_symbols: Eq<"unresolved-symbols">,
- HelpText<"Determine how to handle unresolved symbols">;
+defm undefined_version: B<"undefined-version",
+ "Allow unused version in version script (default)",
+ "Report version scripts that refer undefined symbols">;
-defm rsp_quoting: Eq<"rsp-quoting">,
- HelpText<"Quoting style for response files. Values supported: windows|posix">;
+defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
+ MetaVarName<"[posix,windows]">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
@@ -315,91 +334,123 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def version: F<"version">, HelpText<"Display the version number and exit">;
-defm version_script: Eq<"version-script">, HelpText<"Read a version script">;
+defm version_script: Eq<"version-script", "Read a version script">;
+
+defm warn_backrefs: B<"warn-backrefs",
+ "Warn about backward symbol references to fetch archive members",
+ "Do not warn about backward symbol references to fetch archive members (default)">;
+
+defm warn_common: B<"warn-common",
+ "Warn about duplicate common symbols",
+ "Do not warn about duplicate common symbols (default)">;
-def warn_common: F<"warn-common">,
- HelpText<"Warn about duplicate common symbols">;
+defm warn_symbol_ordering: B<"warn-symbol-ordering",
+ "Warn about problems with the symbol ordering file (default)",
+ "Do not warn about problems with the symbol ordering file">;
def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
HelpText<"Report unresolved symbols as warnings">;
-def whole_archive: F<"whole-archive">,
- HelpText<"Force load of all members in a static library">;
+defm whole_archive: B<"whole-archive",
+ "Force load of all members in a static library",
+ "Do not force load of all members in a static library (default)">;
-defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">,
- MetaVarName<"<symbol>">;
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
-def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
-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_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_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
-def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
-def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
-def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
-def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
-def alias_filter: Separate<["-"], "F">, Alias<filter>;
-def alias_format_b: S<"b">, Alias<format>;
-def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>;
-def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>;
-def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
-def alias_o_output: Joined<["--"], "output=">, Alias<o>;
-def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
-def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
-def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
-def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_rpath_R: JoinedOrSeparate<["-"], "R">, 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_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_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
-def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
-def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
-def alias_version_V: Flag<["-"], "V">, Alias<version>;
-
-// 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<["-"], "(">;
+def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">;
+def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">;
+def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">;
+def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">;
+def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
+def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
+def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
+def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
+def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
+def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;
+def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">;
+def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
+def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">;
+def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">;
+def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">;
+def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">;
+def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">;
+def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
+def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">;
+def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">;
// LTO-related options.
def lto_aa_pipeline: J<"lto-aa-pipeline=">,
HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_debug_pass_manager: F<"lto-debug-pass-manager">,
+ HelpText<"Debug new pass manager">;
+def lto_new_pass_manager: F<"lto-new-pass-manager">,
+ HelpText<"Use new pass manager">;
def lto_newpm_passes: J<"lto-newpm-passes=">,
HelpText<"Passes to run during LTO">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
+def lto_sample_profile: J<"lto-sample-profile=">,
+ HelpText<"Sample profile file path">;
def disable_verify: F<"disable-verify">;
-def mllvm: S<"mllvm">;
+defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
HelpText<"YAML output file for optimization remarks">;
def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
- HelpText<"Include hotness informations in the optimization remarks file">;
-defm plugin_opt: Eq<"plugin-opt">,
- HelpText<"specifies LTO options for compatibility with GNU linkers">;
+ HelpText<"Include hotness information in the optimization remarks file">;
+defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
-def thinlto_cache_policy: S<"thinlto-cache-policy">,
- HelpText<"Pruning policy for the ThinLTO cache">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
+def: F<"plugin-opt=debug-pass-manager">,
+ Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">;
+def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
+def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
+ HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
+def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
+def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
+def: F<"plugin-opt=new-pass-manager">,
+ Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">;
+def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
+def: J<"plugin-opt=sample-profile=">,
+ Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">;
+def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">;
+def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
+def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
+def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
+def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
+def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+
// 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
@@ -407,31 +458,38 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
// 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=">;
+defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
+
+def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
+def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
+def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
+def plugin_opt_slash: J<"plugin-opt=/">;
// Options listed below are silently ignored for now for compatibility.
-def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def cref: F<"cref">;
-def detect_odr_violations: F<"detect-odr-violations">;
-def g: Flag<["-"], "g">;
-def long_plt: F<"long-plt">;
-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">;
-def no_ctors_in_init_array: F<"no-ctors-in-init-array">;
-def no_keep_memory: F<"no-keep-memory">;
-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 stats: F<"stats">;
-def warn_execstack: F<"warn-execstack">;
-def warn_once: F<"warn-once">;
-def warn_shared_textrel: F<"warn-shared-textrel">;
-def EB : F<"EB">;
-def EL : F<"EL">;
-def G: JoinedOrSeparate<["-"], "G">;
-def Qy : F<"Qy">;
+def: F<"allow-shlib-undefined">;
+def: F<"detect-odr-violations">;
+def: Flag<["-"], "g">;
+def: F<"long-plt">;
+def: F<"no-add-needed">;
+def: F<"no-allow-shlib-undefined">;
+def: F<"no-copy-dt-needed-entries">;
+def: F<"no-ctors-in-init-array">;
+def: F<"no-keep-memory">;
+def: F<"no-mmap-output-file">;
+def: F<"no-warn-mismatch">;
+def: Separate<["--", "-"], "rpath-link">;
+def: J<"rpath-link=">;
+def: F<"sort-common">;
+def: F<"stats">;
+def: F<"warn-execstack">;
+def: F<"warn-once">;
+def: F<"warn-shared-textrel">;
+def: F<"EB">;
+def: F<"EL">;
+def: JoinedOrSeparate<["-"], "G">;
+def: F<"Qy">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+ Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+ Flags<[HelpHidden]>;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index f0677f7e1ca5..8253b18b486c 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -10,11 +10,11 @@
#include "OutputSections.h"
#include "Config.h"
#include "LinkerScript.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Compression.h"
@@ -25,15 +25,12 @@
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;
uint8_t Out::First;
-OutputSection *Out::Opd;
-uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
@@ -45,7 +42,9 @@ OutputSection *Out::FiniArray;
std::vector<OutputSection *> elf::OutputSections;
uint32_t OutputSection::getPhdrFlags() const {
- uint32_t Ret = PF_R;
+ uint32_t Ret = 0;
+ if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE))
+ Ret |= PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
@@ -70,9 +69,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
: BaseCommand(OutputSectionKind),
SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
- /*Info*/ 0,
- /*Link*/ 0),
- SectionIndex(INT_MAX) {
+ /*Info*/ 0, /*Link*/ 0) {
Live = false;
}
@@ -91,13 +88,15 @@ static bool canMergeToProgbits(unsigned Type) {
void OutputSection::addSection(InputSection *IS) {
if (!Live) {
// If IS is the first section to be added to this section,
- // initialize Type and Entsize from IS.
+ // initialize Type, Entsize and flags from IS.
Live = true;
Type = IS->Type;
Entsize = IS->Entsize;
+ Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
- if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS)))
+ unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
+ if ((Flags & Mask) != (IS->Flags & Mask))
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
": 0x" + utohexstr(Flags));
@@ -114,9 +113,14 @@ void OutputSection::addSection(InputSection *IS) {
}
IS->Parent = this;
- Flags |= IS->Flags;
+ uint64_t AndMask =
+ Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
+ uint64_t OrMask = ~AndMask;
+ uint64_t AndFlags = (Flags & IS->Flags) & AndMask;
+ uint64_t OrFlags = (Flags | IS->Flags) & OrMask;
+ Flags = AndFlags | OrFlags;
+
Alignment = std::max(Alignment, IS->Alignment);
- IS->OutSecOff = Size++;
// If this section contains a table of fixed-size entries, sh_entsize
// holds the element size. If it contains elements of different size we
@@ -134,8 +138,8 @@ void OutputSection::addSection(InputSection *IS) {
}
}
-void elf::sortByOrder(MutableArrayRef<InputSection *> In,
- std::function<int(InputSectionBase *S)> Order) {
+static void sortByOrder(MutableArrayRef<InputSection *> In,
+ llvm::function_ref<int(InputSectionBase *S)> Order) {
typedef std::pair<int, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
@@ -158,11 +162,11 @@ bool OutputSection::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
-void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
+void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
assert(Live);
- assert(SectionCommands.size() == 1);
- sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections,
- Order);
+ for (BaseCommand *B : SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortByOrder(ISD->Sections, Order);
}
// Fill [Buf, Buf + Size) with Filler.
@@ -183,15 +187,6 @@ template <class ELFT> void OutputSection::maybeCompress() {
!Name.startswith(".debug_"))
return;
- // Calculate the section offsets and size pre-compression.
- Size = 0;
- for (BaseCommand *Cmd : SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
- for (InputSection *IS : ISD->Sections) {
- IS->OutSecOff = alignTo(Size, IS->Alignment);
- this->Size = IS->OutSecOff + IS->getSize();
- }
-
// Create a section header.
ZDebugHeader.resize(sizeof(Elf_Chdr));
auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data());
@@ -214,11 +209,11 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
if (Size == 1)
*Buf = Data;
else if (Size == 2)
- write16(Buf, Data, Config->Endianness);
+ write16(Buf, Data);
else if (Size == 4)
- write32(Buf, Data, Config->Endianness);
+ write32(Buf, Data);
else if (Size == 8)
- write64(Buf, Data, Config->Endianness);
+ write64(Buf, Data);
else
llvm_unreachable("unsupported Size argument");
}
@@ -240,12 +235,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
}
// Write leading padding.
- std::vector<InputSection *> Sections;
- for (BaseCommand *Cmd : SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
- for (InputSection *IS : ISD->Sections)
- if (IS->Live)
- Sections.push_back(IS);
+ std::vector<InputSection *> Sections = getInputSections(this);
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
@@ -290,17 +280,13 @@ static void finalizeShtGroup(OutputSection *OS,
}
template <class ELFT> void OutputSection::finalize() {
- InputSection *First = nullptr;
- for (BaseCommand *Base : SectionCommands) {
- if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
- if (ISD->Sections.empty())
- continue;
- if (First == nullptr)
- First = ISD->Sections.front();
- }
- if (isa<ByteCommand>(Base) && Type == SHT_NOBITS)
- Type = SHT_PROGBITS;
- }
+ if (Type == SHT_NOBITS)
+ for (BaseCommand *Base : SectionCommands)
+ if (isa<ByteCommand>(Base))
+ Type = SHT_PROGBITS;
+
+ std::vector<InputSection *> V = getInputSections(this);
+ InputSection *First = V.empty() ? nullptr : V[0];
if (Flags & SHF_LINK_ORDER) {
// We must preserve the link order dependency of sections with the
@@ -376,8 +362,6 @@ static bool compCtors(const InputSection *A, const InputSection *B) {
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;
}
@@ -403,6 +387,14 @@ int elf::getPriority(StringRef S) {
return V;
}
+std::vector<InputSection *> elf::getInputSections(OutputSection *OS) {
+ std::vector<InputSection *> Ret;
+ for (BaseCommand *Base : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end());
+ return Ret;
+}
+
// 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
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index b2845773e9af..efb6aabe9743 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -14,7 +14,6 @@
#include "InputSection.h"
#include "LinkerScript.h"
#include "Relocations.h"
-
#include "lld/Common/LLVM.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
@@ -49,10 +48,10 @@ public:
static bool classof(const BaseCommand *C);
- uint64_t getLMA() const { return Addr + LMAOffset; }
+ uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
- unsigned SectionIndex;
+ uint32_t SectionIndex = UINT32_MAX;
unsigned SortRank;
uint32_t getPhdrFlags() const;
@@ -78,7 +77,6 @@ public:
// The following fields correspond to Elf_Shdr members.
uint64_t Offset = 0;
- uint64_t LMAOffset = 0;
uint64_t Addr = 0;
uint32_t ShName = 0;
@@ -89,6 +87,7 @@ public:
// The following members are normally only used in linker scripts.
MemoryRegion *MemRegion = nullptr;
+ MemoryRegion *LMARegion = nullptr;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
@@ -99,13 +98,17 @@ public:
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
+ std::string LMARegionName;
+ bool NonAlloc = false;
bool Noload = false;
+ bool ExpressionsUseSymbols = false;
+ bool InOverlay = false;
template <class ELFT> void finalize();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
- void sort(std::function<int(InputSectionBase *S)> Order);
+ void sort(llvm::function_ref<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
@@ -119,13 +122,13 @@ private:
int getPriority(StringRef S);
+std::vector<InputSection *> getInputSections(OutputSection* OS);
+
// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
struct Out {
static uint8_t First;
- static OutputSection *Opd;
- static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
@@ -142,8 +145,6 @@ namespace lld {
namespace elf {
uint64_t getHeaderSize();
-void sortByOrder(llvm::MutableArrayRef<InputSection *> In,
- std::function<int(InputSectionBase *S)> Order);
extern std::vector<OutputSection *> OutputSections;
} // namespace elf
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 1aa0957b1d01..467219ad0542 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -45,14 +45,14 @@
#include "Config.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/Memory.h"
-
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
return Msg + S.getObjMsg(Off);
}
-// This is a MIPS-specific rule.
-//
-// 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.
-static bool isMipsGprel(RelType Type) {
- if (Config->EMachine != EM_MIPS)
- return false;
- Type &= 0xff;
- return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
- Type == R_MICROMIPS_GPREL7_S2;
-}
-
// This function is similar to the `handleTlsRelocation`. MIPS does not
// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
// Mips has a custom MipsGotSection that handles the writing of GOT entries
// without dynamic relocations.
-template <class ELFT>
static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- if (InX::MipsGot->addTlsIndex() && Config->Pic)
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
- InX::MipsGot->getTlsIndexOff(), false, nullptr,
- 0});
+ InX::MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
-
if (Expr == R_MIPS_TLSGD) {
- if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) {
- uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0});
- if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
- Off + Config->Wordsize, false, &Sym, 0});
- }
+ InX::MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {
if (Dyn)
- InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
+ InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest);
else
InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
@@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_ARM)
return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+ return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
@@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
- if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
+ if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC,
+ R_TLSLD_HINT>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
- {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
- return 2;
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ return Target->TlsGdRelaxSkip;
}
+ if (Expr == R_TLSLD_HINT)
+ return 1;
if (InX::Got->addTlsIndex())
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
- InX::Got->getTlsIndexOff(), false, nullptr, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
+ InX::Got->getTlsIndexOff(), nullptr);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
- if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
- C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ if (Expr == R_ABS && !Config->Shared) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
return 1;
}
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
- R_TLSGD_PC>(Expr)) {
+ // Local-Dynamic sequence where offset of tls variable relative to dynamic
+ // thread pointer is stored in the got.
+ if (Expr == R_TLSLD_GOT_OFF) {
+ // Local-Dynamic relocs can be relaxed to local-exec
+ if (!Config->Shared) {
+ C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ if (!Sym.isInGot()) {
+ InX::Got->addEntry(Sym);
+ uint64_t Off = Sym.getGotOffset();
+ InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (InX::Got->addDynTlsEntry(Sym)) {
uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym);
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
uint64_t OffsetOff = Off + Config->Wordsize;
if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc(
- {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff,
+ &Sym);
else
InX::Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
@@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
Offset, Addend, &Sym});
if (!Sym.isInGot()) {
InX::Got->addEntry(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(),
+ &Sym);
}
} else {
C.Relocations.push_back(
@@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) {
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_RELAX_GOT_PC>(Expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) {
static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
- if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
- R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+ if (isRelExprOneOf<
+ R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
+ R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -384,6 +376,10 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
if (!Config->Pic)
return true;
+ // The size of a non preemptible symbol is a constant.
+ if (E == R_SIZE)
+ return true;
+
// For the target and the relocation, we want to know if they are
// absolute or relative.
bool AbsVal = isAbsoluteValue(Sym);
@@ -413,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
}
static RelExpr toPlt(RelExpr Expr) {
- if (Expr == R_PPC_OPD)
- return R_PPC_PLT_OPD;
- if (Expr == R_PC)
+ switch (Expr) {
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
+ case R_PC:
return R_PLT_PC;
- if (Expr == R_PAGE_PC)
+ case R_PAGE_PC:
return R_PLT_PAGE_PC;
- if (Expr == R_ABS)
+ case R_ABS:
return R_PLT;
- return Expr;
+ default:
+ 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)
+ switch (Expr) {
+ case R_PLT_PC:
return R_PC;
- if (Expr == R_PPC_PLT_OPD)
- return R_PPC_OPD;
- if (Expr == R_PLT)
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
+ case R_PLT:
return R_ABS;
- return Expr;
+ default:
+ return Expr;
+ }
}
// Returns true if a given shared symbol is in a read-only segment in a DSO.
-template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
+template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {
typedef typename ELFT::Phdr Elf_Phdr;
// Determine if the symbol is read-only by scanning the DSO's program headers.
- const SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ const SharedFile<ELFT> &File = SS.getFile<ELFT>();
for (const Elf_Phdr &Phdr : check(File.getObj().program_headers()))
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
- !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr &&
- SS->Value < Phdr.p_vaddr + Phdr.p_memsz)
+ !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr &&
+ SS.Value < Phdr.p_vaddr + Phdr.p_memsz)
return true;
return false;
}
@@ -454,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
//
// If two or more symbols are at the same offset, and at least one of
// them are copied by a copy relocation, all of them need to be copied.
-// Otherwise, they would refer different places at runtime.
+// Otherwise, they would refer to different places at runtime.
template <class ELFT>
-static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
+static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
typedef typename ELFT::Sym Elf_Sym;
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ SharedFile<ELFT> &File = SS.getFile<ELFT>();
- std::vector<SharedSymbol *> Ret;
+ SmallSet<SharedSymbol *, 4> Ret;
for (const Elf_Sym &S : File.getGlobalELFSyms()) {
if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS ||
- S.st_value != SS->Value)
+ S.st_value != SS.Value)
continue;
StringRef Name = check(S.getName(File.getStringTable()));
Symbol *Sym = Symtab->find(Name);
if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
- Ret.push_back(Alias);
+ Ret.insert(Alias);
}
return Ret;
}
+// When a symbol is copy relocated or we create a canonical plt entry, it is
+// effectively a defined symbol. In the case of copy relocation the symbol is
+// in .bss and in the case of a canonical plt entry it is in .plt. This function
+// replaces the existing symbol with a Defined pointing to the appropriate
+// location.
+static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
+ uint64_t Size) {
+ Symbol Old = Sym;
+ replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
+ Sym.StOther, Sym.Type, Value, Size, Sec);
+ Sym.PltIndex = Old.PltIndex;
+ Sym.GotIndex = Old.GotIndex;
+ Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.IsPreemptible = true;
+ Sym.ExportDynamic = true;
+ Sym.IsUsedInRegularObj = true;
+ Sym.Used = true;
+}
+
// Reserve space in .bss or .bss.rel.ro for copy relocation.
//
// The copy relocation is pretty much a hack. If you use a copy relocation
@@ -516,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
// to the variable in .bss. This kind of issue is sometimes very hard to
// debug. What's a solution? Instead of exporting a varaible V from a DSO,
// define an accessor getV().
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
// Copy relocation against zero-sized symbol doesn't make sense.
- uint64_t SymSize = SS->getSize();
- if (SymSize == 0)
- fatal("cannot create a copy relocation for symbol " + toString(*SS));
+ uint64_t SymSize = SS.getSize();
+ if (SymSize == 0 || SS.Alignment == 0)
+ fatal("cannot create a copy relocation for symbol " + toString(SS));
// See if this symbol is in a read-only segment. If so, preserve the symbol's
// memory protection by reserving space in the .bss.rel.ro section.
bool IsReadOnly = isReadOnly<ELFT>(SS);
BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
- SymSize, SS->Alignment);
+ SymSize, SS.Alignment);
if (IsReadOnly)
InX::BssRelRo->getParent()->addSection(Sec);
else
@@ -535,125 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
// 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 (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
- Sym->CopyRelSec = Sec;
- Sym->IsPreemptible = false;
- Sym->IsUsedInRegularObj = true;
- Sym->Used = true;
- }
-
- InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0});
-}
-
-static void errorOrWarn(const Twine &Msg) {
- if (!Config->NoinhibitExec)
- error(Msg);
- else
- warn(Msg);
-}
-
-// Returns PLT relocation expression.
-//
-// 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).
-static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) {
- Sym.NeedsPltAddr = true;
- Sym.IsPreemptible = false;
- IsConstant = true;
- return toPlt(Expr);
-}
-
-// This modifies the expression if we can use a copy relocation or point the
-// symbol to the PLT.
-template <class ELFT>
-static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type,
- InputSectionBase &S, uint64_t RelOff,
- bool &IsConstant) {
- // If a relocation can be applied at link-time, we don't need to
- // create a dynamic relocation in the first place.
- if (IsConstant)
- return Expr;
-
- // If the relocation is to a weak undef, and we are producing
- // executable, give up on it and produce a non preemptible 0.
- if (!Config->Shared && Sym.isUndefWeak()) {
- Sym.IsPreemptible = false;
- IsConstant = true;
- return Expr;
- }
-
- // We can create any dynamic relocation supported by the dynamic linker if a
- // section is writable or we are passed -z notext.
- bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText;
- if (CanWrite && Target->isPicRel(Type))
- return Expr;
-
- // If we got here we know that this relocation would require the dynamic
- // linker to write a value to read only memory or use an unsupported
- // relocation.
-
- // We can hack around it if we are producing an executable and
- // the refered symbol can be preemepted to refer to the executable.
- if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) {
- error(
- "can't create dynamic relocation " + toString(Type) + " against " +
- (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
- " in readonly segment; recompile object files with -fPIC" +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- // Copy relocations are only possible if we are creating an executable and the
- // symbol is shared.
- if (!Sym.isShared() || Config->Shared)
- return Expr;
-
- if (Sym.getVisibility() != STV_DEFAULT) {
- error("cannot preempt symbol: " + toString(Sym) +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- if (Sym.isObject()) {
- // Produce a copy relocation.
- auto *B = dyn_cast<SharedSymbol>(&Sym);
- if (B && !B->CopyRelSec) {
- if (Config->ZNocopyreloc)
- error("unresolvable relocation " + toString(Type) +
- " against symbol '" + toString(*B) +
- "'; recompile with -fPIC or remove '-z nocopyreloc'" +
- getLocation(S, Sym, RelOff));
-
- addCopyRelSymbol<ELFT>(B);
- }
- IsConstant = true;
- return Expr;
- }
-
- if (Sym.isFunc())
- return getPltExpr(Sym, Expr, IsConstant);
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
+ replaceWithDefined(*Sym, Sec, 0, Sym->Size);
- errorOrWarn("symbol '" + toString(Sym) + "' defined in " +
- toString(Sym.File) + " has no type");
- return Expr;
+ InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -728,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
return false;
bool CanBeExternal =
- Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT;
+ Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT;
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return false;
@@ -756,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
// this for the N32 ABI. Iterate over relocation with the same offset and put
// theirs types into the single bit-set.
template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) {
- RelType Type = Rel->getType(Config->IsMips64EL);
+ RelType Type = 0;
uint64_t Offset = Rel->r_offset;
int N = 0;
- while (Rel + 1 != End && (Rel + 1)->r_offset == Offset)
- Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N);
+ while (Rel != End && Rel->r_offset == Offset)
+ Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++);
return Type;
}
@@ -811,16 +717,34 @@ private:
};
} // namespace
+static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Add a relative relocation. If RelrDyn section is enabled, and the
+ // relocation offset is guaranteed to be even, add the relocation to
+ // the RelrDyn section, otherwise add it to the RelaDyn section.
+ // RelrDyn sections don't support odd offsets. Also, RelrDyn sections
+ // don't store the addend values, so we must write it to the relocated
+ // address.
+ if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
+ IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ return;
+ }
+ InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
+ Expr, Type);
+}
+
template <class ELFT, class GotPltSection>
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
- RelocationBaseSection *Rel, RelType Type, Symbol &Sym,
- bool UseSymVA) {
+ RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
Plt->addEntry<ELFT>(Sym);
GotPlt->addEntry(Sym);
- Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+ Rel->addReloc(
+ {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0});
}
-template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
+template <class ELFT> static void addGotEntry(Symbol &Sym) {
InX::Got->addEntry(Sym);
RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
@@ -833,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// add a static relocation to a Relocations vector so that
// InputSection::relocate will do the work for us. We may be able
// to just write a value now, but it is a TODO.)
- bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym));
+ bool IsLinkTimeConstant =
+ !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
if (IsLinkTimeConstant) {
InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
return;
@@ -841,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
- RelType Type;
- if (Sym.isTls())
- Type = Target->TlsGotRel;
- else if (!Preemptible && Config->Pic && !isAbsolute(Sym))
- Type = Target->RelativeRel;
- else
- Type = Target->GotRel;
- InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0});
+ if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
+ addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ return;
+ }
+ InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
+ InX::Got, Off, &Sym, 0,
+ Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
+}
- // REL type relocations don't have addend fields unlike RELAs, and
- // their addends are stored to the section to which they are applied.
- // So, store addends if we need to.
- //
- // This is ugly -- the difference between REL and RELA should be
- // handled in a better way. It's a TODO.
- if (!Config->IsRela && !Preemptible)
- InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym});
+// Return true if we can define a symbol in the executable that
+// contains the value/function of a symbol defined in a shared
+// library.
+static bool canDefineSymbolInExecutable(Symbol &Sym) {
+ // If the symbol has default visibility the symbol defined in the
+ // executable will preempt it.
+ // Note that we want the visibility of the shared symbol itself, not
+ // the visibility of the symbol in the output file we are producing. That is
+ // why we use Sym.StOther.
+ if ((Sym.StOther & 0x3) == STV_DEFAULT)
+ return true;
+
+ // If we are allowed to break address equality of functions, defining
+ // a plt entry will allow the program to call the function in the
+ // .so, but the .so and the executable will no agree on the address
+ // of the function. Similar logic for objects.
+ return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) ||
+ (Sym.isObject() && Config->IgnoreDataAddressEquality));
}
// The reason we have to do this early scan is as follows
@@ -874,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// 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 &Sec, ArrayRef<RelTy> Rels) {
- OffsetGetter GetOffset(Sec);
-
- // Not all relocations end up in Sec.Relocations, but a lot do.
- Sec.Relocations.reserve(Rels.size());
-
- for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
- const RelTy &Rel = *I;
- Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
- RelType Type = Rel.getType(Config->IsMips64EL);
-
- // Deal with MIPS oddity.
- if (Config->MipsN32Abi)
- Type = getMipsN32RelType(I, End);
-
- // Get an offset in an output section this relocation is applied to.
- uint64_t Offset = GetOffset.get(Rel.r_offset);
- if (Offset == uint64_t(-1))
- continue;
-
- // Skip if the target symbol is an erroneous undefined symbol.
- if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
- continue;
-
- RelExpr Expr =
- Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset);
-
- // Ignore "hint" relocations because they are only markers for relaxation.
- if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
- continue;
-
- // Handle yet another MIPS-ness.
- if (isMipsGprel(Type)) {
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
- Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym});
- continue;
- }
-
- bool Preemptible = Sym.IsPreemptible;
-
- // Strenghten or relax a PLT access.
- //
- // GNU ifunc symbols must be accessed via PLT because their addresses
- // are determined by runtime.
- //
- // On the other hand, if we know that a PLT entry will be resolved within
- // the same ELF module, we can skip PLT access and directly jump to the
- // destination function. For example, if we are linking a main exectuable,
- // all dynamic symbols that can be resolved within the executable will
- // actually be resolved that way at runtime, because the main exectuable
- // is always at the beginning of a search list. We can leverage that fact.
- if (Sym.isGnuIFunc())
- Expr = toPlt(Expr);
- else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
- Expr =
- Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr);
- else if (!Preemptible)
- Expr = fromPlt(Expr);
-
- bool IsConstant =
- isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset);
-
- Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant);
- if (errorCount())
- 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 (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
- R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
- InX::Got->HasGotOffRel = true;
-
- // Read an addend.
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
-
- // Process some TLS relocations, including relaxing TLS relocations.
- // Note that this function does not handle all TLS relocations.
- if (unsigned Processed =
- handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) {
- I += (Processed - 1);
- continue;
- }
-
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
- if (needsPlt(Expr) && !Sym.isInPlt()) {
- if (Sym.isGnuIFunc() && !Preemptible)
- addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
- Target->IRelativeRel, Sym, true);
- else
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
- Sym, !Preemptible);
- }
-
- // Create a GOT slot if a relocation needs GOT.
- if (needsGot(Expr)) {
- if (Config->EMachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // 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
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- if (Sym.isTls() && Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
- Sym.getGotOffset(), false, &Sym, 0});
- } else if (!Sym.isInGot()) {
- addGotEntry<ELFT>(Sym, Preemptible);
- }
- }
-
- if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) {
- // We don't know anything about the finaly symbol. Just ask the dynamic
- // linker to handle the relocation for us.
- if (!Target->isPicRel(Type))
- errorOrWarn(
- "relocation " + toString(Type) +
- " cannot be used against shared object; recompile with -fPIC" +
- getLocation(Sec, Sym, Offset));
+static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
+ uint64_t Offset, Symbol &Sym, const RelTy &Rel,
+ int64_t Addend) {
+ if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+ bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
+ if (CanWrite) {
+ // R_GOT refers to a position in the got, even if the symbol is preemptible.
+ bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;
- InX::RelaDyn->addReloc(
- {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend});
+ if (!IsPreemptibleValue) {
+ addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
+ return;
+ } else if (RelType Rel = Target->getDynRel(Type)) {
+ InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1014,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- continue;
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ return;
}
+ }
- // The size is not going to change, so we fold it in here.
- if (Expr == R_SIZE)
- Addend += Sym.getSize();
+ // If the relocation is to a weak undef, and we are producing
+ // executable, give up on it and produce a non preemptible 0.
+ if (!Config->Shared && Sym.isUndefWeak()) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // 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 (IsConstant) {
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- continue;
+ if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
+ error(
+ "can't create dynamic relocation " + toString(Type) + " against " +
+ (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
+ " in readonly segment; recompile object files with -fPIC "
+ "or pass '-Wl,-z,notext' to allow text relocations in the output" +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // Copy relocations are only possible if we are creating an executable.
+ if (Config->Shared) {
+ errorOrWarn("relocation " + toString(Type) +
+ " cannot be used against symbol " + toString(Sym) +
+ "; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // If the symbol is undefined we already reported any relevant errors.
+ if (Sym.isUndefined())
+ return;
+
+ if (!canDefineSymbolInExecutable(Sym)) {
+ error("cannot preempt symbol: " + toString(Sym) +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ if (Sym.isObject()) {
+ // Produce a copy relocation.
+ if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
+ if (!Config->ZCopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*SS) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation(Sec, Sym, Offset));
+ addCopyRelSymbol<ELFT>(*SS);
}
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // 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 (Config->IsRela) {
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend});
- } else {
- // In REL, addends are stored to the target section.
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, 0});
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ if (Sym.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 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).
+
+ // For position independent executable on i386, the plt entry requires ebx
+ // to be set. This causes two problems:
+ // * If some code has a direct reference to a function, it was probably
+ // compiled without -fPIE/-fPIC and doesn't maintain ebx.
+ // * If a library definition gets preempted to the executable, it will have
+ // the wrong ebx value.
+ if (Config->Pie && Config->EMachine == EM_386)
+ errorOrWarn("symbol '" + toString(Sym) +
+ "' cannot be preempted; recompile with -fPIE" +
+ getLocation(Sec, Sym, Offset));
+ if (!Sym.isInPlt())
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ if (!Sym.isDefined())
+ replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
+ Sym.NeedsPltAddr = true;
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ errorOrWarn("symbol '" + toString(Sym) + "' has no type" +
+ getLocation(Sec, Sym, Offset));
+}
+
+template <class ELFT, class RelTy>
+static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
+ RelTy *End) {
+ const RelTy &Rel = *I;
+ Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelType Type;
+
+ // Deal with MIPS oddity.
+ if (Config->MipsN32Abi) {
+ Type = getMipsN32RelType(I, End);
+ } else {
+ Type = Rel.getType(Config->IsMips64EL);
+ ++I;
+ }
+
+ // Get an offset in an output section this relocation is applied to.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ return;
+
+ // Skip if the target symbol is an erroneous undefined symbol.
+ if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
+ return;
+
+ const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset;
+ RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ return;
+
+ // Strenghten or relax relocations.
+ //
+ // GNU ifunc symbols must be accessed via PLT because their addresses
+ // are determined by runtime.
+ //
+ // On the other hand, if we know that a PLT entry will be resolved within
+ // the same ELF module, we can skip PLT access and directly jump to the
+ // destination function. For example, if we are linking a main exectuable,
+ // all dynamic symbols that can be resolved within the executable will
+ // actually be resolved that way at runtime, because the main exectuable
+ // is always at the beginning of a search list. We can leverage that fact.
+ if (Sym.isGnuIFunc())
+ Expr = toPlt(Expr);
+ else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
+ else if (!Sym.IsPreemptible)
+ Expr = fromPlt(Expr);
+
+ // 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 (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+ InX::Got->HasGotOffRel = true;
+
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
+
+ // Process some TLS relocations, including relaxing TLS relocations.
+ // Note that this function does not handle all TLS relocations.
+ if (unsigned Processed =
+ handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) {
+ I += (Processed - 1);
+ return;
+ }
+
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Sym.isInPlt()) {
+ if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
+ addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
+ Target->IRelativeRel, Sym);
+ else
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ }
+
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // 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
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ } else if (!Sym.isInGot()) {
+ addGotEntry<ELFT>(Sym);
}
}
+
+ processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
+}
+
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
+
+ // Not all relocations end up in Sec.Relocations, but a lot do.
+ Sec.Relocations.reserve(Rels.size());
+
+ for (auto I = Rels.begin(), End = Rels.end(); I != End;)
+ scanReloc<ELFT>(Sec, GetOffset, I, End);
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
@@ -1259,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
//
// We follow a simple but conservative heuristic to place ThunkSections at
// offsets that are multiples of a Target specific branch range.
-// For an InputSectionRange that is smaller than the range, a single
+// For an InputSectionDescription that is smaller than the range, a single
// ThunkSection at the end of the range will do.
+//
+// For an InputSectionDescription that is more than twice the size of the range,
+// we place the last ThunkSection at range bytes from the end of the
+// InputSectionDescription in order to increase the likelihood that the
+// distance from a thunk to its target will be sufficiently small to
+// allow for the creation of a short thunk.
void ThunkCreator::createInitialThunkSections(
ArrayRef<OutputSection *> OutputSections) {
forEachInputSectionDescription(
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
if (ISD->Sections.empty())
return;
+ uint32_t ISDBegin = ISD->Sections.front()->OutSecOff;
+ uint32_t ISDEnd =
+ ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize();
+ uint32_t LastThunkLowerBound = -1;
+ if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing;
+
uint32_t ISLimit;
- uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff;
- uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ uint32_t PrevISLimit = ISDBegin;
+ uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;
for (const InputSection *IS : ISD->Sections) {
ISLimit = IS->OutSecOff + IS->getSize();
@@ -1277,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections(
addThunkSection(OS, ISD, PrevISLimit);
ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
}
+ if (ISLimit > LastThunkLowerBound)
+ break;
PrevISLimit = ISLimit;
}
addThunkSection(OS, ISD, ISLimit);
@@ -1293,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
uint64_t Src) {
- auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()});
- if (!Res.second) {
- // Check existing Thunks for Sym to see if they can be reused
- for (Thunk *ET : Res.first->second)
- if (ET->isCompatibleWith(Type) &&
- Target->inBranchRange(Type, Src, ET->ThunkSym->getVA()))
- return std::make_pair(ET, false);
- }
+ std::vector<Thunk *> *ThunkVec = nullptr;
+ // We use (section, offset) pair to find the thunk position if possible so
+ // that we create only one thunk for aliased symbols or ICFed sections.
+ if (auto *D = dyn_cast<Defined>(&Sym))
+ if (!D->isInPlt() && D->Section)
+ ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}];
+ if (!ThunkVec)
+ ThunkVec = &ThunkedSymbols[&Sym];
+ // Check existing Thunks for Sym to see if they can be reused
+ for (Thunk *ET : *ThunkVec)
+ if (ET->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA()))
+ return std::make_pair(ET, false);
// No existing compatible Thunk in range, create a new one
Thunk *T = addThunk(Type, Sym);
- Res.first->second.push_back(T);
+ ThunkVec->push_back(T);
return std::make_pair(T, true);
}
@@ -1311,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
// InputSectionDescription::Sections.
void ThunkCreator::forEachInputSectionDescription(
ArrayRef<OutputSection *> OutputSections,
- std::function<void(OutputSection *, InputSectionDescription *)> Fn) {
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
for (OutputSection *OS : OutputSections) {
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
continue;
@@ -1379,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
for (InputSection *IS : ISD->Sections)
for (Relocation &Rel : IS->Relocations) {
- uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset;
+ uint64_t Src = IS->getVA(Rel.Offset);
// If we are a relocation to an existing Thunk, check if it is
// still in range. If not then Rel will be altered to point to its
@@ -1394,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
bool IsNew;
std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
if (IsNew) {
- AddressesChanged = true;
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
if (auto *TIS = T->getTargetInputSection())
@@ -1402,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
else
TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
TS->addThunk(T);
- Thunks[T->ThunkSym] = T;
+ Thunks[T->getThunkTargetSym()] = T;
}
// Redirect relocation to Thunk, we never go via the PLT to a Thunk
- Rel.Sym = T->ThunkSym;
+ Rel.Sym = T->getThunkTargetSym();
Rel.Expr = fromPlt(Rel.Expr);
}
+ for (auto &P : ISD->ThunkSections)
+ AddressesChanged |= P.first->assignOffsets();
});
+ for (auto &P : ThunkedSections)
+ AddressesChanged |= P.second->assignOffsets();
+
// Merge all created synthetic ThunkSections back into OutputSection
mergeThunks(OutputSections);
++Pass;
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 2cc8adfa5985..a4125111c4fe 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -21,7 +21,7 @@ class Symbol;
class InputSection;
class InputSectionBase;
class OutputSection;
-class OutputSection;
+class SectionBase;
// Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL.
typedef uint32_t RelType;
@@ -32,6 +32,7 @@ typedef uint32_t RelType;
enum RelExpr {
R_INVALID,
R_ABS,
+ R_ADDEND,
R_ARM_SBREL,
R_GOT,
R_GOTONLY_PC,
@@ -58,27 +59,33 @@ enum RelExpr {
R_PLT,
R_PLT_PAGE_PC,
R_PLT_PC,
- R_PPC_OPD,
- R_PPC_PLT_OPD,
+ R_PPC_CALL,
+ R_PPC_CALL_PLT,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,
R_RELAX_TLS_GD_TO_IE_ABS,
R_RELAX_TLS_GD_TO_IE_END,
+ R_RELAX_TLS_GD_TO_IE_GOT_OFF,
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_RELAX_TLS_LD_TO_LE_ABS,
R_SIZE,
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
R_TLSDESC_PAGE,
- R_TLSGD,
+ R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
- R_TLSLD,
+ R_TLSLD_GOT,
+ R_TLSLD_GOT_FROM_END,
+ R_TLSLD_GOT_OFF,
+ R_TLSLD_HINT,
R_TLSLD_PC,
};
@@ -150,7 +157,7 @@ private:
void forEachInputSectionDescription(
ArrayRef<OutputSection *> OutputSections,
- std::function<void(OutputSection *, InputSectionDescription *)> Fn);
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn);
std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src);
@@ -160,6 +167,8 @@ private:
bool normalizeExistingThunk(Relocation &Rel, uint64_t Src);
// Record all the available Thunks for a Symbol
+ llvm::DenseMap<std::pair<SectionBase *, uint64_t>, std::vector<Thunk *>>
+ ThunkedSymbolsBySection;
llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols;
// Find a Thunk from the Thunks symbol definition, we can use this to find
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
index ef5a1cff7590..d4b1f6d99cc1 100644
--- a/ELF/ScriptLexer.cpp
+++ b/ELF/ScriptLexer.cpp
@@ -66,8 +66,6 @@ size_t ScriptLexer::getColumnNumber() {
std::string ScriptLexer::getCurrentLocation() {
std::string Filename = getCurrentMB().getBufferIdentifier();
- if (!Pos)
- return Filename;
return (Filename + ":" + Twine(getLineNumber())).str();
}
@@ -116,8 +114,9 @@ void ScriptLexer::tokenize(MemoryBufferRef MB) {
}
// ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>".
+ // "|", "||", "&" and "&&" are different operators.
if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") ||
- S.startswith(">=")) {
+ S.startswith(">=") || S.startswith("||") || S.startswith("&&")) {
Vec.push_back(S.substr(0, 2));
S = S.substr(2);
continue;
@@ -282,10 +281,7 @@ static bool encloses(StringRef S, StringRef T) {
MemoryBufferRef ScriptLexer::getCurrentMB() {
// Find input buffer containing the current token.
- assert(!MBs.empty());
- if (!Pos)
- return MBs[0];
-
+ assert(!MBs.empty() && Pos > 0);
for (MemoryBufferRef MB : MBs)
if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
return MB;
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 4263944981f2..ddb4a49a3e5e 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -63,6 +63,7 @@ private:
void readExtern();
void readGroup();
void readInclude();
+ void readInput();
void readMemory();
void readOutput();
void readOutputArch();
@@ -74,12 +75,14 @@ private:
void readVersion();
void readVersionScriptCommand();
- SymbolAssignment *readAssignment(StringRef Name);
+ SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
uint32_t readFill();
uint32_t parseFill(StringRef Tok);
void readSectionAddressType(OutputSection *Cmd);
+ OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef OutSec);
+ std::vector<BaseCommand *> readOverlay();
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription(StringRef Tok);
StringMatcher readFilePatterns();
@@ -88,16 +91,16 @@ private:
unsigned readPhdrType();
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
- SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ SymbolAssignment *readAssignment(StringRef Tok);
void readSort();
- AssertCommand *readAssert();
- Expr readAssertExpr();
+ Expr readAssert();
Expr readConstant();
Expr getPageSize();
uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
std::pair<uint32_t, uint32_t> readMemoryAttributes();
+ Expr combine(StringRef Op, Expr L, Expr R);
Expr readExpr();
Expr readExpr1(Expr Lhs, int MinPrec);
StringRef readParenLiteral();
@@ -157,17 +160,6 @@ static ExprValue sub(ExprValue A, ExprValue B) {
return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc};
}
-static ExprValue mul(ExprValue A, ExprValue B) {
- return A.getValue() * B.getValue();
-}
-
-static ExprValue div(ExprValue A, ExprValue B) {
- if (uint64_t BV = B.getValue())
- return A.getValue() / BV;
- error("division by zero");
- return 0;
-}
-
static ExprValue bitAnd(ExprValue A, ExprValue B) {
moveAbsRight(A, B);
return {A.Sec, A.ForceAbsolute,
@@ -237,16 +229,16 @@ void ScriptParser::readLinkerScript() {
if (Tok == ";")
continue;
- if (Tok == "ASSERT") {
- Script->SectionCommands.push_back(readAssert());
- } else if (Tok == "ENTRY") {
+ if (Tok == "ENTRY") {
readEntry();
} else if (Tok == "EXTERN") {
readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
+ } else if (Tok == "GROUP") {
readGroup();
} else if (Tok == "INCLUDE") {
readInclude();
+ } else if (Tok == "INPUT") {
+ readInput();
} else if (Tok == "MEMORY") {
readMemory();
} else if (Tok == "OUTPUT") {
@@ -265,7 +257,7 @@ void ScriptParser::readLinkerScript() {
readSections();
} else if (Tok == "VERSION") {
readVersion();
- } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
Script->SectionCommands.push_back(Cmd);
} else {
setError("unknown directive: " + Tok);
@@ -336,13 +328,12 @@ void ScriptParser::readExtern() {
}
void ScriptParser::readGroup() {
- expect("(");
- while (!errorCount() && !consume(")")) {
- if (consume("AS_NEEDED"))
- readAsNeeded();
- else
- addFile(unquote(next()));
- }
+ bool Orig = InputFile::IsInGroup;
+ InputFile::IsInGroup = true;
+ readInput();
+ InputFile::IsInGroup = Orig;
+ if (!Orig)
+ ++InputFile::NextGroupId;
}
void ScriptParser::readInclude() {
@@ -353,7 +344,7 @@ void ScriptParser::readInclude() {
return;
}
- if (Optional<std::string> Path = searchLinkerScript(Tok)) {
+ if (Optional<std::string> Path = searchScript(Tok)) {
if (Optional<MemoryBufferRef> MB = readFile(*Path))
tokenize(*MB);
return;
@@ -361,6 +352,16 @@ void ScriptParser::readInclude() {
setError("cannot find linker script " + Tok);
}
+void ScriptParser::readInput() {
+ expect("(");
+ while (!errorCount() && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
void ScriptParser::readOutput() {
// -o <file> takes predecence over OUTPUT(<file>).
expect("(");
@@ -437,6 +438,49 @@ void ScriptParser::readSearchDir() {
expect(")");
}
+// This reads an overlay description. Overlays are used to describe output
+// sections that use the same virtual memory range and normally would trigger
+// linker's sections sanity check failures.
+// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
+std::vector<BaseCommand *> ScriptParser::readOverlay() {
+ // VA and LMA expressions are optional, though for simplicity of
+ // implementation we assume they are not. That is what OVERLAY was designed
+ // for first of all: to allow sections with overlapping VAs at different LMAs.
+ Expr AddrExpr = readExpr();
+ expect(":");
+ expect("AT");
+ Expr LMAExpr = readParenExpr();
+ expect("{");
+
+ std::vector<BaseCommand *> V;
+ OutputSection *Prev = nullptr;
+ while (!errorCount() && !consume("}")) {
+ // VA is the same for all sections. The LMAs are consecutive in memory
+ // starting from the base load address specified.
+ OutputSection *OS = readOverlaySectionDescription();
+ OS->AddrExpr = AddrExpr;
+ if (Prev)
+ OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; };
+ else
+ OS->LMAExpr = LMAExpr;
+ V.push_back(OS);
+ Prev = OS;
+ }
+
+ // According to the specification, at the end of the overlay, the location
+ // counter should be equal to the overlay base address plus size of the
+ // largest section seen in the overlay.
+ // Here we want to create the Dot assignment command to achieve that.
+ Expr MoveDot = [=] {
+ uint64_t Max = 0;
+ for (BaseCommand *Cmd : V)
+ Max = std::max(Max, cast<OutputSection>(Cmd)->Size);
+ return AddrExpr().getValue() + Max;
+ };
+ V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation()));
+ return V;
+}
+
void ScriptParser::readSections() {
Script->HasSectionsCommand = true;
@@ -446,26 +490,48 @@ void ScriptParser::readSections() {
Config->SingleRoRx = true;
expect("{");
+ std::vector<BaseCommand *> V;
while (!errorCount() && !consume("}")) {
StringRef Tok = next();
- BaseCommand *Cmd = readProvideOrAssignment(Tok);
- if (!Cmd) {
- if (Tok == "ASSERT")
- Cmd = readAssert();
- else
- Cmd = readOutputSectionDescription(Tok);
+ if (Tok == "OVERLAY") {
+ for (BaseCommand *Cmd : readOverlay())
+ V.push_back(Cmd);
+ continue;
}
- Script->SectionCommands.push_back(Cmd);
+
+ if (BaseCommand *Cmd = readAssignment(Tok))
+ V.push_back(Cmd);
+ else
+ V.push_back(readOutputSectionDescription(Tok));
+ }
+
+ if (!atEOF() && consume("INSERT")) {
+ std::vector<BaseCommand *> *Dest = nullptr;
+ if (consume("AFTER"))
+ Dest = &Script->InsertAfterCommands[next()];
+ else if (consume("BEFORE"))
+ Dest = &Script->InsertBeforeCommands[next()];
+ else
+ setError("expected AFTER/BEFORE, but got '" + next() + "'");
+ if (Dest)
+ Dest->insert(Dest->end(), V.begin(), V.end());
+ return;
}
+
+ Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(),
+ V.end());
}
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
- .Cases("*", "/", 5)
- .Cases("+", "-", 4)
- .Cases("<<", ">>", 3)
- .Cases("<", "<=", ">", ">=", "==", "!=", 2)
- .Cases("&", "|", 1)
+ .Cases("*", "/", "%", 8)
+ .Cases("+", "-", 7)
+ .Cases("<<", ">>", 6)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 5)
+ .Case("&", 4)
+ .Case("|", 3)
+ .Case("&&", 2)
+ .Case("||", 1)
.Default(-1);
}
@@ -588,11 +654,7 @@ void ScriptParser::readSort() {
expect(")");
}
-AssertCommand *ScriptParser::readAssert() {
- return make<AssertCommand>(readAssertExpr());
-}
-
-Expr ScriptParser::readAssertExpr() {
+Expr ScriptParser::readAssert() {
expect("(");
Expr E = readExpr();
expect(",");
@@ -617,12 +679,14 @@ uint32_t ScriptParser::readFill() {
return V;
}
-// Reads an expression and/or the special directive "(NOLOAD)" for an
-// output section definition.
+// Reads an expression and/or the special directive for an output
+// section definition. Directive is one of following: "(NOLOAD)",
+// "(COPY)", "(INFO)" or "(OVERLAY)".
//
// An output section name can be followed by an address expression
-// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
-// interpreted as either the beginning of some expression or "(NOLOAD)".
+// and/or directive. This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or beginning
+// of directive.
//
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
@@ -633,6 +697,11 @@ void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
Cmd->Noload = true;
return;
}
+ if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
+ expect(")");
+ Cmd->NonAlloc = true;
+ return;
+ }
Cmd->AddrExpr = readExpr();
expect(")");
} else {
@@ -657,10 +726,23 @@ static Expr checkAlignment(Expr E, std::string &Loc) {
};
}
+OutputSection *ScriptParser::readOverlaySectionDescription() {
+ OutputSection *Cmd =
+ Script->createOutputSection(next(), getCurrentLocation());
+ Cmd->InOverlay = true;
+ expect("{");
+ while (!errorCount() && !consume("}"))
+ Cmd->SectionCommands.push_back(readInputSectionRules(next()));
+ Cmd->Phdrs = readOutputSectionPhdrs();
+ return Cmd;
+}
+
OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSection *Cmd =
Script->createOutputSection(OutSec, getCurrentLocation());
+ size_t SymbolsReferenced = Script->ReferencedSymbols.size();
+
if (peek() != ":")
readSectionAddressType(Cmd);
expect(":");
@@ -684,13 +766,10 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
StringRef Tok = next();
if (Tok == ";") {
// Empty commands are allowed. Do nothing here.
- } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Assign = readAssignment(Tok)) {
Cmd->SectionCommands.push_back(Assign);
} else if (ByteCommand *Data = readByteCommand(Tok)) {
Cmd->SectionCommands.push_back(Data);
- } else if (Tok == "ASSERT") {
- Cmd->SectionCommands.push_back(readAssert());
- expect(";");
} else if (Tok == "CONSTRUCTORS") {
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
// by name. This is for very old file formats such as ECOFF/XCOFF.
@@ -709,6 +788,14 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
if (consume(">"))
Cmd->MemoryRegionName = next();
+ if (consume("AT")) {
+ expect(">");
+ Cmd->LMARegionName = next();
+ }
+
+ if (Cmd->LMAExpr && !Cmd->LMARegionName.empty())
+ error("section can't have both LMA and a load region");
+
Cmd->Phdrs = readOutputSectionPhdrs();
if (consume("="))
@@ -719,6 +806,8 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// Consume optional comma following output section command.
consume(",");
+ if (Script->ReferencedSymbols.size() > SymbolsReferenced)
+ Cmd->ExpressionsUseSymbols = true;
return Cmd;
}
@@ -741,30 +830,39 @@ uint32_t ScriptParser::parseFill(StringRef Tok) {
SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
expect("(");
- SymbolAssignment *Cmd = readAssignment(next());
+ SymbolAssignment *Cmd = readSymbolAssignment(next());
Cmd->Provide = Provide;
Cmd->Hidden = Hidden;
expect(")");
- expect(";");
return Cmd;
}
-SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) {
+ // Assert expression returns Dot, so this is equal to ".=."
+ if (Tok == "ASSERT")
+ return make<SymbolAssignment>(".", readAssert(), getCurrentLocation());
+
+ size_t OldPos = Pos;
SymbolAssignment *Cmd = nullptr;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
+ if (peek() == "=" || peek() == "+=")
+ Cmd = readSymbolAssignment(Tok);
+ else if (Tok == "PROVIDE")
Cmd = readProvideHidden(true, false);
- } else if (Tok == "HIDDEN") {
+ else if (Tok == "HIDDEN")
Cmd = readProvideHidden(false, true);
- } else if (Tok == "PROVIDE_HIDDEN") {
+ else if (Tok == "PROVIDE_HIDDEN")
Cmd = readProvideHidden(true, true);
+
+ if (Cmd) {
+ Cmd->CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ expect(";");
}
return Cmd;
}
-SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
StringRef Op = next();
assert(Op == "=" || Op == "+=");
Expr E = readExpr();
@@ -787,15 +885,31 @@ Expr ScriptParser::readExpr() {
return E;
}
-static Expr combine(StringRef Op, Expr L, Expr R) {
+Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) {
if (Op == "+")
return [=] { return add(L(), R()); };
if (Op == "-")
return [=] { return sub(L(), R()); };
if (Op == "*")
- return [=] { return mul(L(), R()); };
- if (Op == "/")
- return [=] { return div(L(), R()); };
+ return [=] { return L().getValue() * R().getValue(); };
+ if (Op == "/") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() / RV;
+ error(Loc + ": division by zero");
+ return 0;
+ };
+ }
+ if (Op == "%") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() % RV;
+ error(Loc + ": modulo by zero");
+ return 0;
+ };
+ }
if (Op == "<<")
return [=] { return L().getValue() << R().getValue(); };
if (Op == ">>")
@@ -812,6 +926,10 @@ static Expr combine(StringRef Op, Expr L, Expr R) {
return [=] { return L().getValue() == R().getValue(); };
if (Op == "!=")
return [=] { return L().getValue() != R().getValue(); };
+ if (Op == "||")
+ return [=] { return L().getValue() || R().getValue(); };
+ if (Op == "&&")
+ return [=] { return L().getValue() && R().getValue(); };
if (Op == "&")
return [=] { return bitAnd(L(), R()); };
if (Op == "|")
@@ -865,20 +983,13 @@ Expr ScriptParser::readConstant() {
if (S == "MAXPAGESIZE")
return [] { return Config->MaxPageSize; };
setError("unknown constant: " + S);
- return {};
+ return [] { return 0; };
}
// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
// have "K" (Ki) or "M" (Mi) suffixes.
static Optional<uint64_t> parseInt(StringRef Tok) {
- // Negative number
- if (Tok.startswith("-")) {
- if (Optional<uint64_t> Val = parseInt(Tok.substr(1)))
- return -*Val;
- return None;
- }
-
// Hexadecimal
uint64_t Val;
if (Tok.startswith_lower("0x")) {
@@ -917,12 +1028,21 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) {
.Default(-1);
if (Size == -1)
return nullptr;
- return make<ByteCommand>(readParenExpr(), Size);
+
+ size_t OldPos = Pos;
+ Expr E = readParenExpr();
+ std::string CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ return make<ByteCommand>(E, Size, CommandString);
}
StringRef ScriptParser::readParenLiteral() {
expect("(");
+ bool Orig = InExpr;
+ InExpr = false;
StringRef Tok = next();
+ InExpr = Orig;
expect(")");
return Tok;
}
@@ -995,7 +1115,7 @@ Expr ScriptParser::readPrimary() {
};
}
if (Tok == "ASSERT")
- return readAssertExpr();
+ return readAssert();
if (Tok == "CONSTANT")
return readConstant();
if (Tok == "DATA_SEGMENT_ALIGN") {
@@ -1032,8 +1152,10 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "LENGTH") {
StringRef Name = readParenLiteral();
- if (Script->MemoryRegions.count(Name) == 0)
+ if (Script->MemoryRegions.count(Name) == 0) {
setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
return [=] { return Script->MemoryRegions[Name]->Length; };
}
if (Tok == "LOADADDR") {
@@ -1044,10 +1166,22 @@ Expr ScriptParser::readPrimary() {
return Cmd->getLMA();
};
}
+ if (Tok == "MAX" || Tok == "MIN") {
+ expect("(");
+ Expr A = readExpr();
+ expect(",");
+ Expr B = readExpr();
+ expect(")");
+ if (Tok == "MIN")
+ return [=] { return std::min(A().getValue(), B().getValue()); };
+ return [=] { return std::max(A().getValue(), B().getValue()); };
+ }
if (Tok == "ORIGIN") {
StringRef Name = readParenLiteral();
- if (Script->MemoryRegions.count(Name) == 0)
+ if (Script->MemoryRegions.count(Name) == 0) {
setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
return [=] { return Script->MemoryRegions[Name]->Origin; };
}
if (Tok == "SEGMENT_START") {
@@ -1229,6 +1363,9 @@ ScriptParser::readSymbols() {
// Reads an "extern C++" directive, e.g.,
// "extern "C++" { ns::*; "f(int, double)"; };"
+//
+// The last semicolon is optional. E.g. this is OK:
+// "extern "C++" { ns::*; "f(int, double)" };"
std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
StringRef Tok = next();
bool IsCXX = Tok == "\"C++\"";
@@ -1241,6 +1378,8 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
StringRef Tok = next();
bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+ if (consume("}"))
+ return Ret;
expect(";");
}
@@ -1280,11 +1419,10 @@ void ScriptParser::readMemory() {
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- if (Script->MemoryRegions.count(Name))
+ MemoryRegion *MR =
+ make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags);
+ if (!Script->MemoryRegions.insert({Name, MR}).second)
setError("region '" + Name + "' already defined");
- MemoryRegion *MR = make<MemoryRegion>();
- *MR = {Name, Origin, Length, Flags, NegFlags};
- Script->MemoryRegions[Name] = MR;
}
}
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
deleted file mode 100644
index 0ef33a14bc3d..000000000000
--- a/ELF/Strings.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- 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 "Config.h"
-#include "lld/Common/ErrorHandler.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Demangle/Demangle.h"
-#include <algorithm>
-#include <cstring>
-
-using namespace llvm;
-using namespace lld;
-using namespace lld::elf;
-
-StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
- for (StringRef S : Pat) {
- Expected<GlobPattern> Pat = GlobPattern::create(S);
- if (!Pat)
- error(toString(Pat.takeError()));
- else
- Patterns.push_back(*Pat);
- }
-}
-
-bool StringMatcher::match(StringRef S) const {
- for (const GlobPattern &Pat : Patterns)
- if (Pat.match(S))
- return true;
- return false;
-}
-
-// 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 (!to_integer(B, H, 16)) {
- error("not a hexadecimal value: " + B);
- return {};
- }
- Hex.push_back(H);
- }
- return Hex;
-}
-
-// Returns true if S is valid as a C language identifier.
-bool elf::isValidCIdentifier(StringRef S) {
- return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
- std::all_of(S.begin() + 1, S.end(),
- [](char C) { return C == '_' || isAlnum(C); });
-}
diff --git a/ELF/Strings.h b/ELF/Strings.h
deleted file mode 100644
index 5009df65f4c1..000000000000
--- a/ELF/Strings.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//===- 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_ELF_STRINGS_H
-#define LLD_ELF_STRINGS_H
-
-#include "lld/Common/LLVM.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/GlobPattern.h"
-#include <vector>
-
-namespace lld {
-namespace elf {
-
-std::vector<uint8_t> parseHex(StringRef S);
-bool isValidCIdentifier(StringRef S);
-
-// This is a lazy version of StringRef. String size is computed lazily
-// when it is needed. It is more efficient than StringRef to instantiate
-// if you have a string whose size is unknown.
-//
-// ELF string tables contain a lot of null-terminated strings.
-// Most of them are not necessary for the linker because they are names
-// of local symbols and the linker doesn't use local symbol names for
-// name resolution. So, we use this class to represents strings read
-// from string tables.
-class StringRefZ {
-public:
- StringRefZ() : Start(nullptr), Size(0) {}
- StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {}
-
- /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {}
-
- /*implicit*/ StringRefZ(llvm::StringRef S)
- : Start(S.data()), Size(S.size()) {}
-
- operator llvm::StringRef() const {
- if (Size == (size_t)-1)
- Size = strlen(Start);
- return {Start, Size};
- }
-
-private:
- const char *Start;
- mutable size_t Size;
-};
-
-// This class represents multiple glob patterns.
-class StringMatcher {
-public:
- StringMatcher() = default;
- explicit StringMatcher(ArrayRef<StringRef> Pat);
-
- bool match(StringRef S) const;
-
-private:
- std::vector<llvm::GlobPattern> Patterns;
-};
-
-inline ArrayRef<uint8_t> toArrayRef(StringRef S) {
- return {(const uint8_t *)S.data(), S.size()};
-}
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index b6bf21998863..1f5a84ec2c7d 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -38,7 +38,7 @@ static InputFile *getFirstElf() {
return ObjectFiles[0];
if (!SharedFiles.empty())
return SharedFiles[0];
- return nullptr;
+ return BitcodeFiles[0];
}
// All input object files must be for the same architecture
@@ -82,6 +82,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// Lazy object file
if (auto *F = dyn_cast<LazyObjFile>(File)) {
+ LazyObjFiles.push_back(F);
F->parse<ELFT>();
return;
}
@@ -117,7 +118,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// 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
+// Because all bitcode files that the program consists of are passed
// to the compiler at once, it can do whole-program optimization.
template <class ELFT> void SymbolTable::addCombinedLTOObject() {
if (BitcodeFiles.empty())
@@ -130,7 +131,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() {
for (InputFile *File : LTO->compile()) {
DenseSet<CachedHashStringRef> DummyGroups;
- cast<ObjFile<ELFT>>(File)->parse(DummyGroups);
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+ Obj->parse(DummyGroups);
+ for (Symbol *Sym : Obj->getGlobalSymbols())
+ Sym->parseSymbolVersion();
ObjectFiles.push_back(File);
}
}
@@ -154,6 +158,12 @@ template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
Symbol *Sym = find(Name);
if (!Sym)
return;
+
+ // Do not wrap the same symbol twice.
+ for (const WrappedSymbol &S : WrappedSymbols)
+ if (S.Sym == Sym)
+ return;
+
Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
WrappedSymbols.push_back({Sym, Real, Wrap});
@@ -186,7 +196,7 @@ void SymbolTable::applySymbolWrap() {
// First, make a copy of __real_sym.
Symbol *Real = nullptr;
if (W.Real->isDefined()) {
- Real = (Symbol *)make<SymbolUnion>();
+ Real = reinterpret_cast<Symbol *>(make<SymbolUnion>());
memcpy(Real, W.Real, sizeof(SymbolUnion));
}
@@ -234,8 +244,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
- Sym = (Symbol *)make<SymbolUnion>();
- Sym->InVersionScript = false;
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->Visibility = STV_DEFAULT;
Sym->IsUsedInRegularObj = false;
Sym->ExportDynamic = false;
@@ -294,26 +303,88 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
return S;
}
+
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (Binding != STB_WEAK) {
+
+ if (!Config->GcSections && Binding != STB_WEAK)
if (auto *SS = dyn_cast<SharedSymbol>(S))
- if (!Config->GcSections)
- SS->getFile<ELFT>().IsNeeded = true;
- }
- if (auto *L = dyn_cast<Lazy>(S)) {
+ SS->getFile<ELFT>().IsNeeded = true;
+
+ if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
- if (Binding == STB_WEAK)
- L->Type = Type;
- else if (InputFile *F = L->fetch())
- addFile<ELFT>(F);
+ if (Binding == STB_WEAK) {
+ S->Type = Type;
+ return S;
+ }
+
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
+ fetchLazy<ELFT>(S);
+
+ // We don't report backward references to weak symbols as they can be
+ // overridden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
}
return S;
}
@@ -381,7 +452,11 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
+
int Cmp = compareDefined(S, WasInserted, Binding, N);
+ if (Cmp < 0)
+ return S;
+
if (Cmp > 0) {
auto *Bss = make<BssSection>("COMMON", Size, Alignment);
Bss->File = &File;
@@ -389,45 +464,43 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputSections.push_back(Bss);
replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
- } else if (Cmp == 0) {
- auto *D = cast<Defined>(S);
- auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
- if (!Bss) {
- // Non-common symbols take precedence over common symbols.
- if (Config->WarnCommon)
- warn("common " + S->getName() + " is overridden");
- return S;
- }
+ return S;
+ }
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
+ // Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("multiple common of " + D->getName());
+ warn("common " + S->getName() + " is overridden");
+ return S;
+ }
- Bss->Alignment = std::max(Bss->Alignment, Alignment);
- if (Size > Bss->Size) {
- D->File = Bss->File = &File;
- D->Size = Bss->Size = Size;
- }
+ if (Config->WarnCommon)
+ warn("multiple common of " + D->getName());
+
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
}
return S;
}
-static void warnOrError(const Twine &Msg) {
- if (Config->AllowMultipleDefinition)
- warn(Msg);
- else
- error(Msg);
-}
-
static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
- warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
- toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
+ if (!Config->AllowMultipleDefinition)
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
-static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
- uint64_t ErrOffset) {
+static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
+ InputSectionBase *ErrSec, uint64_t ErrOffset) {
+ if (Config->AllowMultipleDefinition)
+ return;
+
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr);
+ reportDuplicate(Sym, NewFile);
return;
}
@@ -451,7 +524,7 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
if (!Src2.empty())
Msg += Src2 + "\n>>> ";
Msg += Obj2;
- warnOrError(Msg);
+ error(Msg);
}
Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
@@ -467,7 +540,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size,
Section);
else if (Cmp == 0)
- reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value);
+ reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
+ Value);
return S;
}
@@ -488,15 +562,16 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted || ((S->isUndefined() || S->isLazy()) &&
- S->getVisibility() == STV_DEFAULT)) {
+ if (WasInserted ||
+ ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) {
uint8_t Binding = S->Binding;
+ bool WasUndefined = S->isUndefined();
replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
Sym.getType(), Sym.st_value, Sym.st_size,
Alignment, VerdefIndex);
if (!WasInserted) {
S->Binding = Binding;
- if (!S->isWeak() && !Config->GcSections)
+ if (!S->isWeak() && !Config->GcSections && WasUndefined)
File.IsNeeded = true;
}
}
@@ -527,85 +602,58 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-template <class ELFT>
-Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
+// This is used to handle lazy symbols. May replace existent
+// symbol with lazy version or request to Fetch it.
+template <class ELFT, typename LazyT, typename... ArgT>
+static void replaceOrFetchLazy(StringRef Name, InputFile &File,
+ llvm::function_ref<InputFile *()> Fetch,
+ ArgT &&... Arg) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = Symtab->insert(Name);
if (WasInserted) {
- replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType);
- return S;
+ replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
+ std::forward<ArgT>(Arg)...);
+ return;
}
if (!S->isUndefined())
- return S;
+ return;
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyArchive>(S, F, Sym, S->Type);
+ replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
S->Binding = STB_WEAK;
- return S;
+ return;
}
- std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym);
- if (!MBInfo.first.getBuffer().empty())
- addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second));
- return S;
+
+ if (InputFile *F = Fetch())
+ Symtab->addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType);
- return;
- }
- if (!S->isUndefined())
- return;
-
- // See comment for addLazyArchive above.
- if (S->isWeak())
- replaceSymbol<LazyObject>(S, Obj, Name, S->Type);
- else if (InputFile *F = Obj.fetch())
- addFile<ELFT>(F);
-}
-
-// If we already saw this symbol, force loading its file.
-template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) {
- if (Symbol *B = find(Name)) {
- // Mark the symbol not to be eliminated by LTO
- // even if it is a bitcode symbol.
- B->IsUsedInRegularObj = true;
- if (auto *L = dyn_cast<Lazy>(B))
- if (InputFile *File = L->fetch())
- addFile<ELFT>(File);
- }
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
+ const object::Archive::Symbol Sym) {
+ replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
+ Sym);
}
-// 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::scanShlibUndefined() {
- for (InputFile *F : SharedFiles) {
- for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) {
- Symbol *Sym = find(U);
- if (!Sym || !Sym->isDefined())
- continue;
- Sym->ExportDynamic = true;
+template <class ELFT>
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
+ replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
+ Name);
+}
- // If -dynamic-list is given, the default version is set to
- // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
- // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
- // specified by -dynamic-list.
- Sym->VersionId = VER_NDX_GLOBAL;
- }
+template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
+ if (auto *S = dyn_cast<LazyArchive>(Sym)) {
+ if (InputFile *File = S->fetch())
+ addFile<ELFT>(File);
+ return;
}
+
+ auto *S = cast<LazyObject>(Sym);
+ if (InputFile *File = cast<LazyObjFile>(S->File)->fetch())
+ addFile<ELFT>(File);
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -704,7 +752,7 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
// Get a list of symbols which we need to assign the version to.
std::vector<Symbol *> Syms = findByVersion(Ver);
if (Syms.empty()) {
- if (Config->NoUndefinedVersion)
+ if (!Config->UndefinedVersion)
error("version script assignment of '" + VersionName + "' to symbol '" +
Ver.Name + "' failed: symbol not defined");
return;
@@ -718,10 +766,10 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
if (Sym->getName().contains('@'))
continue;
- if (Sym->InVersionScript)
- warn("duplicate symbol '" + Ver.Name + "' in version script");
+ if (Sym->VersionId != Config->DefaultSymbolVersion &&
+ Sym->VersionId != VersionId)
+ error("duplicate symbol '" + Ver.Name + "' in version script");
Sym->VersionId = VersionId;
- Sym->InVersionScript = true;
}
}
@@ -769,6 +817,11 @@ void SymbolTable::scanVersionScript() {
Sym->parseSymbolVersion();
}
+template void SymbolTable::addFile<ELF32LE>(InputFile *);
+template void SymbolTable::addFile<ELF32BE>(InputFile *);
+template void SymbolTable::addFile<ELF64LE>(InputFile *);
+template void SymbolTable::addFile<ELF64BE>(InputFile *);
+
template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
@@ -793,16 +846,16 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>();
template void SymbolTable::addCombinedLTOObject<ELF64LE>();
template void SymbolTable::addCombinedLTOObject<ELF64BE>();
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
@@ -811,6 +864,11 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+template void SymbolTable::fetchLazy<ELF32LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
+
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
const typename ELF32LE::Sym &,
uint32_t Alignment, uint32_t);
@@ -823,13 +881,3 @@ template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
const typename ELF64BE::Sym &,
uint32_t Alignment, uint32_t);
-
-template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef);
-
-template void SymbolTable::scanShlibUndefined<ELF32LE>();
-template void SymbolTable::scanShlibUndefined<ELF32BE>();
-template void SymbolTable::scanShlibUndefined<ELF64LE>();
-template void SymbolTable::scanShlibUndefined<ELF64BE>();
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index e7341b05baf5..5e6d44dfe4f9 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -12,7 +12,7 @@
#include "InputFiles.h"
#include "LTO.h"
-#include "Strings.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
@@ -60,8 +60,8 @@ public:
uint32_t VerdefIndex);
template <class ELFT>
- Symbol *addLazyArchive(StringRef Name, ArchiveFile &F,
- const llvm::object::Archive::Symbol S);
+ void addLazyArchive(StringRef Name, ArchiveFile &F,
+ const llvm::object::Archive::Symbol S);
template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj);
@@ -77,8 +77,8 @@ public:
uint8_t Visibility, bool CanOmitFromDynSym,
InputFile *File);
- template <class ELFT> void fetchIfLazy(StringRef Name);
- template <class ELFT> void scanShlibUndefined();
+ template <class ELFT> void fetchLazy(Symbol *Sym);
+
void scanVersionScript();
Symbol *find(StringRef Name);
@@ -90,7 +90,6 @@ public:
private:
std::vector<Symbol *> findByVersion(SymbolVersion Ver);
std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
- void defsym(Symbol *Dst, Symbol *Src);
llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms();
void handleAnonymousVersion();
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 13a91aab80bb..4243cb1e80ef 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -14,7 +14,6 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
-
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
@@ -39,6 +38,7 @@ Defined *ElfSym::GlobalOffsetTable;
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
switch (Sym.kind()) {
@@ -58,6 +58,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
return D.Value;
IS = IS->Repl;
+
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
@@ -76,8 +77,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
Addend = 0;
}
- const OutputSection *OutSec = IS->getOutputSection();
-
// In the typical case, this is actually very simple and boils
// down to adding together 3 numbers:
// 1. The address of the output section.
@@ -88,7 +87,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
// If you understand the data structures involved with this next
// line (and how they get built), then you have a pretty good
// understanding of the linker.
- uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
+ uint64_t VA = IS->getVA(Offset);
if (D.isTls() && !Config->Relocatable) {
if (!Out::TlsPhdr)
@@ -98,20 +97,12 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
}
return VA;
}
- case Symbol::SharedKind: {
- auto &SS = cast<SharedSymbol>(Sym);
- if (SS.CopyRelSec)
- return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff;
- if (SS.NeedsPltAddr)
- return Sym.getPltVA();
- return 0;
- }
+ case Symbol::SharedKind:
case Symbol::UndefinedKind:
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
- return 0;
+ llvm_unreachable("lazy symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -134,22 +125,26 @@ uint64_t Symbol::getGotPltVA() const {
}
uint64_t Symbol::getGotPltOffset() const {
- return GotPltIndex * Target->GotPltEntrySize;
+ if (IsInIgot)
+ return PltIndex * Target->GotPltEntrySize;
+ return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
uint64_t Symbol::getPltVA() const {
if (this->IsInIplt)
return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return InX::Plt->getVA() + Target->PltHeaderSize +
- PltIndex * Target->PltEntrySize;
+ return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
+}
+
+uint64_t Symbol::getPltOffset() const {
+ assert(!this->IsInIplt);
+ return Target->getPltEntryOffset(PltIndex);
}
uint64_t Symbol::getSize() const {
if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size;
- if (const auto *S = dyn_cast<SharedSymbol>(this))
- return S->Size;
- return 0;
+ return cast<SharedSymbol>(this)->Size;
}
OutputSection *Symbol::getOutputSection() const {
@@ -158,13 +153,6 @@ OutputSection *Symbol::getOutputSection() const {
return Sec->Repl->getOutputSection();
return nullptr;
}
-
- if (auto *S = dyn_cast<SharedSymbol>(this)) {
- if (S->CopyRelSec)
- return S->CopyRelSec->getParent();
- return nullptr;
- }
-
return nullptr;
}
@@ -180,7 +168,7 @@ void Symbol::parseSymbolVersion() {
return;
// Truncate the symbol name so that it doesn't include the version string.
- Name = {S.data(), Pos};
+ NameSize = Pos;
// If this is not in this DSO, it is not a definition.
if (!isDefined())
@@ -206,33 +194,15 @@ void Symbol::parseSymbolVersion() {
// It is an error if the specified version is not defined.
// Usually version script is not provided when linking executable,
// but we may still want to override a versioned symbol from DSO,
- // so we do not report error in this case.
- if (Config->Shared)
+ // so we do not report error in this case. We also do not error
+ // if the symbol has a local version as it won't be in the dynamic
+ // symbol table.
+ if (Config->Shared && VersionId != VER_NDX_LOCAL)
error(toString(File) + ": symbol " + S + " has undefined version " +
Verstr);
}
-InputFile *Lazy::fetch() {
- if (auto *S = dyn_cast<LazyArchive>(this))
- return S->fetch();
- return cast<LazyObject>(this)->fetch();
-}
-
-ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); }
-
-InputFile *LazyArchive::fetch() {
- std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym);
-
- // getMember returns an empty buffer if the member was already
- // read from the library.
- if (MBInfo.first.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second);
-}
-
-LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); }
-
-InputFile *LazyObject::fetch() { return getFile().fetch(); }
+InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
@@ -241,7 +211,7 @@ uint8_t Symbol::computeBinding() const {
return STB_LOCAL;
if (VersionId == VER_NDX_LOCAL && isDefined())
return STB_LOCAL;
- if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
+ if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
return Binding;
}
@@ -273,6 +243,27 @@ void elf::printTraceSymbol(Symbol *Sym) {
message(toString(Sym->File) + S + Sym->getName());
}
+void elf::warnUnorderableSymbol(const Symbol *Sym) {
+ if (!Config->WarnSymbolOrdering)
+ return;
+
+ const InputFile *File = Sym->File;
+ auto *D = dyn_cast<Defined>(Sym);
+
+ auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); };
+
+ if (Sym->isUndefined())
+ Warn(": unable to order undefined symbol: ");
+ else if (Sym->isShared())
+ Warn(": unable to order shared symbol: ");
+ else if (D && !D->Section)
+ Warn(": unable to order absolute symbol: ");
+ else if (D && isa<OutputSection>(D->Section))
+ Warn(": unable to order synthetic symbol: ");
+ else if (D && !D->Section->Repl->Live)
+ Warn(": unable to order discarded symbol: ");
+}
+
// Returns a symbol for an error message.
std::string lld::toString(const Symbol &B) {
if (Config->Demangle)
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 9b7207383345..8c9513b9368b 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -7,8 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// All symbols are handled as SymbolBodies regardless of their types.
-// This file defines various types of SymbolBodies.
+// This file defines various types of Symbols.
//
//===----------------------------------------------------------------------===//
@@ -16,9 +15,8 @@
#define LLD_ELF_SYMBOLS_H
#include "InputSection.h"
-#include "Strings.h"
-
#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
@@ -34,6 +32,20 @@ template <class ELFT> class ObjFile;
class OutputSection;
template <class ELFT> class SharedFile;
+// This is a StringRef-like container that doesn't run strlen().
+//
+// ELF string tables contain a lot of null-terminated strings. Most of them
+// are not necessary for the linker because they are names of local symbols,
+// and the linker doesn't use local symbol names for name resolution. So, we
+// use this class to represents strings read from string tables.
+struct StringRefZ {
+ StringRefZ(const char *S) : Data(S), Size(-1) {}
+ StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+
+ const char *Data;
+ const uint32_t Size;
+};
+
// The base class for real symbol classes.
class Symbol {
public:
@@ -47,6 +59,25 @@ public:
Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ // The file from which this symbol was created.
+ InputFile *File;
+
+protected:
+ const char *NameData;
+ mutable uint32_t NameSize;
+
+public:
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t PltIndex = -1;
+ uint32_t GlobalDynIndex = -1;
+
+ // This field is a index to the symbol's version definition.
+ uint32_t VerdefIndex = -1;
+
+ // Version definition index.
+ uint16_t VersionId;
+
// Symbol binding. This is not overwritten by replaceSymbol to track
// changes during resolution. In particular:
// - An undefined weak is still weak when it resolves to a shared library.
@@ -54,8 +85,11 @@ public:
// remember it is weak.
uint8_t Binding;
- // Version definition index.
- uint16_t VersionId;
+ // The following fields have the same meaning as the ELF symbol attributes.
+ uint8_t Type; // symbol type
+ uint8_t StOther; // st_other field value
+
+ const uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -81,12 +115,6 @@ public:
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
- // This symbol version was found in a version script.
- unsigned InVersionScript : 1;
-
- // The file from which this symbol was created.
- InputFile *File;
-
bool includeInDynsym() const;
uint8_t computeBinding() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
@@ -100,15 +128,15 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True is this is an undefined weak symbol. This only works once
- // all input files have been added.
- bool isUndefWeak() const {
- // See comment on Lazy the details.
- return isWeak() && (isUndefined() || isLazy());
+ // True if this is an undefined weak symbol.
+ bool isUndefWeak() const { return isWeak() && isUndefined(); }
+
+ StringRef getName() const {
+ if (NameSize == (uint32_t)-1)
+ NameSize = strlen(NameData);
+ return {NameData, NameSize};
}
- StringRef getName() const { return Name; }
- uint8_t getVisibility() const { return StOther & 0x3; }
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
@@ -121,34 +149,22 @@ public:
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
+ uint64_t getPltOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
- uint32_t DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t GotPltIndex = -1;
- uint32_t PltIndex = -1;
- uint32_t GlobalDynIndex = -1;
-
protected:
Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
uint8_t StOther, uint8_t Type)
- : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false),
- IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
- Type(Type), StOther(StOther), Name(Name) {}
-
- const unsigned SymbolKind : 8;
+ : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
+ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
+ IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ Used(!Config->GcSections), NeedsTocRestore(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
- // True if this symbol has an entry in the global part of MIPS GOT.
- unsigned IsInGlobalMipsGot : 1;
-
- // True if this symbol is referenced by 32-bit GOT relocations.
- unsigned Is32BitMipsGot : 1;
// True if this symbol is in the Iplt sub-section of the Plt.
unsigned IsInIplt : 1;
@@ -156,14 +172,15 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
+ // True if this symbol is preemptible at load time.
unsigned IsPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
unsigned Used : 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
+ // True if a call to this symbol needs to be followed by a restore of the
+ // PPC64 toc pointer.
+ unsigned NeedsTocRestore : 1;
// 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
@@ -178,9 +195,6 @@ public:
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:
- StringRefZ Name;
};
// Represents a symbol that is defined in the current output file.
@@ -214,8 +228,9 @@ public:
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value),
- Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) {
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
+ Alignment(Alignment), Value(Value), Size(Size) {
+ this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
@@ -240,54 +255,36 @@ public:
return *cast<SharedFile<ELFT>>(File);
}
- // If not null, there is a copy relocation to this section.
- InputSection *CopyRelSec = nullptr;
+ uint32_t Alignment;
uint64_t Value; // st_value
uint64_t Size; // st_size
-
- // This field is a index to the symbol's version definition.
- uint32_t VerdefIndex;
-
- uint32_t Alignment;
};
-// This represents a symbol that is not yet in the link, but we know where to
-// find it if needed. If the resolver finds both Undefined and Lazy for the same
-// name, it will ask the Lazy to load a file.
+// LazyArchive and LazyObject represent a symbols that is not yet in the link,
+// but we know where to find it if needed. If the resolver finds both Undefined
+// and Lazy for the same name, it will ask the Lazy to load a file.
//
// A special complication is the handling of weak undefined symbols. They should
// not load a file, but we have to remember we have seen both the weak undefined
// and the lazy. We represent that with a lazy symbol with a weak binding. This
// means that code looking for undefined symbols normally also has to take lazy
// symbols into consideration.
-class Lazy : public Symbol {
-public:
- static bool classof(const Symbol *S) { return S->isLazy(); }
-
- // Returns an object file for this symbol, or a nullptr if the file
- // was already returned.
- InputFile *fetch();
-
-protected:
- Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type)
- : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
- Type) {}
-};
// 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.
-class LazyArchive : public Lazy {
+class LazyArchive : public Symbol {
public:
- LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S,
- uint8_t Type)
- : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {}
+ LazyArchive(InputFile &File, uint8_t Type,
+ const llvm::object::Archive::Symbol S)
+ : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type),
+ Sym(S) {}
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
- ArchiveFile &getFile();
InputFile *fetch();
private:
@@ -296,15 +293,13 @@ private:
// LazyObject symbols represents symbols in object files between
// --start-lib and --end-lib options.
-class LazyObject : public Lazy {
+class LazyObject : public Symbol {
public:
- LazyObject(InputFile &File, StringRef Name, uint8_t Type)
- : Lazy(LazyObjectKind, File, Name, Type) {}
+ LazyObject(InputFile &File, uint8_t Type, StringRef Name)
+ : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type) {}
static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
-
- LazyObjFile &getFile();
- InputFile *fetch();
};
// Some linker-generated symbols need to be created as
@@ -334,6 +329,9 @@ struct ElfSym {
static Defined *MipsGp;
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
+
+ // __rela_iplt_end or __rel_iplt_end
+ static Defined *RelaIpltEnd;
};
// A buffer class that is large enough to hold any Symbol-derived
@@ -351,6 +349,8 @@ void printTraceSymbol(Symbol *Sym);
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
@@ -367,13 +367,14 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
S->ExportDynamic = Sym.ExportDynamic;
S->CanInline = Sym.CanInline;
S->Traced = Sym.Traced;
- S->InVersionScript = Sym.InVersionScript;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (S->Traced)
printTraceSymbol(S);
}
+
+void warnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
std::string toString(const elf::Symbol &B);
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index a5e291b79a4d..38859e1650bf 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -20,15 +20,16 @@
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/Decompressor.h"
@@ -47,27 +48,20 @@ using namespace llvm::dwarf;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
-using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-constexpr size_t MergeNoTailSection::NumShards;
-
-static void write32(void *Buf, uint32_t Val) {
- endian::write32(Buf, Val, Config->Endianness);
-}
+using llvm::support::endian::read32le;
+using llvm::support::endian::write32le;
+using llvm::support::endian::write64le;
-uint64_t SyntheticSection::getVA() const {
- if (OutputSection *Sec = getParent())
- return Sec->Addr + OutSecOff;
- return 0;
-}
+constexpr size_t MergeNoTailSection::NumShards;
// Returns an LLD version string.
static ArrayRef<uint8_t> getVersion() {
// Check LLD_VERSION first for ease of testing.
- // You can get consitent output by using the environment variable.
+ // You can get consistent output by using the environment variable.
// This is only for testing.
StringRef S = getenv("LLD_VERSION");
if (S.empty())
@@ -192,8 +186,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
if (Opt->kind == ODK_REGINFO) {
- if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
- error(Filename + ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
@@ -244,10 +236,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
- if (Config->Relocatable && R->ri_gp_value)
- error(toString(Sec->File) + ": unsupported non-zero ri_gp_value");
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
@@ -266,8 +256,8 @@ InputSection *elf::createInterpSection() {
return Sec;
}
-Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
- uint64_t Size, InputSectionBase &Section) {
+Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section) {
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
Value, Size, &Section);
if (InX::SymTab)
@@ -338,8 +328,6 @@ void BuildIdSection::computeHash(
BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
this->Bss = true;
- if (OutputSection *Sec = getParent())
- Sec->Alignment = std::max(Sec->Alignment, Alignment);
this->Size = Size;
}
@@ -380,15 +368,11 @@ EhFrameSection::EhFrameSection()
// and where their relocations point to.
template <class ELFT, class RelTy>
CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection>(Cie.Sec);
- if (read32(Cie.data().data() + 4, Config->Endianness) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
Symbol *Personality = nullptr;
unsigned FirstRelI = Cie.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality =
- &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+ &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
@@ -433,14 +417,14 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
- DenseMap<size_t, CieRecord *> OffsetToCie;
+ OffsetToCie.clear();
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.Size == 4)
return;
size_t Offset = Piece.InputOff;
- uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness);
+ uint32_t ID = read32(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
continue;
@@ -468,10 +452,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
for (auto *DS : Sec->DependentSections)
DependentSections.push_back(DS);
- // .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<ELFT>();
if (Sec->Pieces.empty())
return;
@@ -494,9 +474,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
}
void EhFrameSection::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
-
+ assert(!this->Size); // Not finalized.
size_t Off = 0;
for (CieRecord *Rec : CieRecords) {
Rec->Cie->OutputOff = Off;
@@ -509,10 +487,10 @@ void EhFrameSection::finalizeContents() {
}
// The LSB standard does not allow a .eh_frame section with zero
- // Call Frame Information records. Therefore add a CIE record length
- // 0 as a terminator if this .eh_frame section is empty.
- if (Off == 0)
- Off = 4;
+ // Call Frame Information records. glibc unwind-dw2-fde.c
+ // classify_object_over_fdes expects there is a CIE record length 0 as a
+ // terminator. Thus we add one unconditionally.
+ Off += 4;
this->Size = Off;
}
@@ -524,25 +502,47 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
+ uint64_t VA = InX::EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
- uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uint32_t FdeVA = getParent()->Addr + Fde->OutputOff;
- Ret.push_back({Pc, FdeVA});
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ if (!isInt<32>(Pc - VA))
+ fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
+ Twine::utohexstr(Pc - VA));
+ Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
}
}
+
+ // 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.PcRel < B.PcRel;
+ };
+ std::stable_sort(Ret.begin(), Ret.end(), Less);
+ auto Eq = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel == B.PcRel;
+ };
+ Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
+
return Ret;
}
static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
switch (Size) {
case DW_EH_PE_udata2:
- return read16(Buf, Config->Endianness);
+ return read16(Buf);
+ case DW_EH_PE_sdata2:
+ return (int16_t)read16(Buf);
case DW_EH_PE_udata4:
- return read32(Buf, Config->Endianness);
+ return read32(Buf);
+ case DW_EH_PE_sdata4:
+ return (int32_t)read32(Buf);
case DW_EH_PE_udata8:
- return read64(Buf, Config->Endianness);
+ case DW_EH_PE_sdata8:
+ return read64(Buf);
case DW_EH_PE_absptr:
return readUint(Buf);
}
@@ -556,7 +556,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7);
+ uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
@@ -589,7 +589,15 @@ void EhFrameSection::writeTo(uint8_t *Buf) {
GotSection::GotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotEntrySize, ".got") {}
+ Target->GotEntrySize, ".got") {
+ // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
+ // .got. If there are no references to .TOC. in the symbol table,
+ // ElfSym::GlobalOffsetTable will not be defined and we won't need to save
+ // .TOC. in the .got. When it is defined, we increase NumEntries by the number
+ // of entries used to emit ElfSym::GlobalOffsetTable.
+ if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
+ NumEntries += Target->GotHeaderEntriesNum;
+}
void GotSection::addEntry(Symbol &Sym) {
Sym.GotIndex = NumEntries;
@@ -623,196 +631,383 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
-void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
+void GotSection::finalizeContents() {
+ Size = NumEntries * Config->Wordsize;
+}
bool GotSection::empty() const {
// We need to emit a GOT even if it's empty if there's a relocation that is
// relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT
- // (i.e. _GLOBAL_OFFSET_TABLE_).
- return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable;
+ // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got.
+ return NumEntries == 0 && !HasGotOffRel &&
+ !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt);
}
void GotSection::writeTo(uint8_t *Buf) {
// Buf points to the start of this section's buffer,
// whereas InputSectionBase::relocateAlloc() expects its argument
// to point to the start of the output section.
+ Target->writeGotHeader(Buf);
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
".got") {}
-void MipsGotSection::addEntry(Symbol &Sym, int64_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
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+ RelExpr Expr) {
+ FileGot &G = getGot(File);
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.
- PageIndexMap.insert({Sym.getOutputSection(), 0});
- 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 = TlsEntries.size();
- TlsEntries.push_back(&Sym);
- return;
- }
- auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) {
- if (S.isInGot() && !A)
- return;
- size_t NewIndex = Items.size();
- if (!EntryIndexMap.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, GlobalEntries);
- Sym.IsInGlobalMipsGot = true;
- } else if (Expr == R_MIPS_GOT_OFF32) {
- AddEntry(Sym, Addend, LocalEntries32);
- Sym.Is32BitMipsGot = true;
- } else {
- // Hold local GOT entries accessed via a 16-bit index separately.
- // That allows to write them in the beginning of the GOT and keep
- // their indexes as less as possible to escape relocation's overflow.
- AddEntry(Sym, Addend, LocalEntries);
- }
+ if (const OutputSection *OS = Sym.getOutputSection())
+ G.PagesMap.insert({OS, {}});
+ else
+ G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+ } else if (Sym.isTls())
+ G.Tls.insert({&Sym, 0});
+ else if (Sym.IsPreemptible && Expr == R_ABS)
+ G.Relocs.insert({&Sym, 0});
+ else if (Sym.IsPreemptible)
+ G.Global.insert({&Sym, 0});
+ else if (Expr == R_MIPS_GOT_OFF32)
+ G.Local32.insert({{&Sym, Addend}, 0});
+ else
+ G.Local16.insert({{&Sym, Addend}, 0});
}
-bool MipsGotSection::addDynTlsEntry(Symbol &Sym) {
- if (Sym.GlobalDynIndex != -1U)
- return false;
- Sym.GlobalDynIndex = TlsEntries.size();
- // Global Dynamic TLS entries take two GOT slots.
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(&Sym);
- return true;
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+ getGot(File).DynTlsSymbols.insert({&Sym, 0});
}
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-bool MipsGotSection::addTlsIndex() {
- if (TlsIndexOff != uint32_t(-1))
- return false;
- TlsIndexOff = TlsEntries.size() * Config->Wordsize;
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(nullptr);
- return true;
+void MipsGotSection::addTlsIndex(InputFile &File) {
+ getGot(File).DynTlsSymbols.insert({nullptr, 0});
}
-static uint64_t getMipsPageAddr(uint64_t Addr) {
- return (Addr + 0x8000) & ~0xffff;
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+ return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+ Tls.size() + DynTlsSymbols.size() * 2;
}
-static uint64_t getMipsPageCount(uint64_t Size) {
- return (Size + 0xfffe) / 0xffff + 1;
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+ size_t Num = 0;
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+ Num += P.second.Count;
+ return Num;
}
-uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B,
- int64_t Addend) const {
- const OutputSection *OutSec = B.getOutputSection();
- uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
- uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
- assert(Index < PageEntriesNum);
- return (HeaderEntriesNum + Index) * Config->Wordsize;
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+ size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+ // If there are relocation-only entries in the GOT, TLS entries
+ // are allocated after them. TLS entries should be addressable
+ // by 16-bit index so count both reloc-only and TLS entries.
+ if (!Tls.empty() || !DynTlsSymbols.empty())
+ Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+ return Count;
}
-uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B,
- int64_t Addend) const {
- // Calculate offset of the GOT entries block: TLS, global, local.
- uint64_t Index = HeaderEntriesNum + PageEntriesNum;
- if (B.isTls())
- Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
- else if (B.IsInGlobalMipsGot)
- Index += LocalEntries.size() + LocalEntries32.size();
- else if (B.Is32BitMipsGot)
- Index += LocalEntries.size();
- // Calculate offset of the GOT entry in the block.
- if (B.isInGot())
- Index += B.GotIndex;
- else {
- auto It = EntryIndexMap.find({&B, Addend});
- assert(It != EntryIndexMap.end());
- Index += It->second;
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+ if (!F.MipsGotIndex.hasValue()) {
+ Gots.emplace_back();
+ Gots.back().File = &F;
+ F.MipsGotIndex = Gots.size() - 1;
+ }
+ return Gots[*F.MipsGotIndex];
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
+ const Symbol &Sym,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ uint64_t Index = 0;
+ if (const OutputSection *OutSec = Sym.getOutputSection()) {
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+ Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+ } else {
+ Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
}
return Index * Config->Wordsize;
}
-uint64_t MipsGotSection::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ if (Sym->isTls())
+ return G.Tls.lookup(Sym) * Config->Wordsize;
+ if (Sym->IsPreemptible)
+ return G.Global.lookup(Sym) * Config->Wordsize;
+ return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
}
-uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const {
- return B.GlobalDynIndex * Config->Wordsize;
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
+ const Symbol &S) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
}
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
- return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+ if (Gots.empty())
+ return nullptr;
+ const FileGot &PrimGot = Gots.front();
+ if (!PrimGot.Global.empty())
+ return PrimGot.Global.front().first;
+ if (!PrimGot.Relocs.empty())
+ return PrimGot.Relocs.front().first;
+ return nullptr;
}
unsigned MipsGotSection::getLocalEntriesNum() const {
- return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
- LocalEntries32.size();
+ if (Gots.empty())
+ return HeaderEntriesNum;
+ return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+ Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+ FileGot Tmp = Dst;
+ set_union(Tmp.PagesMap, Src.PagesMap);
+ set_union(Tmp.Local16, Src.Local16);
+ set_union(Tmp.Global, Src.Global);
+ set_union(Tmp.Relocs, Src.Relocs);
+ set_union(Tmp.Tls, Src.Tls);
+ set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+ size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+ Count += Tmp.getIndexedEntriesNum();
+
+ if (Count * Config->Wordsize > Config->MipsGotSize)
+ return false;
+
+ std::swap(Tmp, Dst);
+ return true;
}
void MipsGotSection::finalizeContents() { updateAllocSize(); }
bool MipsGotSection::updateAllocSize() {
- PageEntriesNum = 0;
- for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
- // For each output section referenced by GOT page relocations calculate
- // and save into PageIndexMap 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. And take in account the case when the section intersects
- // page boundaries.
- P.second = PageEntriesNum;
- PageEntriesNum += getMipsPageCount(P.first->Size);
- }
- Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- Config->Wordsize;
+ Size = HeaderEntriesNum * Config->Wordsize;
+ for (const FileGot &G : Gots)
+ Size += G.getEntriesNum() * Config->Wordsize;
return false;
}
+template <class ELFT> void MipsGotSection::build() {
+ if (Gots.empty())
+ return;
+
+ std::vector<FileGot> MergedGots(1);
+
+ // For each GOT move non-preemptible symbols from the `Global`
+ // to `Local16` list. Preemptible symbol might become non-preemptible
+ // one if, for example, it gets a related copy relocation.
+ for (FileGot &Got : Gots) {
+ for (auto &P: Got.Global)
+ if (!P.first->IsPreemptible)
+ Got.Local16.insert({{P.first, 0}, 0});
+ Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return !P.first->IsPreemptible;
+ });
+ }
+
+ // For each GOT remove "reloc-only" entry if there is "global"
+ // entry for the same symbol. And add local entries which indexed
+ // using 32-bit value at the end of 16-bit entries.
+ for (FileGot &Got : Gots) {
+ Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return Got.Global.count(P.first);
+ });
+ set_union(Got.Local16, Got.Local32);
+ Got.Local32.clear();
+ }
+
+ // Evaluate number of "reloc-only" entries in the resulting GOT.
+ // To do that put all unique "reloc-only" and "global" entries
+ // from all GOTs to the future primary GOT.
+ FileGot *PrimGot = &MergedGots.front();
+ for (FileGot &Got : Gots) {
+ set_union(PrimGot->Relocs, Got.Global);
+ set_union(PrimGot->Relocs, Got.Relocs);
+ Got.Relocs.clear();
+ }
+
+ // Evaluate number of "page" entries in each GOT.
+ for (FileGot &Got : Gots) {
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ const OutputSection *OS = P.first;
+ uint64_t SecSize = 0;
+ for (BaseCommand *Cmd : OS->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections) {
+ uint64_t Off = alignTo(SecSize, IS->Alignment);
+ SecSize = Off + IS->getSize();
+ }
+ }
+ P.second.Count = getMipsPageCount(SecSize);
+ }
+ }
+
+ // Merge GOTs. Try to join as much as possible GOTs but do not exceed
+ // maximum GOT size. At first, try to fill the primary GOT because
+ // the primary GOT can be accessed in the most effective way. If it
+ // is not possible, try to fill the last GOT in the list, and finally
+ // create a new GOT if both attempts failed.
+ for (FileGot &SrcGot : Gots) {
+ InputFile *File = SrcGot.File;
+ if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
+ File->MipsGotIndex = 0;
+ } else {
+ // If this is the first time we failed to merge with the primary GOT,
+ // MergedGots.back() will also be the primary GOT. We must make sure not
+ // to try to merge again with IsPrimary=false, as otherwise, if the
+ // inputs are just right, we could allow the primary GOT to become 1 or 2
+ // words too big due to ignoring the header size.
+ if (MergedGots.size() == 1 ||
+ !tryMergeGots(MergedGots.back(), SrcGot, false)) {
+ MergedGots.emplace_back();
+ std::swap(MergedGots.back(), SrcGot);
+ }
+ File->MipsGotIndex = MergedGots.size() - 1;
+ }
+ }
+ std::swap(Gots, MergedGots);
+
+ // Reduce number of "reloc-only" entries in the primary GOT
+ // by substracting "global" entries exist in the primary GOT.
+ PrimGot = &Gots.front();
+ PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return PrimGot->Global.count(P.first);
+ });
+
+ // Calculate indexes for each GOT entry.
+ size_t Index = HeaderEntriesNum;
+ for (FileGot &Got : Gots) {
+ Got.StartIndex = &Got == PrimGot ? 0 : Index;
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PagesMap 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. And take in account the case when the section intersects
+ // page boundaries.
+ P.second.FirstIndex = Index;
+ Index += P.second.Count;
+ }
+ for (auto &P: Got.Local16)
+ P.second = Index++;
+ for (auto &P: Got.Global)
+ P.second = Index++;
+ for (auto &P: Got.Relocs)
+ P.second = Index++;
+ for (auto &P: Got.Tls)
+ P.second = Index++;
+ for (auto &P: Got.DynTlsSymbols) {
+ P.second = Index;
+ Index += 2;
+ }
+ }
+
+ // Update Symbol::GotIndex field to use this
+ // value later in the `sortMipsSymbols` function.
+ for (auto &P : PrimGot->Global)
+ P.first->GotIndex = P.second;
+ for (auto &P : PrimGot->Relocs)
+ P.first->GotIndex = P.second;
+
+ // Create dynamic relocations.
+ for (FileGot &Got : Gots) {
+ // Create dynamic relocations for TLS entries.
+ for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S->IsPreemptible)
+ InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ }
+ for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S == nullptr) {
+ if (!Config->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ } else {
+ // When building a shared library we still need a dynamic relocation
+ // for the module index. Therefore only checking for
+ // S->IsPreemptible is not sufficient (this happens e.g. for
+ // thread-locals that have been marked as local through a linker script)
+ if (!S->IsPreemptible && !Config->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ // However, we can skip writing the TLS offset reloc for non-preemptible
+ // symbols since it is known even in shared libraries
+ if (!S->IsPreemptible)
+ continue;
+ Offset += Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ }
+ }
+
+ // Do not create dynamic relocations for non-TLS
+ // entries in the primary GOT.
+ if (&Got == PrimGot)
+ continue;
+
+ // Dynamic relocations for "global" entries.
+ for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ }
+ if (!Config->Pic)
+ continue;
+ // Dynamic relocations for "local" entries in case of PIC.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ Got.PagesMap) {
+ size_t PageCount = L.second.Count;
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
+ }
+ }
+ for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
+ }
+ }
+}
+
bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
-uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+ // For files without related GOT or files refer a primary GOT
+ // returns "common" _gp value. For secondary GOTs calculate
+ // individual _gp values.
+ if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+ return ElfSym::MipsGp->getVA(0);
+ return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+ 0x7ff0;
+}
void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
@@ -830,59 +1025,67 @@ void MipsGotSection::writeTo(uint8_t *Buf) {
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
- Buf += HeaderEntriesNum * Config->Wordsize;
- // Write 'page address' entries to the local part of the GOT.
- for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
- size_t PageCount = getMipsPageCount(L.first->Size);
- uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
- for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
- writeUint(Entry, FirstPageAddr + PI * 0x10000);
- }
- }
- Buf += PageEntriesNum * Config->Wordsize;
- auto AddEntry = [&](const GotEntry &SA) {
- uint8_t *Entry = Buf;
- Buf += Config->Wordsize;
- const Symbol *Sym = SA.first;
- uint64_t VA = Sym->getVA(SA.second);
- if (Sym->StOther & STO_MIPS_MICROMIPS)
- VA |= 1;
- writeUint(Entry, VA);
- };
- std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
- std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
- std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
- // Initialize TLS-related GOT entries. If the entry has a corresponding
- // dynamic relocations, leave it initialized by zero. Write down adjusted
- // TLS symbol's values otherwise. To calculate the adjustments use offsets
- // for thread-local storage.
- // https://www.linux-mips.org/wiki/NPTL
- if (TlsIndexOff != -1U && !Config->Pic)
- writeUint(Buf + TlsIndexOff, 1);
- for (const Symbol *B : TlsEntries) {
- if (!B || B->IsPreemptible)
- continue;
- uint64_t VA = B->getVA();
- if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
- writeUint(Entry, VA - 0x7000);
+ for (const FileGot &G : Gots) {
+ auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+ uint64_t VA = A;
+ if (S) {
+ VA = S->getVA(A);
+ if (S->StOther & STO_MIPS_MICROMIPS)
+ VA |= 1;
+ }
+ writeUint(Buf + I * Config->Wordsize, VA);
+ };
+ // Write 'page address' entries to the local part of the GOT.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ G.PagesMap) {
+ size_t PageCount = L.second.Count;
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI)
+ Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
}
- if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
- writeUint(Entry, 1);
- Entry += Config->Wordsize;
- writeUint(Entry, VA - 0x8000);
+ // Local, global, TLS, reloc-only entries.
+ // If TLS entry has a corresponding dynamic relocations, leave it
+ // initialized by zero. Write down adjusted TLS symbol's values otherwise.
+ // To calculate the adjustments use offsets for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ for (const std::pair<GotEntry, size_t> &P : G.Local16)
+ Write(P.second, P.first.first, P.first.second);
+ // Write VA to the primary GOT only. For secondary GOTs that
+ // will be done by REL32 dynamic relocations.
+ if (&G == &Gots.front())
+ for (const std::pair<const Symbol *, size_t> &P : G.Global)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Relocs)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Tls)
+ Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
+ for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+ if (P.first == nullptr && !Config->Pic)
+ Write(P.second, nullptr, 1);
+ else if (P.first && !P.first->IsPreemptible) {
+ // If we are emitting PIC code with relocations we mustn't write
+ // anything to the GOT here. When using Elf_Rel relocations the value
+ // one will be treated as an addend and will cause crashes at runtime
+ if (!Config->Pic)
+ Write(P.second, nullptr, 1);
+ Write(P.second + 1, P.first, -0x8000);
+ }
}
}
}
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
GotPltSection::GotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
void GotPltSection::addEntry(Symbol &Sym) {
- Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -900,16 +1103,37 @@ void GotPltSection::writeTo(uint8_t *Buf) {
}
}
-// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
-// part of the .got.plt
+bool GotPltSection::empty() const {
+ // We need to emit a GOT.PLT even if it's empty if there's a symbol that
+ // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol
+ // relative to the .got.plt section.
+ return Entries.empty() &&
+ !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
+}
+
+static StringRef getIgotPltName() {
+ // On ARM the IgotPltSection is part of the GotSection.
+ if (Config->EMachine == EM_ARM)
+ return ".got";
+
+ // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+ // needs to be named the same.
+ if (Config->EMachine == EM_PPC64)
+ return ".plt";
+
+ return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
IgotPltSection::IgotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
Sym.IsInIgot = true;
- Sym.GotPltIndex = Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -1005,8 +1229,14 @@ void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
template <class ELFT>
void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
+ size_t TagOffset = Entries.size() * Entsize;
Entries.push_back(
- {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }});
+ {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
}
template <class ELFT>
@@ -1034,6 +1264,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
+ if (Config->ZInitfirst)
+ DtFlags1 |= DF_1_INITFIRST;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
@@ -1046,6 +1278,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
+ if (!Config->ZText)
+ DtFlags |= DF_TEXTREL;
if (DtFlags)
addInt(DT_FLAGS, DtFlags);
@@ -1064,7 +1298,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(DT_DEBUG, 0);
this->Link = InX::DynStrTab->getParent()->SectionIndex;
- if (InX::RelaDyn->getParent() && !InX::RelaDyn->empty()) {
+ if (!InX::RelaDyn->empty()) {
addInSec(InX::RelaDyn->DynamicTag, InX::RelaDyn);
addSize(InX::RelaDyn->SizeDynamicTag, InX::RelaDyn->getParent());
@@ -1081,7 +1315,21 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
- if (InX::RelaPlt->getParent() && !InX::RelaPlt->empty()) {
+ if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
+ addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
+ InX::RelrDyn);
+ addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
+ InX::RelrDyn->getParent());
+ addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
+ sizeof(Elf_Relr));
+ }
+ // .rel[a].plt section usually consists of two parts, containing plt and
+ // iplt relocations. It is possible to have only iplt relocations in the
+ // output. In that case RelaPlt is empty and have zero offset, the same offset
+ // as RelaIplt have. And we still want to emit proper dynamic tags for that
+ // case, so here we always use RelaPlt as marker for the begining of
+ // .rel[a].plt section.
+ if (InX::RelaPlt->getParent()->Live) {
addInSec(DT_JMPREL, InX::RelaPlt);
addSize(DT_PLTRELSZ, InX::RelaPlt->getParent());
switch (Config->EMachine) {
@@ -1154,8 +1402,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
else
addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ if (InX::MipsRldMap) {
+ if (!Config->Pie)
+ addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ // Store the offset to the .rld_map section
+ // relative to the address of the tag.
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ }
+ }
+
+ // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+ if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+ // The Glink tag points to 32 bytes before the first lazy symbol resolution
+ // stub, which starts directly after the header.
+ Entries.push_back({DT_PPC64_GLINK, [=] {
+ unsigned Offset = Target->PltHeaderSize - 32;
+ return InX::Plt->getVA(0) + Offset;
+ }});
}
addInt(DT_NULL, 0);
@@ -1175,13 +1438,16 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
}
uint64_t DynamicReloc::getOffset() const {
- return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
+ return InputSec->getVA(OffsetInSec);
}
-int64_t DynamicReloc::getAddend() const {
+int64_t DynamicReloc::computeAddend() const {
if (UseSymVA)
return Sym->getVA(Addend);
- return Addend;
+ if (!OutputSec)
+ return Addend;
+ // See the comment in the DynamicReloc ctor.
+ return getMipsPageAddr(OutputSec->Addr) + Addend;
}
uint32_t DynamicReloc::getSymIndex() const {
@@ -1196,6 +1462,23 @@ RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
+void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
+ uint64_t OffsetInSec, Symbol *Sym) {
+ addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
+}
+
+void RelocationBaseSection::addReloc(RelType DynType,
+ InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym,
+ int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Write the addends to the relocated address if required. We skip
+ // it if the written value would be zero.
+ if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0))
+ InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend});
+}
+
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
@@ -1212,23 +1495,17 @@ void RelocationBaseSection::finalizeContents() {
getParent()->Link = Link;
}
+RelrBaseSection::RelrBaseSection()
+ : SyntheticSection(SHF_ALLOC,
+ Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
+ Config->Wordsize, ".relr.dyn") {}
+
template <class ELFT>
static void encodeDynamicReloc(typename ELFT::Rela *P,
const DynamicReloc &Rel) {
if (Config->IsRela)
- P->r_addend = Rel.getAddend();
+ P->r_addend = Rel.computeAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
- // The MIPS GOT section contains dynamic relocations that correspond to TLS
- // entries. These entries are placed after the global and local sections of
- // the GOT. At the point when we create these relocations, the size of the
- // global and local sections is unknown, so the offset that we store in the
- // TLS entry's DynamicReloc is relative to the start of the TLS section of
- // the GOT, rather than being relative to the start of the GOT. This line of
- // code adds the size of the global and local sections to the virtual
- // address computed by getOffset() in order to adjust it into the TLS
- // section.
- P->r_offset += InX::MipsGot->getTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
@@ -1241,32 +1518,22 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-template <class ELFT, class RelTy>
-static bool compRelocations(const RelTy &A, const RelTy &B) {
- bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
- bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
+static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) {
+ bool AIsRel = A.Type == Target->RelativeRel;
+ bool BIsRel = B.Type == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
-
- return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
+ return A.getSymIndex() < B.getSymIndex();
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
- uint8_t *BufBegin = Buf;
+ if (Sort)
+ std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations);
+
for (const DynamicReloc &Rel : Relocs) {
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-
- if (Sort) {
- if (Config->IsRela)
- 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() {
@@ -1354,10 +1621,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
NonRelatives.push_back(R);
}
- std::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives.begin(), Relatives.end(),
+ [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
@@ -1435,10 +1702,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
// Finally the non-relative relocations.
- std::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives.begin(), NonRelatives.end(),
+ [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1461,6 +1728,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
return RelocData.size() != OldSize;
}
+template <class ELFT> RelrSection<ELFT>::RelrSection() {
+ this->Entsize = Config->Wordsize;
+}
+
+template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
+ // This function computes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
+ size_t OldSize = RelrRelocs.size();
+ RelrRelocs.clear();
+
+ // Same as Config->Wordsize but faster because this is a compile-time
+ // constant.
+ const size_t Wordsize = sizeof(typename ELFT::uint);
+
+ // Number of bits to use for the relocation offsets bitmap.
+ // Must be either 63 or 31.
+ const size_t NBits = Wordsize * 8 - 1;
+
+ // Get offsets for all relative relocations and sort them.
+ std::vector<uint64_t> Offsets;
+ for (const RelativeReloc &Rel : Relocs)
+ Offsets.push_back(Rel.getOffset());
+ llvm::sort(Offsets.begin(), Offsets.end());
+
+ // For each leading relocation, find following ones that can be folded
+ // as a bitmap and fold them.
+ for (size_t I = 0, E = Offsets.size(); I < E;) {
+ // Add a leading relocation.
+ RelrRelocs.push_back(Elf_Relr(Offsets[I]));
+ uint64_t Base = Offsets[I] + Wordsize;
+ ++I;
+
+ // Find foldable relocations to construct bitmaps.
+ while (I < E) {
+ uint64_t Bitmap = 0;
+
+ while (I < E) {
+ uint64_t Delta = Offsets[I] - Base;
+
+ // If it is too far, it cannot be folded.
+ if (Delta >= NBits * Wordsize)
+ break;
+
+ // If it is not a multiple of wordsize away, it cannot be folded.
+ if (Delta % Wordsize)
+ break;
+
+ // Fold it.
+ Bitmap |= 1ULL << (Delta / Wordsize);
+ ++I;
+ }
+
+ if (!Bitmap)
+ break;
+
+ RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
+ Base += NBits * Wordsize;
+ }
+ }
+
+ return RelrRelocs.size() != OldSize;
+}
+
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
@@ -1476,50 +1834,70 @@ SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
static bool sortMipsSymbols(const SymbolTableEntry &L,
const SymbolTableEntry &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.Sym->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot;
- if (LIsInLocalGot || RIsInLocalGot)
- return !RIsInLocalGot;
- return L.Sym->GotIndex < R.Sym->GotIndex;
+ // All other entries go to the beginning of a dynsym in arbitrary order.
+ if (L.Sym->isInGot() && R.Sym->isInGot())
+ return L.Sym->GotIndex < R.Sym->GotIndex;
+ if (!L.Sym->isInGot() && !R.Sym->isInGot())
+ return false;
+ return !L.Sym->isInGot();
}
void SymbolTableBaseSection::finalizeContents() {
getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (this->Type != SHT_DYNSYM)
+ return;
+
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
- if (this->Type == SHT_DYNSYM) {
- // Section's Info field has the index of the first non-local symbol.
- // Because the first symbol entry is a null entry, 1 is the first.
- getParent()->Info = 1;
-
- if (InX::GnuHashTab) {
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
- } else if (Config->EMachine == EM_MIPS) {
- std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
- }
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I;
- return;
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
+
+ if (InX::GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ InX::GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
+
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Sym->DynsymIndex = ++I;
}
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
+//
+// Aside from above, we put local symbols in groups starting with the STT_FILE
+// symbol. That is convenient for purpose of identifying where are local symbols
+// coming from.
void SymbolTableBaseSection::postThunkContents() {
- if (this->Type == SHT_DYNSYM)
- return;
- // move all local symbols before global symbols.
- auto It = std::stable_partition(
+ assert(this->Type == SHT_SYMTAB);
+
+ // Move all local symbols before global symbols.
+ auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
- size_t NumLocals = It - Symbols.begin();
+ size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;
+
+ // We want to group the local symbols by file. For that we rebuild the local
+ // part of the symbols vector. We do not need to care about the STT_FILE
+ // symbols, they are already naturally placed first in each group. That
+ // happens because STT_FILE is always the first symbol in the object and hence
+ // precede all other local symbols we add for a file.
+ MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
+ for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
+ Arr[S.Sym->File].push_back(S);
+
+ auto I = Symbols.begin();
+ for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
+ for (SymbolTableEntry &Entry : P.second)
+ *I++ = Entry;
}
void SymbolTableBaseSection::addSymbol(Symbol *B) {
@@ -1586,6 +1964,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
CommonSec = dyn_cast_or_null<BssSection>(D->Section);
if (CommonSec)
ESym->st_shndx = SHN_COMMON;
+ else if (Sym->NeedsPltAddr)
+ ESym->st_shndx = SHN_UNDEF;
else if (const OutputSection *OutSec = Sym->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<Defined>(Sym))
@@ -1627,9 +2007,11 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
ESym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
- // defined microMIPS symbols and shared symbols with PLT record.
- if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) ||
- (Sym->isShared() && Sym->NeedsPltAddr)) {
+ // a defined microMIPS symbol and symbol should point to its
+ // PLT entry (in case of microMIPS, PLT entries always contain
+ // microMIPS code).
+ if (Sym->isDefined() &&
+ ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
@@ -1682,12 +2064,14 @@ GnuHashTableSection::GnuHashTableSection()
void GnuHashTableSection::finalizeContents() {
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
- // Computes bloom filter size in word size. We want to allocate 8
+ // Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
- if (Symbols.empty())
+ if (Symbols.empty()) {
MaskWords = 1;
- else
- MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+ } else {
+ uint64_t NumBits = Symbols.size() * 12;
+ MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
+ }
Size = 16; // Header
Size += Config->Wordsize * MaskWords; // Bloom filter
@@ -1705,7 +2089,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
write32(Buf, NBuckets);
write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
- write32(Buf + 12, getShift2());
+ write32(Buf + 12, Shift2);
Buf += 16;
// Write a bloom filter and a hash table.
@@ -1722,12 +2106,12 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
- const unsigned C = Config->Wordsize * 8;
+ unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
- Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C);
+ Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
writeUint(Buf + I * Config->Wordsize, Val);
}
}
@@ -1769,21 +2153,23 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
- // Shared symbols that this executable preempts are special. The dynamic
- // linker has to look them up, so they have to be in the hash table.
- if (auto *SS = dyn_cast<SharedSymbol>(S.Sym))
- return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr;
return !S.Sym->isDefined();
});
- if (Mid == V.end())
- return;
// We chose load factor 4 for the on-disk hash table. For each hash
// collision, the dynamic linker will compare a uint32_t hash value.
- // Since the integer comparison is quite fast, we believe we can make
- // the load factor even larger. 4 is just a conservative choice.
+ // Since the integer comparison is quite fast, we believe we can
+ // make the load factor even larger. 4 is just a conservative choice.
+ //
+ // Note that we don't want to create a zero-sized hash table because
+ // Android loader as of 2018 doesn't like a .gnu.hash containing such
+ // table. If that's the case, we create a hash table with one unused
+ // dummy slot.
NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
+ if (Mid == V.end())
+ return;
+
for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
Symbol *B = Ent.Sym;
uint32_t Hash = hashGnu(B->getName());
@@ -1817,6 +2203,9 @@ void HashTableSection::finalizeContents() {
}
void HashTableSection::writeTo(uint8_t *Buf) {
+ // See comment in GnuHashTableSection::writeTo.
+ memset(Buf, 0, Size);
+
unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
@@ -1836,9 +2225,12 @@ void HashTableSection::writeTo(uint8_t *Buf) {
}
}
-PltSection::PltSection(size_t S)
- : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
- HeaderSize(S) {
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
+PltSection::PltSection(bool IsIplt)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
+ HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
if (Config->EMachine == EM_SPARCV9)
@@ -1848,7 +2240,7 @@ PltSection::PltSection(size_t S)
void PltSection::writeTo(uint8_t *Buf) {
// At beginning of PLT but not the IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
@@ -1867,7 +2259,7 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
RelocationBaseSection *PltRelocSection = InX::RelaPlt;
- if (HeaderSize == 0) {
+ if (IsIplt) {
PltRelocSection = InX::RelaIplt;
Sym.IsInIplt = true;
}
@@ -1884,7 +2276,7 @@ size_t PltSection::getSize() const {
// example ARM uses mapping symbols to aid disassembly
void PltSection::addSymbols() {
// The PLT may have symbols defined for the Header, the IPLT has no header
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->addPltHeaderSymbols(*this);
size_t Off = HeaderSize;
for (size_t I = 0; I < Entries.size(); ++I) {
@@ -1894,7 +2286,7 @@ void PltSection::addSymbols() {
}
unsigned PltSection::getPltRelocOff() const {
- return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
+ return IsIplt ? InX::Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
@@ -1905,16 +2297,48 @@ static uint32_t computeGdbHash(StringRef S) {
return H;
}
-static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) {
- std::vector<GdbIndexChunk::CuEntry> Ret;
+GdbIndexSection::GdbIndexSection()
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
+
+// Returns the desired size of an on-disk hash table for a .gdb_index section.
+// There's a tradeoff between size and collision rate. We aim 75% utilization.
+size_t GdbIndexSection::computeSymtabSize() const {
+ return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
+}
+
+// Compute the output section size.
+void GdbIndexSection::initOutputSize() {
+ Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
+
+ for (GdbChunk &Chunk : Chunks)
+ Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
+
+ // Add the constant pool size if exists.
+ if (!Symbols.empty()) {
+ GdbSymbol &Sym = Symbols.back();
+ Size += Sym.NameOff + Sym.Name.size() + 1;
+ }
+}
+
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
+
+static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<GdbIndexSection::CuEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
-static std::vector<GdbIndexChunk::AddressEntry>
+static std::vector<GdbIndexSection::AddressEntry>
readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
- std::vector<GdbIndexChunk::AddressEntry> Ret;
+ std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
@@ -1938,218 +2362,192 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
return Ret;
}
-static std::vector<GdbIndexChunk::NameTypeEntry>
-readPubNamesAndTypes(DWARFContext &Dwarf) {
+static std::vector<GdbIndexSection::NameTypeEntry>
+readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
- std::vector<GdbIndexChunk::NameTypeEntry> Ret;
+ std::vector<GdbIndexSection::NameTypeEntry> Ret;
for (StringRef Sec : {Sec1, Sec2}) {
DWARFDebugPubTable Table(Sec, Config->IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
- for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) {
- CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name));
- Ret.push_back({S, Ent.Descriptor.toBits()});
- }
- }
+ for (const DWARFDebugPubTable::Set &Set : Table.getData())
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
+ (Ent.Descriptor.toBits() << 24) | Idx});
}
return Ret;
}
-static std::vector<InputSection *> getDebugInfoSections() {
- std::vector<InputSection *> Ret;
- for (InputSectionBase *S : InputSections)
- if (InputSection *IS = dyn_cast<InputSection>(S))
- if (IS->Name == ".debug_info")
- Ret.push_back(IS);
- return Ret;
-}
+// Create a list of symbols from a given list of symbol names and types
+// by uniquifying them by name.
+static std::vector<GdbIndexSection::GdbSymbol>
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
+ typedef GdbIndexSection::GdbSymbol GdbSymbol;
+ typedef GdbIndexSection::NameTypeEntry NameTypeEntry;
-void GdbIndexSection::fixCuIndex() {
- uint32_t Idx = 0;
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas)
- Ent.CuIndex += Idx;
- Idx += Chunk.CompilationUnits.size();
- }
-}
+ // The number of symbols we will handle in this function is of the order
+ // of millions for very large executables, so we use multi-threading to
+ // speed it up.
+ size_t NumShards = 32;
+ size_t Concurrency = 1;
+ if (ThreadsEnabled)
+ Concurrency =
+ std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
-std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() {
- std::vector<std::vector<uint32_t>> Ret;
- uint32_t Idx = 0;
- uint32_t Off = 0;
+ // A sharded map to uniquify symbols by name.
+ std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
+ size_t Shift = 32 - countTrailingZeros(NumShards);
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) {
- GdbSymbol *&Sym = Symbols[Ent.Name];
- if (!Sym) {
- Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()});
- Off += Ent.Name.size() + 1;
- Ret.push_back({});
- }
+ // Instantiate GdbSymbols while uniqufying them by name.
+ std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
+ parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
+ for (ArrayRef<NameTypeEntry> Entries : NameTypes) {
+ for (const NameTypeEntry &Ent : Entries) {
+ size_t ShardId = Ent.Name.hash() >> Shift;
+ if ((ShardId & (Concurrency - 1)) != ThreadId)
+ continue;
- // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains
- // duplicate entries, so we want to dedup them.
- std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex];
- uint32_t Val = (Ent.Type << 24) | Idx;
- if (Vec.empty() || Vec.back() != Val)
- Vec.push_back(Val);
+ size_t &Idx = Map[ShardId][Ent.Name];
+ if (Idx) {
+ Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type);
+ continue;
+ }
+
+ Idx = Symbols[ShardId].size() + 1;
+ Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0});
+ }
}
- Idx += Chunk.CompilationUnits.size();
+ });
+
+ size_t NumSymbols = 0;
+ for (ArrayRef<GdbSymbol> V : Symbols)
+ NumSymbols += V.size();
+
+ // The return type is a flattened vector, so we'll copy each vector
+ // contents to Ret.
+ std::vector<GdbSymbol> Ret;
+ Ret.reserve(NumSymbols);
+ for (std::vector<GdbSymbol> &Vec : Symbols)
+ for (GdbSymbol &Sym : Vec)
+ Ret.push_back(std::move(Sym));
+
+ // CU vectors and symbol names are adjacent in the output file.
+ // We can compute their offsets in the output file now.
+ size_t Off = 0;
+ for (GdbSymbol &Sym : Ret) {
+ Sym.CuVectorOff = Off;
+ Off += (Sym.CuVector.size() + 1) * 4;
+ }
+ for (GdbSymbol &Sym : Ret) {
+ Sym.NameOff = Off;
+ Off += Sym.Name.size() + 1;
}
- StringPoolSize = Off;
return Ret;
}
-template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
- // Gather debug info to create a .gdb_index section.
+// Returns a newly-created .gdb_index section.
+template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
std::vector<InputSection *> Sections = getDebugInfoSections();
- std::vector<GdbIndexChunk> Chunks(Sections.size());
-
- parallelForEachN(0, Chunks.size(), [&](size_t I) {
- ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
-
- Chunks[I].DebugInfoSec = Sections[I];
- Chunks[I].CompilationUnits = readCuList(Dwarf);
- Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
- Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf);
- });
// .debug_gnu_pub{names,types} are useless in executables.
// They are present in input object files solely for creating
- // a .gdb_index. So we can remove it from the output.
+ // a .gdb_index. So we can remove them from the output.
for (InputSectionBase *S : InputSections)
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
S->Live = false;
- // Create a .gdb_index and returns it.
- return make<GdbIndexSection>(std::move(Chunks));
-}
+ std::vector<GdbChunk> Chunks(Sections.size());
+ std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size());
-static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.CompilationUnits.size();
- return Ret;
-}
-
-static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.AddressAreas.size();
- return Ret;
-}
-
-std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() {
- uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3);
- if (Size < 1024)
- Size = 1024;
-
- uint32_t Mask = Size - 1;
- std::vector<GdbSymbol *> Ret(Size);
+ parallelForEachN(0, Sections.size(), [&](size_t I) {
+ ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
- for (auto &KV : Symbols) {
- GdbSymbol *Sym = KV.second;
- uint32_t I = Sym->NameHash & Mask;
- uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+ Chunks[I].Sec = Sections[I];
+ Chunks[I].CompilationUnits = readCuList(Dwarf);
+ Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
+ NameTypes[I] = readPubNamesAndTypes(Dwarf, I);
+ });
- while (Ret[I])
- I = (I + Step) & Mask;
- Ret[I] = Sym;
- }
+ auto *Ret = make<GdbIndexSection>();
+ Ret->Chunks = std::move(Chunks);
+ Ret->Symbols = createSymbols(NameTypes);
+ Ret->initOutputSize();
return Ret;
}
-GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C)
- : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) {
- fixCuIndex();
- CuVectors = createCuVectors();
- GdbSymtab = createGdbSymtab();
-
- // Compute offsets early to know the section size.
- // Each chunk size needs to be in sync with what we write in writeTo.
- CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16;
- SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20;
- ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8;
-
- size_t Off = 0;
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- CuVectorOffsets.push_back(Off);
- Off += (Vec.size() + 1) * 4;
- }
- StringPoolOffset = ConstantPoolOffset + Off;
-}
-
-size_t GdbIndexSection::getSize() const {
- return StringPoolOffset + StringPoolSize;
-}
-
void GdbIndexSection::writeTo(uint8_t *Buf) {
- // Write the section header.
- write32le(Buf, 7);
- write32le(Buf + 4, CuListOffset);
- write32le(Buf + 8, CuTypesOffset);
- write32le(Buf + 12, CuTypesOffset);
- write32le(Buf + 16, SymtabOffset);
- write32le(Buf + 20, ConstantPoolOffset);
- Buf += 24;
+ // Write the header.
+ auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
+ uint8_t *Start = Buf;
+ Hdr->Version = 7;
+ Buf += sizeof(*Hdr);
// Write the CU list.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) {
- write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+ Hdr->CuListOff = Buf - Start;
+ for (GdbChunk &Chunk : Chunks) {
+ for (CuEntry &Cu : Chunk.CompilationUnits) {
+ write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
}
}
// Write the address area.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) {
- uint64_t BaseAddr =
- E.Section->getParent()->Addr + E.Section->getOffset(0);
+ Hdr->CuTypesOff = Buf - Start;
+ Hdr->AddressAreaOff = Buf - Start;
+ uint32_t CuOff = 0;
+ for (GdbChunk &Chunk : Chunks) {
+ for (AddressEntry &E : Chunk.AddressAreas) {
+ uint64_t BaseAddr = E.Section->getVA(0);
write64le(Buf, BaseAddr + E.LowAddress);
write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
+ write32le(Buf + 16, E.CuIndex + CuOff);
Buf += 20;
}
+ CuOff += Chunk.CompilationUnits.size();
}
- // Write the symbol table.
- for (GdbSymbol *Sym : GdbSymtab) {
- if (Sym) {
- write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset);
- write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]);
- }
- Buf += 8;
+ // Write the on-disk open-addressing hash table containing symbols.
+ Hdr->SymtabOff = Buf - Start;
+ size_t SymtabSize = computeSymtabSize();
+ uint32_t Mask = SymtabSize - 1;
+
+ for (GdbSymbol &Sym : Symbols) {
+ uint32_t H = Sym.Name.hash();
+ uint32_t I = H & Mask;
+ uint32_t Step = ((H * 17) & Mask) | 1;
+
+ while (read32le(Buf + I * 8))
+ I = (I + Step) & Mask;
+
+ write32le(Buf + I * 8, Sym.NameOff);
+ write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
}
+ Buf += SymtabSize * 8;
+
+ // Write the string pool.
+ Hdr->ConstantPoolOff = Buf - Start;
+ for (GdbSymbol &Sym : Symbols)
+ memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+
// Write the CU vectors.
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- write32le(Buf, Vec.size());
+ for (GdbSymbol &Sym : Symbols) {
+ write32le(Buf, Sym.CuVector.size());
Buf += 4;
- for (uint32_t Val : Vec) {
+ for (uint32_t Val : Sym.CuVector) {
write32le(Buf, Val);
Buf += 4;
}
}
-
- // Write the string pool.
- for (auto &KV : Symbols) {
- CachedHashStringRef S = KV.first;
- GdbSymbol *Sym = KV.second;
- size_t Off = Sym->NameOffset;
- memcpy(Buf + Off, S.val().data(), S.size());
- Buf[Off + S.size()] = '\0';
- }
}
bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
EhFrameHeader::EhFrameHeader()
- : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
@@ -2160,14 +2558,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
- // 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;
@@ -2176,10 +2566,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
write32(Buf + 8, Fdes.size());
Buf += 12;
- uint64_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
- write32(Buf, Fde.Pc - VA);
- write32(Buf + 4, Fde.FdeVA - VA);
+ write32(Buf, Fde.PcRel);
+ write32(Buf + 4, Fde.FdeVARel);
Buf += 8;
}
}
@@ -2289,11 +2678,9 @@ VersionNeedSection<ELFT>::VersionNeedSection()
NextIndex = getVerDefNum() + 1;
}
-template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
- const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
- if (!Ver) {
+template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
+ auto &File = cast<SharedFile<ELFT>>(*SS->File);
+ if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;
}
@@ -2303,7 +2690,9 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
// for the soname.
if (File.VerdefMap.empty())
Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)});
+ const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
+
// 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.
@@ -2429,10 +2818,8 @@ void MergeNoTailSection::finalizeContents() {
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
for (MergeInputSection *Sec : Sections) {
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
- if (!Sec->Pieces[I].Live)
- continue;
size_t ShardId = getShardId(Sec->Pieces[I].Hash);
- if ((ShardId & (Concurrency - 1)) == ThreadId)
+ if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));
}
}
@@ -2469,11 +2856,20 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
-// Debug sections may be compressed by zlib. Uncompress if exists.
+// Debug sections may be compressed by zlib. Decompress if exists.
void elf::decompressSections() {
+ parallelForEach(InputSections,
+ [](InputSectionBase *Sec) { Sec->maybeDecompress(); });
+}
+
+template <class ELFT> void elf::splitSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection
+ // before calling finalizeContents().
parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- Sec->maybeUncompress();
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ S->splitIntoPieces();
+ else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
+ Eh->split<ELFT>();
});
}
@@ -2485,14 +2881,6 @@ void elf::decompressSections() {
// that it replaces. It then finalizes each synthetic section in order
// to compute an output offset for each piece of each input section.
void elf::mergeSections() {
- // splitIntoPieces needs to be called on each MergeInputSection
- // before calling finalizeContents(). Do that first.
- parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- if (auto *S = dyn_cast<MergeInputSection>(Sec))
- S->splitIntoPieces();
- });
-
std::vector<MergeSyntheticSection *> MergeSections;
for (InputSectionBase *&S : InputSections) {
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
@@ -2554,8 +2942,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
// address described by any other table entry.
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
assert(Highest);
- uint64_t S =
- Highest->getParent()->Addr + Highest->getOffset(Highest->getSize());
+ uint64_t S = Highest->getVA(Highest->getSize());
uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 1);
@@ -2563,15 +2950,16 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// The sentinel has to be removed if there are no other .ARM.exidx entries.
bool ARMExidxSentinelSection::empty() const {
- OutputSection *OS = getParent();
- for (auto *B : OS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(B))
- for (auto *S : ISD->Sections)
- if (!isa<ARMExidxSentinelSection>(S))
- return false;
+ for (InputSection *IS : getInputSections(getParent()))
+ if (!isa<ARMExidxSentinelSection>(IS))
+ return false;
return true;
}
+bool ARMExidxSentinelSection::classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
+}
+
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
Config->Wordsize, ".text.thunk") {
@@ -2580,16 +2968,13 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
}
void ThunkSection::addThunk(Thunk *T) {
- uint64_t Off = alignTo(Size, T->Alignment);
- T->Offset = Off;
Thunks.push_back(T);
T->addSymbols(*this);
- Size = Off + T->size();
}
void ThunkSection::writeTo(uint8_t *Buf) {
- for (const Thunk *T : Thunks)
- T->writeTo(Buf + T->Offset, *this);
+ for (Thunk *T : Thunks)
+ T->writeTo(Buf + T->Offset);
}
InputSection *ThunkSection::getTargetInputSection() const {
@@ -2599,6 +2984,20 @@ InputSection *ThunkSection::getTargetInputSection() const {
return T->getTargetInputSection();
}
+bool ThunkSection::assignOffsets() {
+ uint64_t Off = 0;
+ for (Thunk *T : Thunks) {
+ Off = alignTo(Off, T->Alignment);
+ T->setOffset(Off);
+ uint32_t Size = T->size();
+ T->getThunkTargetSym()->Size = Size;
+ Off += Size;
+ }
+ bool Changed = Off != Size;
+ Size = Off;
+ return Changed;
+}
+
InputSection *InX::ARMAttributes;
BssSection *InX::Bss;
BssSection *InX::BssRelRo;
@@ -2620,16 +3019,22 @@ MipsRldMapSection *InX::MipsRldMap;
PltSection *InX::Plt;
PltSection *InX::Iplt;
RelocationBaseSection *InX::RelaDyn;
+RelrBaseSection *InX::RelrDyn;
RelocationBaseSection *InX::RelaPlt;
RelocationBaseSection *InX::RelaIplt;
StringTableSection *InX::ShStrTab;
StringTableSection *InX::StrTab;
SymbolTableBaseSection *InX::SymTab;
-template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
+
+template void elf::splitSections<ELF32LE>();
+template void elf::splitSections<ELF32BE>();
+template void elf::splitSections<ELF64LE>();
+template void elf::splitSections<ELF64BE>();
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
@@ -2641,6 +3046,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
@@ -2671,6 +3081,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>;
template class elf::AndroidPackedRelocationSection<ELF64LE>;
template class elf::AndroidPackedRelocationSection<ELF64BE>;
+template class elf::RelrSection<ELF32LE>;
+template class elf::RelrSection<ELF32BE>;
+template class elf::RelrSection<ELF64LE>;
+template class elf::RelrSection<ELF64BE>;
+
template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index a990590513bb..0366c6c3f8c7 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -26,10 +26,12 @@
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Endian.h"
#include <functional>
namespace lld {
namespace elf {
+class Defined;
class SharedSymbol;
class SyntheticSection : public InputSection {
@@ -51,7 +53,6 @@ public:
// If any additional finalization of contents are needed post thunk creation.
virtual void postThunkContents() {}
virtual bool empty() const { return false; }
- uint64_t getVA() const;
static bool classof(const SectionBase *D) {
return D->kind() == InputSectionBase::Synthetic;
@@ -78,13 +79,18 @@ public:
size_t NumFdes = 0;
struct FdeData {
- uint32_t Pc;
- uint32_t FdeVA;
+ uint32_t PcRel;
+ uint32_t FdeVARel;
};
std::vector<FdeData> getFdeData() const;
+ ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; }
private:
+ // This is used only when parsing EhInputSection. We keep it here to avoid
+ // allocating one for each EhInputSection.
+ llvm::DenseMap<size_t, CieRecord *> OffsetToCie;
+
uint64_t Size = 0;
template <class ELFT, class RelTy>
@@ -173,12 +179,21 @@ public:
bool updateAllocSize() override;
void finalizeContents() override;
bool empty() const override;
- void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr);
- bool addDynTlsEntry(Symbol &Sym);
- bool addTlsIndex();
- uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getGlobalDynOffset(const Symbol &B) const;
+
+ // Join separate GOTs built for each input file to generate
+ // primary and optional multiple secondary GOTs.
+ template <class ELFT> void build();
+
+ void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr);
+ void addDynTlsEntry(InputFile &File, Symbol &Sym);
+ void addTlsIndex(InputFile &File);
+
+ uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const;
+ uint64_t getTlsIndexOffset(const InputFile *F) const;
// 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
@@ -190,13 +205,8 @@ public:
// the number of reserved entries.
unsigned getLocalEntriesNum() const;
- // Returns offset of TLS part of the MIPS GOT table. This part goes
- // after 'local' and 'global' entries.
- uint64_t getTlsOffset() const;
-
- uint32_t getTlsIndexOff() const { return TlsIndexOff; }
-
- uint64_t getGp() const;
+ // Return _gp value for primary GOT (nullptr) or particular input file.
+ uint64_t getGp(const InputFile *F = nullptr) const;
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
@@ -235,32 +245,110 @@ private:
// addressing, but MIPS ABI requires that these entries be present in GOT.
// TLS entries:
// Entries created by TLS relocations.
+ //
+ // If the sum of local, global and tls entries is less than 64K only single
+ // got is enough. Otherwise, multi-got is created. Series of primary and
+ // multiple secondary GOTs have the following layout:
+ // - Primary GOT
+ // Header
+ // Local entries
+ // Global entries
+ // Relocation only entries
+ // TLS entries
+ //
+ // - Secondary GOT
+ // Local entries
+ // Global entries
+ // TLS entries
+ // ...
+ //
+ // All GOT entries required by relocations from a single input file entirely
+ // belong to either primary or one of secondary GOTs. To reference GOT entries
+ // each GOT has its own _gp value points to the "middle" of the GOT.
+ // In the code this value loaded to the register which is used for GOT access.
+ //
+ // MIPS 32 function's prologue:
+ // lui v0,0x0
+ // 0: R_MIPS_HI16 _gp_disp
+ // addiu v0,v0,0
+ // 4: R_MIPS_LO16 _gp_disp
+ //
+ // MIPS 64:
+ // lui at,0x0
+ // 14: R_MIPS_GPREL16 main
+ //
+ // Dynamic linker does not know anything about secondary GOTs and cannot
+ // use a regular MIPS mechanism for GOT entries initialization. So we have
+ // to use an approach accepted by other architectures and create dynamic
+ // relocations R_MIPS_REL32 to initialize global entries (and local in case
+ // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
+ // requires GOT entries and correspondingly ordered dynamic symbol table
+ // entries to deal with dynamic relocations. To handle this problem
+ // relocation-only section in the primary GOT contains entries for all
+ // symbols referenced in global parts of secondary GOTs. Although the sum
+ // of local and normal global entries of the primary got should be less
+ // than 64K, the size of the primary got (including relocation-only entries
+ // can be greater than 64K, because parts of the primary got that overflow
+ // the 64K limit are used only by the dynamic linker at dynamic link-time
+ // and not by 16-bit gp-relative addressing at run-time.
+ //
+ // For complete multi-GOT description see the following link
+ // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
// Number of "Header" entries.
static const unsigned HeaderEntriesNum = 2;
- // Number of allocated "Page" entries.
- uint32_t PageEntriesNum = 0;
- // Map output sections referenced by MIPS GOT relocations
- // to the first index of "Page" entries allocated for this section.
- llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
-
- typedef std::pair<const Symbol *, uint64_t> GotEntry;
- typedef std::vector<GotEntry> GotEntries;
- // Map from Symbol-Addend pair to the GOT index.
- llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
- // Local entries (16-bit access).
- GotEntries LocalEntries;
- // Local entries (32-bit access).
- GotEntries LocalEntries32;
-
- // Normal and reloc-only global entries.
- GotEntries GlobalEntries;
-
- // TLS entries.
- std::vector<const Symbol *> TlsEntries;
- uint32_t TlsIndexOff = -1;
uint64_t Size = 0;
+
+ size_t LocalEntriesNum = 0;
+
+ // Symbol and addend.
+ typedef std::pair<Symbol *, int64_t> GotEntry;
+
+ struct FileGot {
+ InputFile *File = nullptr;
+ size_t StartIndex = 0;
+
+ struct PageBlock {
+ size_t FirstIndex = 0;
+ size_t Count = 0;
+ };
+
+ // Map output sections referenced by MIPS GOT relocations
+ // to the description (index/count) "page" entries allocated
+ // for this section.
+ llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap;
+ // Maps from Symbol+Addend pair or just Symbol to the GOT entry index.
+ llvm::MapVector<GotEntry, size_t> Local16;
+ llvm::MapVector<GotEntry, size_t> Local32;
+ llvm::MapVector<Symbol *, size_t> Global;
+ llvm::MapVector<Symbol *, size_t> Relocs;
+ llvm::MapVector<Symbol *, size_t> Tls;
+ // Set of symbols referenced by dynamic TLS relocations.
+ llvm::MapVector<Symbol *, size_t> DynTlsSymbols;
+
+ // Total number of all entries.
+ size_t getEntriesNum() const;
+ // Number of "page" entries.
+ size_t getPageEntriesNum() const;
+ // Number of entries require 16-bit index to access.
+ size_t getIndexedEntriesNum() const;
+
+ bool isOverflow() const;
+ };
+
+ // Container of GOT created for each input file.
+ // After building a final series of GOTs this container
+ // holds primary and secondary GOT's.
+ std::vector<FileGot> Gots;
+
+ // Return (and create if necessary) `FileGot`.
+ FileGot &getGot(InputFile &F);
+
+ // Try to merge two GOTs. In case of success the `Dst` contains
+ // result of merging and the function returns true. In case of
+ // ovwerflow the `Dst` is unchanged and the function returns false.
+ bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary);
};
class GotPltSection final : public SyntheticSection {
@@ -269,7 +357,7 @@ public:
void addEntry(Symbol &Sym);
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
- bool empty() const override { return Entries.empty(); }
+ bool empty() const override;
private:
std::vector<const Symbol *> Entries;
@@ -310,30 +398,48 @@ private:
class DynamicReloc {
public:
- DynamicReloc(uint32_t Type, const InputSectionBase *InputSec,
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
- UseSymVA(UseSymVA), Addend(Addend) {}
+ UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {}
+ // This constructor records dynamic relocation settings used by MIPS
+ // multi-GOT implementation. It's to relocate addresses of 64kb pages
+ // lie inside the output section.
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, const OutputSection *OutputSec,
+ int64_t Addend)
+ : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {}
uint64_t getOffset() const;
- int64_t getAddend() const;
uint32_t getSymIndex() const;
const InputSectionBase *getInputSec() const { return InputSec; }
- uint32_t Type;
+ // Computes the addend of the dynamic relocation. Note that this is not the
+ // same as the Addend member variable as it also includes the symbol address
+ // if UseSymVA is true.
+ int64_t computeAddend() const;
+
+ RelType Type;
private:
Symbol *Sym;
const InputSectionBase *InputSec = nullptr;
uint64_t OffsetInSec;
+ // If this member is true, the dynamic relocation will not be against the
+ // symbol but will instead be a relative relocation that simply adds the
+ // load address. This means we need to write the symbol virtual address
+ // plus the original addend as the final relocation addend.
bool UseSymVA;
int64_t Addend;
+ const OutputSection *OutputSec;
};
template <class ELFT> class DynamicSection final : public SyntheticSection {
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::Relr Elf_Relr;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
@@ -350,6 +456,7 @@ private:
void add(int32_t Tag, std::function<uint64_t()> Fn);
void addInt(int32_t Tag, uint64_t Val);
void addInSec(int32_t Tag, InputSection *Sec);
+ void addInSecRelative(int32_t Tag, InputSection *Sec);
void addOutSec(int32_t Tag, OutputSection *Sec);
void addSize(int32_t Tag, OutputSection *Sec);
void addSym(int32_t Tag, Symbol *Sym);
@@ -361,6 +468,13 @@ class RelocationBaseSection : public SyntheticSection {
public:
RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag,
int32_t SizeDynamicTag);
+ void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym);
+ // Add a dynamic relocation that might need an addend. This takes care of
+ // writing the addend to the output section if needed.
+ void addReloc(RelType DynType, InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type);
void addReloc(const DynamicReloc &Reloc);
bool empty() const override { return Relocs.empty(); }
size_t getSize() const override { return Relocs.size() * this->Entsize; }
@@ -405,6 +519,39 @@ private:
SmallVector<char, 0> RelocData;
};
+struct RelativeReloc {
+ uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); }
+
+ const InputSectionBase *InputSec;
+ uint64_t OffsetInSec;
+};
+
+class RelrBaseSection : public SyntheticSection {
+public:
+ RelrBaseSection();
+ std::vector<RelativeReloc> Relocs;
+};
+
+// RelrSection is used to encode offsets for relative relocations.
+// Proposal for adding SHT_RELR sections to generic-abi is here:
+// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+// For more details, see the comment in RelrSection::updateAllocSize().
+template <class ELFT> class RelrSection final : public RelrBaseSection {
+ typedef typename ELFT::Relr Elf_Relr;
+
+public:
+ RelrSection();
+
+ bool updateAllocSize() override;
+ size_t getSize() const override { return RelrRelocs.size() * this->Entsize; }
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf, RelrRelocs.data(), getSize());
+ }
+
+private:
+ std::vector<Elf_Relr> RelrRelocs;
+};
+
struct SymbolTableEntry {
Symbol *Sym;
size_t StrTabOffset;
@@ -455,7 +602,7 @@ public:
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
- size_t getShift2() const { return Config->Is64 ? 6 : 5; }
+ enum { Shift2 = 6 };
void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
@@ -484,13 +631,13 @@ private:
size_t Size = 0;
};
-// The PltSection is used for both the Plt and Iplt. The former always has a
+// The PltSection is used for both the Plt and Iplt. The former usually has a
// header as its first entry that is used at run-time to resolve lazy binding.
// The latter is used for GNU Ifunc symbols, that will be subject to a
// Target->IRelativeRel.
class PltSection : public SyntheticSection {
public:
- PltSection(size_t HeaderSize);
+ PltSection(bool IsIplt);
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
bool empty() const override { return Entries.empty(); }
@@ -501,13 +648,12 @@ public:
private:
unsigned getPltRelocOff() const;
std::vector<std::pair<const Symbol *, unsigned>> Entries;
- // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero
size_t HeaderSize;
+ bool IsIplt;
};
-// GdbIndexChunk is created for each .debug_info section and contains
-// information to create a part of .gdb_index for a given input section.
-struct GdbIndexChunk {
+class GdbIndexSection final : public SyntheticSection {
+public:
struct AddressEntry {
InputSection *Section;
uint64_t LowAddress;
@@ -522,59 +668,51 @@ struct GdbIndexChunk {
struct NameTypeEntry {
llvm::CachedHashStringRef Name;
- uint8_t Type;
+ uint32_t Type;
};
- InputSection *DebugInfoSec;
- std::vector<AddressEntry> AddressAreas;
- std::vector<CuEntry> CompilationUnits;
- std::vector<NameTypeEntry> NamesAndTypes;
-};
+ struct GdbChunk {
+ InputSection *Sec;
+ std::vector<AddressEntry> AddressAreas;
+ std::vector<CuEntry> CompilationUnits;
+ };
-// The symbol type for the .gdb_index section.
-struct GdbSymbol {
- uint32_t NameHash;
- size_t NameOffset;
- size_t CuVectorIndex;
-};
+ struct GdbSymbol {
+ llvm::CachedHashStringRef Name;
+ std::vector<uint32_t> CuVector;
+ uint32_t NameOff;
+ uint32_t CuVectorOff;
+ };
-class GdbIndexSection final : public SyntheticSection {
-public:
- GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
+ GdbIndexSection();
+ template <typename ELFT> static GdbIndexSection *create();
void writeTo(uint8_t *Buf) override;
- size_t getSize() const override;
+ size_t getSize() const override { return Size; }
bool empty() const override;
private:
- void fixCuIndex();
- std::vector<std::vector<uint32_t>> createCuVectors();
- std::vector<GdbSymbol *> createGdbSymtab();
-
- // A symbol table for this .gdb_index section.
- std::vector<GdbSymbol *> GdbSymtab;
-
- // CU vector is a part of constant pool area of section.
- std::vector<std::vector<uint32_t>> CuVectors;
+ struct GdbIndexHeader {
+ llvm::support::ulittle32_t Version;
+ llvm::support::ulittle32_t CuListOff;
+ llvm::support::ulittle32_t CuTypesOff;
+ llvm::support::ulittle32_t AddressAreaOff;
+ llvm::support::ulittle32_t SymtabOff;
+ llvm::support::ulittle32_t ConstantPoolOff;
+ };
- // Symbol table contents.
- llvm::DenseMap<llvm::CachedHashStringRef, GdbSymbol *> Symbols;
+ void initOutputSize();
+ size_t computeSymtabSize() const;
- // Each chunk contains information gathered from a debug sections of single
- // object and used to build different areas of gdb index.
- std::vector<GdbIndexChunk> Chunks;
+ // Each chunk contains information gathered from debug sections of a
+ // single object file.
+ std::vector<GdbChunk> Chunks;
- static constexpr uint32_t CuListOffset = 24;
- uint32_t CuTypesOffset;
- uint32_t SymtabOffset;
- uint32_t ConstantPoolOffset;
- uint32_t StringPoolOffset;
- uint32_t StringPoolSize;
+ // A symbol table for this .gdb_index section.
+ std::vector<GdbSymbol> Symbols;
- std::vector<size_t> CuVectorOffsets;
+ size_t Size;
};
-template <class ELFT> GdbIndexSection *createGdbIndex();
-
// --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.
@@ -653,7 +791,7 @@ template <class ELFT> class VersionNeedSection final : public SyntheticSection {
public:
VersionNeedSection();
- void addSymbol(SharedSymbol *SS);
+ void addSymbol(Symbol *Sym);
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
@@ -668,13 +806,12 @@ public:
class MergeSyntheticSection : public SyntheticSection {
public:
void addSection(MergeInputSection *MS);
+ std::vector<MergeInputSection *> Sections;
protected:
MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
uint32_t Alignment)
: SyntheticSection(Flags, Type, Alignment, Name) {}
-
- std::vector<MergeInputSection *> Sections;
};
class MergeTailSection final : public MergeSyntheticSection {
@@ -787,7 +924,12 @@ public:
void writeTo(uint8_t *Buf) override;
bool empty() const override;
- InputSection *Highest = 0;
+ static bool classof(const SectionBase *D);
+
+ // The last section referenced by a regular .ARM.exidx section.
+ // It is found and filled in Writer<ELFT>::resolveShfLinkOrder().
+ // The sentinel points at the end of that section.
+ InputSection *Highest = nullptr;
};
// A container for one or more linker generated thunks. Instances of these
@@ -805,19 +947,21 @@ public:
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
InputSection *getTargetInputSection() const;
+ bool assignOffsets();
private:
- std::vector<const Thunk *> Thunks;
+ std::vector<Thunk *> Thunks;
size_t Size = 0;
};
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
void decompressSections();
+template <class ELFT> void splitSections();
void mergeSections();
-Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
- uint64_t Size, InputSectionBase &Section);
+Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section);
// Linker generated sections which can be used as inputs.
struct InX {
@@ -842,6 +986,7 @@ struct InX {
static PltSection *Plt;
static PltSection *Iplt;
static RelocationBaseSection *RelaDyn;
+ static RelrBaseSection *RelrDyn;
static RelocationBaseSection *RelaPlt;
static RelocationBaseSection *RelaIplt;
static StringTableSection *ShStrTab;
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index b528fd583c1a..815f3a045551 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -60,6 +60,8 @@ TargetInfo *elf::getTarget() {
return getARMTargetInfo();
case EM_AVR:
return getAVRTargetInfo();
+ case EM_HEXAGON:
+ return getHexagonTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
@@ -87,29 +89,29 @@ TargetInfo *elf::getTarget() {
fatal("unknown target machine");
}
-template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
+template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
for (InputSectionBase *D : InputSections) {
- auto *IS = dyn_cast<InputSection>(D);
- if (!IS || !IS->getParent())
+ auto *IS = cast<InputSection>(D);
+ if (!IS->getParent())
continue;
uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
- return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
+ return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
}
- return "";
+ return {};
}
-std::string elf::getErrorLocation(const uint8_t *Loc) {
+ErrorPlace elf::getErrorPlace(const uint8_t *Loc) {
switch (Config->EKind) {
case ELF32LEKind:
- return getErrorLoc<ELF32LE>(Loc);
+ return getErrPlace<ELF32LE>(Loc);
case ELF32BEKind:
- return getErrorLoc<ELF32BE>(Loc);
+ return getErrPlace<ELF32BE>(Loc);
case ELF64LEKind:
- return getErrorLoc<ELF64LE>(Loc);
+ return getErrPlace<ELF64LE>(Loc);
case ELF64BEKind:
- return getErrorLoc<ELF64BE>(Loc);
+ return getErrPlace<ELF64BE>(Loc);
default:
llvm_unreachable("unknown ELF type");
}
@@ -128,6 +130,12 @@ bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+
bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
return true;
}
diff --git a/ELF/Target.h b/ELF/Target.h
index 1f58adba1817..82c7b8f7b6c5 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -25,9 +25,9 @@ class Symbol;
class TargetInfo {
public:
virtual uint32_t calcEFlags() const { return 0; }
- virtual bool isPicRel(RelType Type) const { return true; }
virtual RelType getDynRel(RelType Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
+ virtual void writeGotHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {};
virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const;
virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const;
@@ -43,8 +43,12 @@ public:
virtual void addPltHeaderSymbols(InputSection &IS) const {}
virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {}
+ unsigned getPltEntryOffset(unsigned Index) const {
+ return Index * PltEntrySize + PltHeaderSize;
+ }
+
// 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
+ // all those bits are 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.
@@ -55,6 +59,13 @@ public:
virtual bool needsThunk(RelExpr Expr, RelType RelocType,
const InputFile *File, uint64_t BranchAddr,
const Symbol &S) const;
+
+ // The function with a prologue starting at Loc was compiled with
+ // -fsplit-stack and it calls a function compiled without. Adjust the prologue
+ // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks.
+ virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const;
+
// Return true if we can reach Dst from Src with Relocation RelocType
virtual bool inBranchRange(RelType Type, uint64_t Src,
uint64_t Dst) const;
@@ -71,9 +82,10 @@ public:
uint64_t getImageBase();
- // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
- // end of .got
+ // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section.
uint64_t GotBaseSymOff = 0;
+ // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got.
+ bool GotBaseSymInGotPlt = true;
// On systems with range extensions we place collections of Thunks at
// regular spacings that enable the majority of branches reach the Thunks.
@@ -97,9 +109,18 @@ public:
// to support lazy loading.
unsigned GotPltHeaderEntriesNum = 3;
- // Set to 0 for variant 2
+ // On PPC ELF V2 abi, the first entry in the .got is the .TOC.
+ unsigned GotHeaderEntriesNum = 0;
+
+ // For TLS variant 1, the TCB is a fixed size specified by the Target.
+ // For variant 2, the TCB is an unspecified size.
+ // Set to 0 for variant 2.
unsigned TcbSize = 0;
+ // Set to the offset (in bytes) that the thread pointer is initialized to
+ // point to, relative to the start of the thread local storage.
+ unsigned TlsTpOffset = 0;
+
bool NeedsThunks = false;
// A 4-byte field corresponding to one or more trap instructions, used to pad
@@ -126,6 +147,7 @@ TargetInfo *getAArch64TargetInfo();
TargetInfo *getAMDGPUTargetInfo();
TargetInfo *getARMTargetInfo();
TargetInfo *getAVRTargetInfo();
+TargetInfo *getHexagonTargetInfo();
TargetInfo *getPPC64TargetInfo();
TargetInfo *getPPCTargetInfo();
TargetInfo *getSPARCV9TargetInfo();
@@ -134,7 +156,17 @@ TargetInfo *getX86TargetInfo();
TargetInfo *getX86_64TargetInfo();
template <class ELFT> TargetInfo *getMipsTargetInfo();
-std::string getErrorLocation(const uint8_t *Loc);
+struct ErrorPlace {
+ InputSectionBase *IS;
+ std::string Loc;
+};
+
+// Returns input section and corresponding source string for the given location.
+ErrorPlace getErrorPlace(const uint8_t *Loc);
+
+static inline std::string getErrorLocation(const uint8_t *Loc) {
+ return getErrorPlace(Loc).Loc;
+}
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
@@ -146,39 +178,74 @@ template <class ELFT> bool isMipsPIC(const Defined *Sym);
static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V,
int64_t Min, uint64_t Max) {
- error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
- " out of range: " + V + " is not in [" + Twine(Min) + ", " +
- Twine(Max) + "]");
+ ErrorPlace ErrPlace = getErrorPlace(Loc);
+ StringRef Hint;
+ if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug"))
+ Hint = "; consider recompiling with -fdebug-types-section to reduce size "
+ "of debug sections";
+
+ error(ErrPlace.Loc + "relocation " + lld::toString(Type) +
+ " out of range: " + V.str() + " is not in [" + Twine(Min).str() + ", " +
+ Twine(Max).str() + "]" + Hint);
}
-template <unsigned N>
-static void checkInt(uint8_t *Loc, int64_t V, RelType Type) {
- if (!llvm::isInt<N>(V))
+// Sign-extend Nth bit all the way to MSB.
+inline int64_t signExtend(uint64_t V, int N) {
+ return int64_t(V << (64 - N)) >> (64 - N);
+}
+
+// Make sure that V can be represented as an N bit signed integer.
+inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) {
+ if (V != signExtend(V, N))
reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N));
}
-template <unsigned N>
-static void checkUInt(uint8_t *Loc, uint64_t V, RelType Type) {
- if (!llvm::isUInt<N>(V))
+// Make sure that V can be represented as an N bit unsigned integer.
+inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ if ((V >> N) != 0)
reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N));
}
-template <unsigned N>
-static void checkIntUInt(uint8_t *Loc, uint64_t V, RelType Type) {
- if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V))
- // For the error message we should cast V to a signed integer so that error
- // messages show a small negative value rather than an extremely large one
+// Make sure that V can be represented as an N bit signed or unsigned integer.
+inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ // For the error message we should cast V to a signed integer so that error
+ // messages show a small negative value rather than an extremely large one
+ if (V != (uint64_t)signExtend(V, N) && (V >> N) != 0)
reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N),
- llvm::maxUIntN(N));
+ llvm::maxIntN(N));
}
-template <unsigned N>
-static void checkAlignment(uint8_t *Loc, uint64_t V, RelType Type) {
+inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) {
if ((V & (N - 1)) != 0)
error(getErrorLocation(Loc) + "improper alignment for relocation " +
lld::toString(Type) + ": 0x" + llvm::utohexstr(V) +
" is not aligned to " + Twine(N) + " bytes");
}
+
+// Endianness-aware read/write.
+inline uint16_t read16(const void *P) {
+ return llvm::support::endian::read16(P, Config->Endianness);
+}
+
+inline uint32_t read32(const void *P) {
+ return llvm::support::endian::read32(P, Config->Endianness);
+}
+
+inline uint64_t read64(const void *P) {
+ return llvm::support::endian::read64(P, Config->Endianness);
+}
+
+inline void write16(void *P, uint16_t V) {
+ llvm::support::endian::write16(P, V, Config->Endianness);
+}
+
+inline void write32(void *P, uint32_t V) {
+ llvm::support::endian::write32(P, V, Config->Endianness);
+}
+
+inline void write64(void *P, uint64_t V) {
+ llvm::support::endian::write64(P, V, Config->Endianness);
+}
} // namespace elf
} // namespace lld
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index b0bbf6da705a..2cd7e51ae357 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -40,7 +40,6 @@
using namespace llvm;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
namespace lld {
@@ -52,59 +51,112 @@ namespace {
class AArch64ABSLongThunk final : public Thunk {
public:
AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
};
class AArch64ADRPThunk final : public Thunk {
public:
AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
};
+// Base class for ARM thunks.
+//
+// An ARM thunk may be either short or long. A short thunk is simply a branch
+// (B) instruction, and it may be used to call ARM functions when the distance
+// from the thunk to the target is less than 32MB. Long thunks can branch to any
+// virtual address and can switch between ARM and Thumb, and they are
+// implemented in the derived classes. This class tries to create a short thunk
+// if the target is in range, otherwise it creates a long thunk.
+class ARMThunk : public Thunk {
+public:
+ ARMThunk(Symbol &Dest) : Thunk(Dest) {}
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // This field tracks whether all previously considered layouts would allow
+ // this thunk to be short. If we have ever needed a long thunk, we always
+ // create a long thunk, even if the thunk may be short given the current
+ // distance to the target. We do this because transitioning from long to short
+ // can create layout oscillations in certain corner cases which would prevent
+ // the layout from converging.
+ bool MayUseShortThunk = true;
+};
+
+// Base class for Thumb-2 thunks.
+//
+// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
+// which has a range of 16MB.
+class ThumbThunk : public Thunk {
+public:
+ ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // See comment in ARMThunk above.
+ bool MayUseShortThunk = true;
+};
+
// Specific ARM Thunk implementations. The naming convention is:
// Source State, TargetState, Target Requirement, ABS or PI, Range
-class ARMV7ABSLongThunk final : public Thunk {
+class ARMV7ABSLongThunk final : public ARMThunk {
public:
- ARMV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
+ ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ARMV7PILongThunk final : public Thunk {
+class ARMV7PILongThunk final : public ARMThunk {
public:
- ARMV7PILongThunk(Symbol &Dest) : Thunk(Dest) {}
+ ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ThumbV7ABSLongThunk final : public Thunk {
+class ThumbV7ABSLongThunk final : public ThumbThunk {
public:
- ThumbV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+ ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
- uint32_t size() const override { return 10; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 10; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ThumbV7PILongThunk final : public Thunk {
+class ThumbV7PILongThunk final : public ThumbThunk {
public:
- ThumbV7PILongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+ ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
// MIPS LA25 thunk
@@ -112,8 +164,8 @@ class MipsThunk final : public Thunk {
public:
MipsThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
@@ -123,8 +175,8 @@ class MicroMipsThunk final : public Thunk {
public:
MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 14; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 14; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
@@ -134,14 +186,44 @@ class MicroMipsR6Thunk final : public Thunk {
public:
MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
+
+// PPC64 Plt call stubs.
+// Any call site that needs to call through a plt entry needs a call stub in
+// the .text section. The call stub is responsible for:
+// 1) Saving the toc-pointer to the stack.
+// 2) Loading the target functions address from the procedure linkage table into
+// r12 for use by the target functions global entry point, and into the count
+// register.
+// 3) Transfering control to the target function through an indirect branch.
+class PPC64PltCallStub final : public Thunk {
+public:
+ PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 20; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
} // end anonymous namespace
+Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section) {
+ Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section);
+ Syms.push_back(D);
+ return D;
+}
+
+void Thunk::setOffset(uint64_t NewOffset) {
+ for (Defined *D : Syms)
+ D->Value = D->Value - Offset + NewOffset;
+ Offset = NewOffset;
+}
+
// AArch64 long range Thunks
static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
@@ -149,7 +231,7 @@ static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
return V;
}
-void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void AArch64ABSLongThunk::writeTo(uint8_t *Buf) {
const uint8_t Data[] = {
0x50, 0x00, 0x00, 0x58, // ldr x16, L0
0x00, 0x02, 0x1f, 0xd6, // br x16
@@ -162,11 +244,10 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
- addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS);
+ addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
}
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
@@ -174,26 +255,24 @@ void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
// clang and gcc do not support the large code model for position independent
// code so it is safe to use this for position independent thunks without
// worrying about the destination being more than 4Gb away.
-void AArch64ADRPThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
const uint8_t Data[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
0x00, 0x02, 0x1f, 0xd6, // br x16
};
uint64_t S = getAArch64ThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA();
+ uint64_t P = getThunkTargetSym()->getVA();
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(S) - getAArch64Page(P));
Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S);
}
-void AArch64ADRPThunk::addSymbols(ThunkSection &IS)
-{
- ThunkSym = addSyntheticLocal(
- Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
+void AArch64ADRPThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
}
// ARM Target Thunks
@@ -202,7 +281,81 @@ static uint64_t getARMThunkDestVA(const Symbol &S) {
return SignExtend64<32>(V);
}
-void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+// This function returns true if the target is not Thumb and is within 2^26, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ARMThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if (S & 1) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ MayUseShortThunk = llvm::isInt<26>(Offset);
+ return MayUseShortThunk;
+}
+
+void ARMThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ const uint8_t Data[] = {
+ 0x00, 0x00, 0x00, 0xea, // b S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_JUMP24, Offset);
+}
+
+bool ARMThunk::isCompatibleWith(RelType Type) const {
+ // Thumb branch relocations can't use BLX
+ return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
+}
+
+// This function returns true if the target is Thumb and is within 2^25, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ThumbThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if ((S & 1) == 0) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA() & ~1;
+ int64_t Offset = S - P - 4;
+ MayUseShortThunk = llvm::isInt<25>(Offset);
+ return MayUseShortThunk;
+}
+
+void ThumbThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 4;
+ const uint8_t Data[] = {
+ 0x00, 0xf0, 0x00, 0xb0, // b.w S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset);
+}
+
+bool ThumbThunk::isCompatibleWith(RelType Type) const {
+ // ARM branch relocations can't use BLX
+ return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
+}
+
+void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
@@ -215,18 +368,12 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
-}
-
-bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const {
- // Thumb branch relocations can't use BLX
- return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
+ addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
}
-void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
@@ -239,18 +386,12 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
- Offset | 0x1, size(), IS);
- addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
+ addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
}
-bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const {
- // ARM branch relocations can't use BLX
- return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
-}
-
-void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ARMV7PILongThunk::writeLong(uint8_t *Buf) {
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) + 8)
@@ -258,7 +399,7 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
0x1c, 0xff, 0x2f, 0xe1, // bx r12
};
uint64_t S = getARMThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA();
+ uint64_t P = getThunkTargetSym()->getVA();
uint64_t Offset = S - P - 16;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
@@ -266,18 +407,12 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
+ addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
}
-bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const {
- // Thumb branch relocations can't use BLX
- return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
-}
-
-void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ThumbV7PILongThunk::writeLong(uint8_t *Buf) {
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)
@@ -285,7 +420,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
0x60, 0x47, // bx r12
};
uint64_t S = getARMThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA() & ~0x1;
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
uint64_t Offset = S - P - 12;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
@@ -293,32 +428,25 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
- Offset | 0x1, size(), IS);
- addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
-}
-
-bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const {
- // ARM branch relocations can't use BLX
- return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
+ addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
}
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
-void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA();
- write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func)
- write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func
- write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
- write32(Buf + 12, 0x00000000, Config->Endianness); // nop
+ write32(Buf, 0x3c190000); // lui $25, %hi(func)
+ write32(Buf + 4, 0x08000000 | (S >> 2)); // j func
+ write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
+ write32(Buf + 12, 0x00000000); // nop
Target->relocateOne(Buf, R_MIPS_HI16, S);
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
}
void MipsThunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
+ addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0,
+ IS);
}
InputSection *MipsThunk::getTargetInputSection() const {
@@ -328,22 +456,21 @@ InputSection *MipsThunk::getTargetInputSection() const {
// Write microMIPS R2-R5 LA25 thunk code
// to call PIC function from the non-PIC one.
-void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MicroMipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA() | 1;
- write16(Buf, 0x41b9, Config->Endianness); // lui $25, %hi(func)
- write16(Buf + 4, 0xd400, Config->Endianness); // j func
- write16(Buf + 8, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
- write16(Buf + 12, 0x0c00, Config->Endianness); // nop
+ write16(Buf, 0x41b9); // lui $25, %hi(func)
+ write16(Buf + 4, 0xd400); // j func
+ write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 12, 0x0c00); // nop
Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S);
Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S);
}
void MicroMipsThunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
- ThunkSym->StOther |= STO_MIPS_MICROMIPS;
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsThunk::getTargetInputSection() const {
@@ -353,22 +480,21 @@ InputSection *MicroMipsThunk::getTargetInputSection() const {
// Write microMIPS R6 LA25 thunk code
// to call PIC function from the non-PIC one.
-void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA() | 1;
- uint64_t P = ThunkSym->getVA();
- write16(Buf, 0x1320, Config->Endianness); // lui $25, %hi(func)
- write16(Buf + 4, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
- write16(Buf + 8, 0x9400, Config->Endianness); // bc func
+ uint64_t P = getThunkTargetSym()->getVA();
+ write16(Buf, 0x1320); // lui $25, %hi(func)
+ write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 8, 0x9400); // bc func
Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S);
Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12);
}
void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
- ThunkSym->StOther |= STO_MIPS_MICROMIPS;
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
@@ -376,6 +502,25 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
return dyn_cast<InputSection>(DR.Section);
}
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Off = Destination.getGotPltVA() - getPPC64TocBase();
+ // Need to add 0x8000 to offset to account for the low bits being signed.
+ uint16_t OffHa = (Off + 0x8000) >> 16;
+ uint16_t OffLo = Off;
+
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ write32(Buf + 4, 0x3d820000 | OffHa); // addis r12,r2, X@plt@to@ha
+ write32(Buf + 8, 0xe98c0000 | OffLo); // ld r12,X@plt@toc@l(r12)
+ write32(Buf + 12, 0x7d8903a6); // mtctr r12
+ write32(Buf + 16, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
+ Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ S->NeedsTocRestore = true;
+}
+
Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@@ -419,15 +564,26 @@ static Thunk *addThunkMips(RelType Type, Symbol &S) {
return make<MipsThunk>(S);
}
+static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
+ if (Type == R_PPC64_REL24)
+ return make<PPC64PltCallStub>(S);
+ fatal("unexpected relocation type");
+}
+
Thunk *addThunk(RelType Type, Symbol &S) {
if (Config->EMachine == EM_AARCH64)
return addThunkAArch64(Type, S);
- else if (Config->EMachine == EM_ARM)
+
+ if (Config->EMachine == EM_ARM)
return addThunkArm(Type, S);
- else if (Config->EMachine == EM_MIPS)
+
+ if (Config->EMachine == EM_MIPS)
return addThunkMips(Type, S);
- llvm_unreachable("add Thunk only supported for ARM and Mips");
- return nullptr;
+
+ if (Config->EMachine == EM_PPC64)
+ return addThunkPPC64(Type, S);
+
+ llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
}
} // end namespace elf
diff --git a/ELF/Thunks.h b/ELF/Thunks.h
index 828fac0bf53b..ed82b4d946ac 100644
--- a/ELF/Thunks.h
+++ b/ELF/Thunks.h
@@ -14,6 +14,7 @@
namespace lld {
namespace elf {
+class Defined;
class Symbol;
class ThunkSection;
// Class to describe an instance of a Thunk.
@@ -30,12 +31,17 @@ public:
Thunk(Symbol &Destination);
virtual ~Thunk();
- virtual uint32_t size() const { return 0; }
- virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {}
+ virtual uint32_t size() = 0;
+ virtual void writeTo(uint8_t *Buf) = 0;
- // All Thunks must define at least one symbol ThunkSym so that we can
- // redirect relocations to it.
- virtual void addSymbols(ThunkSection &IS) {}
+ // All Thunks must define at least one symbol, known as the thunk target
+ // symbol, so that we can redirect relocations to it. The thunk may define
+ // additional symbols, but these are never targets for relocations.
+ virtual void addSymbols(ThunkSection &IS) = 0;
+
+ void setOffset(uint64_t Offset);
+ Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section);
// Some Thunks must be placed immediately before their Target as they elide
// a branch and fall through to the first Symbol in the Target.
@@ -45,10 +51,12 @@ public:
// compatible with it.
virtual bool isCompatibleWith(RelType Type) const { return true; }
+ Defined *getThunkTargetSym() const { return Syms[0]; }
+
// The alignment requirement for this Thunk, defaults to the size of the
// typical code section alignment.
Symbol &Destination;
- Symbol *ThunkSym;
+ llvm::SmallVector<Defined *, 3> Syms;
uint64_t Offset = 0;
uint32_t Alignment = 4;
};
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 15f382104756..533ac47f937f 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -9,18 +9,19 @@
#include "Writer.h"
#include "AArch64ErrataFix.h"
+#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
#include "MapFile.h"
#include "OutputSections.h"
#include "Relocations.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
@@ -49,7 +50,7 @@ public:
private:
void copyLocalSymbols();
void addSectionSymbols();
- void forEachRelSec(std::function<void(InputSectionBase &)> Fn);
+ void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
void sortInputSections();
@@ -62,6 +63,7 @@ private:
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
+ void checkSections();
void fixSectionAlignments();
void openFile();
void writeTrapInstr();
@@ -81,39 +83,48 @@ private:
uint64_t FileSize;
uint64_t SectionHeaderOff;
-
- bool HasGotBaseSym = false;
};
} // anonymous namespace
-StringRef elf::getOutputSectionName(InputSectionBase *S) {
- // ".zdebug_" is a prefix for ZLIB-compressed sections.
- // Because we decompressed input sections, we want to remove 'z'.
- if (S->Name.startswith(".zdebug_"))
- return Saver.save("." + S->Name.substr(2));
+static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
+ return Name.startswith(Prefix) || Name == Prefix.drop_back();
+}
+StringRef elf::getOutputSectionName(const InputSectionBase *S) {
if (Config->Relocatable)
return S->Name;
// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
- if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
- !isa<SyntheticSection>(S)) {
- OutputSection *Out =
- cast<InputSection>(S)->getRelocatedSection()->getOutputSection();
- if (S->Type == SHT_RELA)
- return Saver.save(".rela" + Out->Name);
- return Saver.save(".rel" + Out->Name);
+ if (auto *IS = dyn_cast<InputSection>(S)) {
+ if (InputSectionBase *Rel = IS->getRelocatedSection()) {
+ OutputSection *Out = Rel->getOutputSection();
+ if (S->Type == SHT_RELA)
+ return Saver.save(".rela" + Out->Name);
+ return Saver.save(".rel" + Out->Name);
+ }
}
+ // This check is for -z keep-text-section-prefix. This option separates text
+ // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
+ // ".text.exit".
+ // When enabled, this allows identifying the hot code region (.text.hot) in
+ // the final binary which can be selectively mapped to huge pages or mlocked,
+ // for instance.
+ if (Config->ZKeepTextSectionPrefix)
+ for (StringRef V :
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+ }
+
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
- StringRef Prefix = V.drop_back();
- if (S->Name.startswith(V) || S->Name == Prefix)
- return Prefix;
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
}
// CommonSection is identified as "COMMON" in linker scripts.
@@ -194,21 +205,30 @@ void elf::addReservedSymbols() {
Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
}
+ // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
+ // combines the typical ELF GOT with the small data sections. It commonly
+ // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
+ // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
+ // represent the TOC base which is offset by 0x8000 bytes from the start of
+ // the .got section.
ElfSym::GlobalOffsetTable = addOptionalRegular(
- "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff);
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
+ Out::ElfHeader, Target->GotBaseSymOff);
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
+ addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __executable_start is not documented, but the expectation of at
- // least the android libc is that it points to the elf header too.
+ // least the Android libc is that it points to the ELF header.
+ addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __dso_handle symbol is passed to cxa_finalize as a marker to identify
// each DSO. The address of the symbol doesn't matter as long as they are
// different in different DSOs, so we chose the start address of the DSO.
- for (const char *Name :
- {"__ehdr_start", "__executable_start", "__dso_handle"})
- addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN);
+ addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN);
// If linker script do layout we do not need to create any standart symbols.
if (Script->HasSectionsCommand)
@@ -280,10 +300,9 @@ template <class ELFT> static void createSyntheticSections() {
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
// This makes sure our relro is contiguous.
- bool HasDataRelRo =
- Script->HasSectionsCommand && findSection(".data.rel.ro");
- InX::BssRelRo = make<BssSection>(
- HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
+ bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
+ InX::BssRelRo =
+ make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
Add(InX::BssRelRo);
// Add MIPS-specific sections.
@@ -330,6 +349,11 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::RelaDyn);
}
+ if (Config->RelrPackDynRelocs) {
+ InX::RelrDyn = make<RelrSection<ELFT>>();
+ Add(InX::RelrDyn);
+ }
+
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
@@ -346,7 +370,7 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = createGdbIndex<ELFT>();
+ InX::GdbIndex = GdbIndexSection::create<ELFT>();
Add(InX::GdbIndex);
}
@@ -369,9 +393,9 @@ template <class ELFT> static void createSyntheticSections() {
false /*Sort*/);
Add(InX::RelaIplt);
- InX::Plt = make<PltSection>(Target->PltHeaderSize);
+ InX::Plt = make<PltSection>(false);
Add(InX::Plt);
- InX::Iplt = make<PltSection>(0);
+ InX::Iplt = make<PltSection>(true);
Add(InX::Iplt);
if (!Config->Relocatable) {
@@ -427,13 +451,14 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
+ Script->assignAddresses();
+
// If -compressed-debug-sections is specified, we need to compress
// .debug_* sections. Do it right now because it changes the size of
// output sections.
- parallelForEach(OutputSections,
- [](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); });
+ for (OutputSection *Sec : OutputSections)
+ Sec->maybeCompress<ELFT>();
- Script->assignAddresses();
Script->allocateHeaders(Phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
@@ -453,6 +478,9 @@ template <class ELFT> void Writer<ELFT>::run() {
Sec->Addr = 0;
}
+ if (Config->CheckSections)
+ checkSections();
+
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
@@ -475,8 +503,9 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
- // Handle -Map option.
+ // Handle -Map and -cref options.
writeMapFile();
+ writeCrossReferenceTable();
if (errorCount())
return;
@@ -486,12 +515,9 @@ template <class ELFT> void Writer<ELFT>::run() {
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
const Symbol &B) {
- if (B.isFile() || B.isSection())
+ if (B.isSection())
return false;
- // If sym references a section in a discarded group, don't keep it.
- if (Sec == &InputSection::Discarded)
- return false;
if (Config->Discard == DiscardPolicy::None)
return true;
@@ -637,6 +663,9 @@ static bool isRelroSection(const OutputSection *Sec) {
if (InX::Got && Sec == InX::Got->getParent())
return true;
+ if (Sec->Name.equals(".toc"))
+ return true;
+
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
@@ -668,20 +697,22 @@ static bool isRelroSection(const OutputSection *Sec) {
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 16,
- RF_NOT_INTERP = 1 << 15,
- RF_NOT_ALLOC = 1 << 14,
- RF_WRITE = 1 << 13,
- RF_EXEC_WRITE = 1 << 12,
- RF_EXEC = 1 << 11,
- RF_NON_TLS_BSS = 1 << 10,
- RF_NON_TLS_BSS_RO = 1 << 9,
- RF_NOT_TLS = 1 << 8,
- RF_BSS = 1 << 7,
+ RF_NOT_ADDR_SET = 1 << 18,
+ RF_NOT_INTERP = 1 << 17,
+ RF_NOT_ALLOC = 1 << 16,
+ RF_WRITE = 1 << 15,
+ RF_EXEC_WRITE = 1 << 14,
+ RF_EXEC = 1 << 13,
+ RF_RODATA = 1 << 12,
+ RF_NON_TLS_BSS = 1 << 11,
+ RF_NON_TLS_BSS_RO = 1 << 10,
+ RF_NOT_TLS = 1 << 9,
+ RF_BSS = 1 << 8,
+ RF_NOTE = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
- RF_PPC_OPD = 1 << 5,
- RF_PPC_TOCL = 1 << 4,
- RF_PPC_TOC = 1 << 3,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_GOT = 1 << 3,
RF_PPC_BRANCH_LT = 1 << 2,
RF_MIPS_GPREL = 1 << 1,
RF_MIPS_NOT_GOT = 1 << 0
@@ -712,8 +743,7 @@ static unsigned getSectionRank(const OutputSection *Sec) {
// considerations:
// * Read-only sections come first such that they go in the
// PT_LOAD covering the program headers at the start of the file.
- // * Read-only, executable sections come next, unless the
- // -no-rosegment option is used.
+ // * Read-only, executable sections come next.
// * Writable, executable sections follow such that .plt on
// architectures where it needs to be writable will be placed
// between .text and .data.
@@ -725,11 +755,16 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsExec) {
if (IsWrite)
Rank |= RF_EXEC_WRITE;
- else if (!Config->SingleRoRx)
+ else
Rank |= RF_EXEC;
- } else {
- if (IsWrite)
- Rank |= RF_WRITE;
+ } else if (IsWrite) {
+ Rank |= RF_WRITE;
+ } else if (Sec->Type == SHT_PROGBITS) {
+ // Make non-executable and non-writable PROGBITS sections (e.g .rodata
+ // .eh_frame) closer to .text. They likely contain PC or GOT relative
+ // relocations and there could be relocation overflow if other huge sections
+ // (.dynstr .dynsym) were placed in between.
+ Rank |= RF_RODATA;
}
// If we got here we know that both A and B are in the same PT_LOAD.
@@ -765,6 +800,12 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsNoBits)
Rank |= RF_BSS;
+ // We create a NOTE segment for contiguous .note sections, so make
+ // them contigous if there are more than one .note section with the
+ // same attributes.
+ if (Sec->Type == SHT_NOTE)
+ Rank |= RF_NOTE;
+
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64) {
@@ -778,18 +819,19 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
- if (Name == ".opd")
- Rank |= RF_PPC_OPD;
-
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
if (Name == ".toc")
Rank |= RF_PPC_TOC;
+ if (Name == ".got")
+ Rank |= RF_PPC_GOT;
+
if (Name == ".branch_lt")
Rank |= RF_PPC_BRANCH_LT;
}
+
if (Config->EMachine == EM_MIPS) {
// All sections with SHF_MIPS_GPREL flag should be grouped together
// because data in these sections is addressable with a gp relative address.
@@ -830,17 +872,19 @@ void PhdrEntry::add(OutputSection *Sec) {
// 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 (!Config->Static)
+ if (needsInterpSection())
return;
StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
+ ElfSym::RelaIpltEnd =
+ addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
-void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
+void Writer<ELFT>::forEachRelSec(
+ llvm::function_ref<void(InputSectionBase &)> Fn) {
// 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.
@@ -860,14 +904,18 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
// defining these symbols explicitly in the linker script.
template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
- // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
- // be at some offset from the base of the .got section, usually 0 or the end
- // of the .got
- InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
- : cast<InputSection>(InX::Got);
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
+ // to the start of the .got or .got.plt section.
+ InputSection *GotSection = InX::GotPlt;
+ if (!Target->GotBaseSymInGotPlt)
+ GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+ : cast<InputSection>(InX::Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
+ if (ElfSym::RelaIpltEnd)
+ ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -937,8 +985,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) {
static int getRankProximity(OutputSection *A, BaseCommand *B) {
if (auto *Sec = dyn_cast<OutputSection>(B))
- if (Sec->Live)
- return getRankProximityAux(A, Sec);
+ return getRankProximityAux(A, Sec);
return -1;
}
@@ -957,11 +1004,9 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) {
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
static bool shouldSkip(BaseCommand *Cmd) {
- if (isa<OutputSection>(Cmd))
- return false;
if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
return Assign->Name != ".";
- return true;
+ return false;
}
// We want to place orphan sections so that they share as much
@@ -984,20 +1029,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
int Proximity = getRankProximity(Sec, *I);
for (; I != E; ++I) {
auto *CurSec = dyn_cast<OutputSection>(*I);
- if (!CurSec || !CurSec->Live)
+ if (!CurSec)
continue;
if (getRankProximity(Sec, CurSec) != Proximity ||
Sec->SortRank < CurSec->SortRank)
break;
}
- auto IsLiveSection = [](BaseCommand *Cmd) {
- auto *OS = dyn_cast<OutputSection>(Cmd);
- return OS && OS->Live;
- };
-
+ auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); };
auto J = std::find_if(llvm::make_reverse_iterator(I),
- llvm::make_reverse_iterator(B), IsLiveSection);
+ llvm::make_reverse_iterator(B), IsOutputSec);
I = J.base();
// As a special case, if the orphan section is the last section, put
@@ -1005,7 +1046,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
// This matches bfd's behavior and is convenient when the linker script fully
// specifies the start of the file, but doesn't care about the end (the non
// alloc sections for example).
- auto NextSec = std::find_if(I, E, IsLiveSection);
+ auto NextSec = std::find_if(I, E, IsOutputSec);
if (NextSec == E)
return E;
@@ -1014,32 +1055,172 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
return I;
}
-// If no layout was provided by linker script, we want to apply default
-// sorting for special input sections and handle --symbol-ordering-file.
-template <class ELFT> void Writer<ELFT>::sortInputSections() {
- assert(!Script->HasSectionsCommand);
+// Builds section order for handling --symbol-ordering-file.
+static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
+ DenseMap<const InputSectionBase *, int> SectionOrder;
+ // Use the rarely used option -call-graph-ordering-file to sort sections.
+ if (!Config->CallGraphProfile.empty())
+ return computeCallGraphProfileOrder();
- // Sort input sections by priority using the list provided
- // by --symbol-ordering-file.
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
- if (!Order.empty())
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- if (Sec->Live)
- Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); });
+ if (Config->SymbolOrderingFile.empty())
+ return SectionOrder;
+
+ struct SymbolOrderEntry {
+ int Priority;
+ bool Present;
+ };
+
+ // Build a map from symbols to their priorities. Symbols that didn't
+ // appear in the symbol ordering file have the lowest priority 0.
+ // All explicitly mentioned symbols have negative (higher) priorities.
+ DenseMap<StringRef, SymbolOrderEntry> SymbolOrder;
+ int Priority = -Config->SymbolOrderingFile.size();
+ for (StringRef S : Config->SymbolOrderingFile)
+ SymbolOrder.insert({S, {Priority++, false}});
+
+ // Build a map from sections to their priorities.
+ auto AddSym = [&](Symbol &Sym) {
+ auto It = SymbolOrder.find(Sym.getName());
+ if (It == SymbolOrder.end())
+ return;
+ SymbolOrderEntry &Ent = It->second;
+ Ent.Present = true;
+
+ warnUnorderableSymbol(&Sym);
+
+ if (auto *D = dyn_cast<Defined>(&Sym)) {
+ if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
+ int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
+ Priority = std::min(Priority, Ent.Priority);
+ }
+ }
+ };
+ // We want both global and local symbols. We get the global ones from the
+ // symbol table and iterate the object files for the local ones.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (!Sym->isLazy())
+ AddSym(*Sym);
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ if (Sym->isLocal())
+ AddSym(*Sym);
+
+ if (Config->WarnSymbolOrdering)
+ for (auto OrderEntry : SymbolOrder)
+ if (!OrderEntry.second.Present)
+ warn("symbol ordering file: no such symbol: " + OrderEntry.first);
+
+ return SectionOrder;
+}
+
+// Sorts the sections in ISD according to the provided section order.
+static void
+sortISDBySectionOrder(InputSectionDescription *ISD,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ std::vector<InputSection *> UnorderedSections;
+ std::vector<std::pair<InputSection *, int>> OrderedSections;
+ uint64_t UnorderedSize = 0;
+
+ for (InputSection *IS : ISD->Sections) {
+ auto I = Order.find(IS);
+ if (I == Order.end()) {
+ UnorderedSections.push_back(IS);
+ UnorderedSize += IS->getSize();
+ continue;
+ }
+ OrderedSections.push_back({IS, I->second});
+ }
+ llvm::sort(
+ OrderedSections.begin(), OrderedSections.end(),
+ [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
+
+ // Find an insertion point for the ordered section list in the unordered
+ // section list. On targets with limited-range branches, this is the mid-point
+ // of the unordered section list. This decreases the likelihood that a range
+ // extension thunk will be needed to enter or exit the ordered region. If the
+ // ordered section list is a list of hot functions, we can generally expect
+ // the ordered functions to be called more often than the unordered functions,
+ // making it more likely that any particular call will be within range, and
+ // therefore reducing the number of thunks required.
+ //
+ // For example, imagine that you have 8MB of hot code and 32MB of cold code.
+ // If the layout is:
+ //
+ // 8MB hot
+ // 32MB cold
+ //
+ // only the first 8-16MB of the cold code (depending on which hot function it
+ // is actually calling) can call the hot code without a range extension thunk.
+ // However, if we use this layout:
+ //
+ // 16MB cold
+ // 8MB hot
+ // 16MB cold
+ //
+ // both the last 8-16MB of the first block of cold code and the first 8-16MB
+ // of the second block of cold code can call the hot code without a thunk. So
+ // we effectively double the amount of code that could potentially call into
+ // the hot code without a thunk.
+ size_t InsPt = 0;
+ if (Target->ThunkSectionSpacing && !OrderedSections.empty()) {
+ uint64_t UnorderedPos = 0;
+ for (; InsPt != UnorderedSections.size(); ++InsPt) {
+ UnorderedPos += UnorderedSections[InsPt]->getSize();
+ if (UnorderedPos > UnorderedSize / 2)
+ break;
+ }
+ }
+
+ ISD->Sections.clear();
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
+ ISD->Sections.push_back(IS);
+ for (std::pair<InputSection *, int> P : OrderedSections)
+ ISD->Sections.push_back(P.first);
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
+ ISD->Sections.push_back(IS);
+}
+
+static void sortSection(OutputSection *Sec,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ StringRef Name = Sec->Name;
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
- if (OutputSection *Sec = findSection(".init_array"))
- Sec->sortInitFini();
- if (OutputSection *Sec = findSection(".fini_array"))
- Sec->sortInitFini();
+ if (Name == ".init_array" || Name == ".fini_array") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortInitFini();
+ return;
+ }
// Sort input sections by the special rule for .ctors and .dtors.
- if (OutputSection *Sec = findSection(".ctors"))
- Sec->sortCtorsDtors();
- if (OutputSection *Sec = findSection(".dtors"))
- Sec->sortCtorsDtors();
+ if (Name == ".ctors" || Name == ".dtors") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortCtorsDtors();
+ return;
+ }
+
+ // Never sort these.
+ if (Name == ".init" || Name == ".fini")
+ return;
+
+ // Sort input sections by priority using the list provided
+ // by --symbol-ordering-file.
+ if (!Order.empty())
+ for (BaseCommand *B : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortISDBySectionOrder(ISD, Order);
+}
+
+// If no layout was provided by linker script, we want to apply default
+// sorting for special input sections. This also handles --symbol-ordering-file.
+template <class ELFT> void Writer<ELFT>::sortInputSections() {
+ // Build the order once since it is expensive.
+ DenseMap<const InputSectionBase *, int> Order = buildSectionOrder();
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ sortSection(Sec, Order);
}
template <class ELFT> void Writer<ELFT>::sortSections() {
@@ -1050,22 +1231,29 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
if (Config->Relocatable)
return;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- Sec->SortRank = getSectionRank(Sec);
+ sortInputSections();
- if (!Script->HasSectionsCommand) {
- sortInputSections();
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *OS = dyn_cast<OutputSection>(Base);
+ if (!OS)
+ continue;
+ OS->SortRank = getSectionRank(OS);
+
+ // We want to assign rude approximation values to OutSecOff fields
+ // to know the relative order of the input sections. We use it for
+ // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
+ uint64_t I = 0;
+ for (InputSection *Sec : getInputSections(OS))
+ Sec->OutSecOff = I++;
+ }
+ if (!Script->HasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
- auto E = Script->SectionCommands.end();
- auto I = Script->SectionCommands.begin();
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
- I = std::find_if(I, E, IsSection);
- E = std::find_if(llvm::make_reverse_iterator(E),
- llvm::make_reverse_iterator(I), IsSection)
- .base();
- std::stable_sort(I, E, compareSections);
+ std::stable_sort(
+ llvm::find_if(Script->SectionCommands, IsSection),
+ llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
+ compareSections);
return;
}
@@ -1096,7 +1284,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// The way we define an order then is:
// * Sort only the orphan sections. They are in the end right now.
// * Move each orphan section to its preferred position. We try
- // to put each section in the last position where it it can share
+ // to put each section in the last position where it can share
// a PT_LOAD.
//
// There is some ambiguity as to where exactly a new entry should be
@@ -1112,7 +1300,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto E = Script->SectionCommands.end();
auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
if (auto *Sec = dyn_cast<OutputSection>(Base))
- return Sec->Live && Sec->SectionIndex == INT_MAX;
+ return Sec->SectionIndex == UINT32_MAX;
return false;
});
@@ -1187,8 +1375,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
};
// Get the last table Entry from the previous .ARM.exidx section.
- const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>(
- Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry));
+ const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back();
if (IsExtabRef(PrevEntry.Unwind))
return false;
@@ -1200,14 +1387,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
// consecutive identical entries are rare and the effort to check that they
// are identical is high.
- if (isa<SyntheticSection>(Cur))
- // Exidx sentinel section has implicit EXIDX_CANTUNWIND;
- return PrevEntry.Unwind == 0x1;
-
- ArrayRef<const ExidxEntry> Entries(
- reinterpret_cast<const ExidxEntry *>(Cur->Data.data()),
- Cur->getSize() / sizeof(ExidxEntry));
- for (const ExidxEntry &Entry : Entries)
+ for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
return false;
// All table entries in this .ARM.exidx Section can be merged into the
@@ -1237,13 +1417,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
if (!Config->Relocatable && Config->EMachine == EM_ARM &&
Sec->Type == SHT_ARM_EXIDX) {
- if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) {
+ if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) {
assert(Sections.size() >= 2 &&
"We should create a sentinel section only if there are "
"alive regular exidx sections.");
// The last executable section is required to fill the sentinel.
// Remember it here so that we don't have to find it again.
- auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back());
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
@@ -1254,16 +1433,13 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// previous one. This does not require any rewriting of InputSection
// contents but misses opportunities for fine grained deduplication
// where only a subset of the InputSection contents can be merged.
- int Cur = 1;
- int Prev = 0;
+ size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
- int N = Sections.size() - 1;
- while (Cur < N) {
- if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur]))
- Sections[Cur] = nullptr;
+ for (size_t I = 1; I < Sections.size() - 1; ++I) {
+ if (isDuplicateArmExidxSec(Sections[Prev], Sections[I]))
+ Sections[I] = nullptr;
else
- Prev = Cur;
- ++Cur;
+ Prev = I;
}
}
}
@@ -1274,14 +1450,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// Remove the Sections we marked as duplicate earlier.
for (BaseCommand *Base : Sec->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
- ISD->Sections.erase(
- std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr),
- ISD->Sections.end());
+ llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; });
}
}
static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
- std::function<void(SyntheticSection *)> Fn) {
+ llvm::function_ref<void(SyntheticSection *)> Fn) {
for (SyntheticSection *SS : Sections)
if (SS && SS->getParent() && !SS->empty())
Fn(SS);
@@ -1308,27 +1482,15 @@ static void removeUnusedSyntheticSections() {
if (!SS)
return;
OutputSection *OS = SS->getParent();
- if (!SS->empty() || !OS)
+ if (!OS || !SS->empty())
continue;
- std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end();
- for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end();
- I != E; ++I) {
- BaseCommand *B = *I;
- if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+ // If we reach here, then SS is an unused synthetic section and we want to
+ // remove it from corresponding input section description of output section.
+ for (BaseCommand *B : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
llvm::erase_if(ISD->Sections,
[=](InputSection *IS) { return IS == SS; });
- if (ISD->Sections.empty())
- Empty = I;
- }
- }
- if (Empty != OS->SectionCommands.end())
- OS->SectionCommands.erase(Empty);
-
- // If there are no other sections in the output section, remove it from the
- // output.
- if (OS->SectionCommands.empty())
- OS->Live = false;
}
}
@@ -1420,9 +1582,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::DynSymTab && Sym->includeInDynsym()) {
InX::DynSymTab->addSymbol(Sym);
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded)
- In<ELFT>::VerNeed->addSymbol(SS);
+ if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
+ if (File->IsNeeded && !Sym->isUndefined())
+ In<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1430,10 +1592,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
+ if (InX::MipsGot)
+ InX::MipsGot->build<ELFT>();
+
removeUnusedSyntheticSections();
sortSections();
- Script->removeEmptyCommands();
// Now that we have the final list, create a list of all the
// OutputSections for convenience.
@@ -1449,7 +1613,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
// This is a bit of a hack. A value of 0 means undef, so we set it
- // to 1 t make __ehdr_start defined. The section number is not
+ // to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
@@ -1475,12 +1639,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic(
- {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
- InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
- In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
- InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt,
- InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr,
- In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
+ {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
+ InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
+ In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
+ InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelrDyn,
+ InX::RelaIplt, InX::RelaPlt, InX::Plt, InX::Iplt,
+ InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
[](SyntheticSection *SS) { SS->finalizeContents(); });
if (!Script->HasSectionsCommand && !Config->Relocatable)
@@ -1492,10 +1656,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Some architectures need to generate content that depends on the address
// of InputSections. For example some architectures use small displacements
- // for jump instructions that is is the linker's responsibility for creating
+ // for jump instructions that is the linker's responsibility for creating
// range extension thunks for. As the generation of the content may also
// alter InputSection addresses we must converge to a fixed point.
- if (Target->NeedsThunks || Config->AndroidPackDynRelocs) {
+ if (Target->NeedsThunks || Config->AndroidPackDynRelocs ||
+ Config->RelrPackDynRelocs) {
ThunkCreator TC;
AArch64Err843419Patcher A64P;
bool Changed;
@@ -1512,34 +1677,48 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::MipsGot)
InX::MipsGot->updateAllocSize();
Changed |= InX::RelaDyn->updateAllocSize();
+ if (InX::RelrDyn)
+ Changed |= InX::RelrDyn->updateAllocSize();
} while (Changed);
}
+ // createThunks may have added local symbols to the static symbol table
+ applySynthetic({InX::SymTab},
+ [](SyntheticSection *SS) { SS->postThunkContents(); });
+
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
-
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
}
// 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, OutputSection *OS) {
- // These symbols resolve to the image base if the section does not exist.
- // A special value -1 indicates end of the section.
+ // If a section does not exist, there's ambiguity as to how we
+ // define _start and _end symbols for an init/fini section. Since
+ // the loader assume that the symbols are always defined, we need to
+ // always define them. But what value? The loader iterates over all
+ // pointers between _start and _end to run global ctors/dtors, so if
+ // the section is empty, their symbol values don't actually matter
+ // as long as _start and _end point to the same location.
+ //
+ // That said, we don't want to set the symbols to 0 (which is
+ // probably the simplest value) because that could cause some
+ // program to fail to link due to relocation overflow, if their
+ // program text is above 2 GiB. We use the address of the .text
+ // section instead to prevent that failure.
+ OutputSection *Default = findSection(".text");
+ if (!Default)
+ Default = Out::ElfHeader;
+ auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
addOptionalRegular(End, OS, -1);
} else {
- if (Config->Pic)
- OS = Out::ElfHeader;
- addOptionalRegular(Start, OS, 0);
- addOptionalRegular(End, OS, 0);
+ addOptionalRegular(Start, Default, 0);
+ addOptionalRegular(End, Default, 0);
}
};
@@ -1561,12 +1740,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
StringRef S = Sec->Name;
if (!isValidCIdentifier(S))
return;
- addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
- addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
+ addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED);
+ addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *Sec) {
- if (!(Sec->Flags & SHF_ALLOC))
+ if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
@@ -1623,9 +1802,13 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
// different flags or is loaded at a discontiguous address using AT linker
- // script command.
+ // script command. At the same time, we don't want to create a separate
+ // load segment for the headers, even if the first output section has
+ // an AT attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if (Sec->LMAExpr || Flags != NewFlags) {
+ if ((Sec->LMAExpr && Load->LastSec != Out::ProgramHeaders) ||
+ Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
+
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
@@ -1686,11 +1869,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// pages for the stack non-executable. If you really want an executable
// stack, you can pass -z execstack, but that's not recommended for
// security reasons.
- unsigned Perm;
+ unsigned Perm = PF_R | PF_W;
if (Config->ZExecstack)
- Perm = PF_R | PF_W | PF_X;
- else
- Perm = PF_R | PF_W;
+ Perm |= PF_X;
AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
@@ -1703,7 +1884,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Create one PT_NOTE per a group of contiguous .note sections.
PhdrEntry *Note = nullptr;
for (OutputSection *Sec : OutputSections) {
- if (Sec->Type == SHT_NOTE) {
+ if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) {
if (!Note || Sec->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
@@ -1767,30 +1948,36 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// virtual address (modulo the page size) so that the loader can load
// executables without any address adjustment.
static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) {
- // If the section is not in a PT_LOAD, we just have to align it.
- if (!Cmd->PtLoad)
- return alignTo(Off, Cmd->Alignment);
-
- OutputSection *First = Cmd->PtLoad->FirstSec;
+ OutputSection *First = Cmd->PtLoad ? Cmd->PtLoad->FirstSec : nullptr;
// The first section in a PT_LOAD has to have congruent offset and address
// module the page size.
if (Cmd == First)
return alignTo(Off, std::max<uint64_t>(Cmd->Alignment, Config->MaxPageSize),
Cmd->Addr);
+ // For SHT_NOBITS we don't want the alignment of the section to impact the
+ // offset of the sections that follow. Since nothing seems to care about the
+ // sh_offset of the SHT_NOBITS section itself, just ignore it.
+ if (Cmd->Type == SHT_NOBITS)
+ return Off;
+
+ // If the section is not in a PT_LOAD, we just have to align it.
+ if (!Cmd->PtLoad)
+ return alignTo(Off, Cmd->Alignment);
+
// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
return First->Offset + Cmd->Addr - First->Addr;
}
static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) {
- if (Cmd->Type == SHT_NOBITS) {
- Cmd->Offset = Off;
- return Off;
- }
-
Off = getFileAlignment(Off, Cmd);
Cmd->Offset = Off;
+
+ // For SHT_NOBITS we should not count the size.
+ if (Cmd->Type == SHT_NOBITS)
+ return Off;
+
return Off + Cmd->Size;
}
@@ -1802,6 +1989,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
FileSize = alignTo(Off, Config->Wordsize);
}
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+ if (Len == 0)
+ return "<empty range at 0x" + utohexstr(Addr) + ">";
+ return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
@@ -1826,6 +2019,24 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+ // Our logic assumes that sections have rising VA within the same segment.
+ // With use of linker scripts it is possible to violate this rule and get file
+ // offset overlaps or overflows. That should never happen with a valid script
+ // which does not move the location counter backwards and usually scripts do
+ // not do that. Unfortunately, there are apps in the wild, for example, Linux
+ // kernel, which control segment distribution explicitly and move the counter
+ // backwards, so we have to allow doing that to support linking them. We
+ // perform non-critical checks for overlaps in checkSectionOverlap(), but here
+ // we want to prevent file size overflows because it would crash the linker.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOBITS)
+ continue;
+ if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+ error("unable to place section " + Sec->Name + " at file offset " +
+ rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+ "; check your linker script for overflows");
+ }
}
// Finalize the program headers. We call this function after we assign
@@ -1864,6 +2075,97 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
}
}
+// A helper struct for checkSectionOverlap.
+namespace {
+struct SectionOffset {
+ OutputSection *Sec;
+ uint64_t Offset;
+};
+} // namespace
+
+// Check whether sections overlap for a specific address range (file offsets,
+// load and virtual adresses).
+static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
+ bool IsVirtualAddr) {
+ llvm::sort(Sections.begin(), Sections.end(),
+ [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
+
+ // Finding overlap is easy given a vector is sorted by start position.
+ // If an element starts before the end of the previous element, they overlap.
+ for (size_t I = 1, End = Sections.size(); I < End; ++I) {
+ SectionOffset A = Sections[I - 1];
+ SectionOffset B = Sections[I];
+ if (B.Offset >= A.Offset + A.Sec->Size)
+ continue;
+
+ // If both sections are in OVERLAY we allow the overlapping of virtual
+ // addresses, because it is what OVERLAY was designed for.
+ if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay)
+ continue;
+
+ errorOrWarn("section " + A.Sec->Name + " " + Name +
+ " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name +
+ " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " +
+ B.Sec->Name + " range is " +
+ rangeToString(B.Offset, B.Sec->Size));
+ }
+}
+
+// Check for overlapping sections and address overflows.
+//
+// In this function we check that none of the output sections have overlapping
+// file offsets. For SHF_ALLOC sections we also check that the load address
+// ranges and the virtual address ranges don't overlap
+template <class ELFT> void Writer<ELFT>::checkSections() {
+ // First, check that section's VAs fit in available address space for target.
+ for (OutputSection *OS : OutputSections)
+ if ((OS->Addr + OS->Size < OS->Addr) ||
+ (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
+ errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
+ " of size 0x" + utohexstr(OS->Size) +
+ " exceeds available address space");
+
+ // Check for overlapping file offsets. In this case we need to skip any
+ // section marked as SHT_NOBITS. These sections don't actually occupy space in
+ // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
+ // binary is specified only add SHF_ALLOC sections are added to the output
+ // file so we skip any non-allocated sections in that case.
+ std::vector<SectionOffset> FileOffs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && Sec->Type != SHT_NOBITS &&
+ (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
+ FileOffs.push_back({Sec, Sec->Offset});
+ checkOverlap("file", FileOffs, false);
+
+ // When linking with -r there is no need to check for overlapping virtual/load
+ // addresses since those addresses will only be assigned when the final
+ // executable/shared object is created.
+ if (Config->Relocatable)
+ return;
+
+ // Checking for overlapping virtual and load addresses only needs to take
+ // into account SHF_ALLOC sections since others will not be loaded.
+ // Furthermore, we also need to skip SHF_TLS sections since these will be
+ // mapped to other addresses at runtime and can therefore have overlapping
+ // ranges in the file.
+ std::vector<SectionOffset> VMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ VMAs.push_back({Sec, Sec->Addr});
+ checkOverlap("virtual address", VMAs, true);
+
+ // Finally, check that the load addresses don't overlap. This will usually be
+ // the same as the virtual addresses but can be different when using a linker
+ // script with AT().
+ std::vector<SectionOffset> LMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ LMAs.push_back({Sec, Sec->getLMA()});
+ checkOverlap("load address", LMAs, false);
+}
+
// The entry point address is chosen in the following ways.
//
// 1. the '-e' entry command-line option;
@@ -1905,8 +2207,20 @@ static uint16_t getELFType() {
return ET_EXEC;
}
+static uint8_t getAbiVersion() {
+ // MIPS non-PIC executable gets ABI version 1.
+ if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC &&
+ (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
+ return 1;
+ return 0;
+}
+
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
+ // For executable segments, the trap instructions are written before writing
+ // the header. Setting Elf header bytes to zero ensures that any unused bytes
+ // in header are zero-cleared, instead of having trap instructions.
+ memset(Buf, 0, sizeof(Elf_Ehdr));
memcpy(Buf, "\177ELF", 4);
// Write the ELF header.
@@ -1915,6 +2229,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = Config->OSABI;
+ EHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
EHdr->e_type = getELFType();
EHdr->e_machine = Config->EMachine;
EHdr->e_version = EV_CURRENT;
@@ -1924,8 +2239,6 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
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 = InX::ShStrTab->getParent()->SectionIndex;
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
@@ -1946,8 +2259,30 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
++HBuf;
}
- // Write the section header table. Note that the first table entry is null.
+ // Write the section header table.
+ //
+ // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum
+ // and e_shstrndx fields. When the value of one of these fields exceeds
+ // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and
+ // use fields in the section header at index 0 to store
+ // the value. The sentinel values and fields are:
+ // e_shnum = 0, SHdrs[0].sh_size = number of sections.
+ // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ size_t Num = OutputSections.size() + 1;
+ if (Num >= SHN_LORESERVE)
+ SHdrs->sh_size = Num;
+ else
+ EHdr->e_shnum = Num;
+
+ uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex;
+ if (StrTabIndex >= SHN_LORESERVE) {
+ SHdrs->sh_link = StrTabIndex;
+ EHdr->e_shstrndx = SHN_XINDEX;
+ } else {
+ EHdr->e_shstrndx = StrTabIndex;
+ }
+
for (OutputSection *Sec : OutputSections)
Sec->writeHeaderTo<ELFT>(++SHdrs);
}
@@ -2018,14 +2353,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
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 (auto *OpdCmd = findSection(".opd")) {
- Out::Opd = OpdCmd;
- Out::OpdBuf = Buf + Out::Opd->Offset;
- OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
- }
-
OutputSection *EhFrameHdr = nullptr;
if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
EhFrameHdr = InX::EhFrameHdr->getParent();
@@ -2038,8 +2365,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
- if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
- Sec->Type != SHT_RELA)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
diff --git a/ELF/Writer.h b/ELF/Writer.h
index d247068bab23..7806f824c58f 100644
--- a/ELF/Writer.h
+++ b/ELF/Writer.h
@@ -23,7 +23,6 @@ class InputSectionBase;
template <class ELFT> class ObjFile;
class SymbolTable;
template <class ELFT> void writeResult();
-template <class ELFT> void markLive();
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
@@ -44,10 +43,12 @@ struct PhdrEntry {
OutputSection *FirstSec = nullptr;
OutputSection *LastSec = nullptr;
bool HasLMA = false;
+
+ uint64_t LMAOffset = 0;
};
void addReservedSymbols();
-llvm::StringRef getOutputSectionName(InputSectionBase *S);
+llvm::StringRef getOutputSectionName(const InputSectionBase *S);
template <class ELFT> uint32_t calcMipsEFlags();
diff --git a/LICENSE.TXT b/LICENSE.TXT
index ec97986c86ba..e05e1845766e 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ lld License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2011-2016 by the contributors listed in CREDITS.TXT
+Copyright (c) 2011-2018 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
diff --git a/MinGW/Driver.cpp b/MinGW/Driver.cpp
index 6d3bea5d9040..27a5550ec9c7 100644
--- a/MinGW/Driver.cpp
+++ b/MinGW/Driver.cpp
@@ -136,6 +136,8 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
Add("-output-def:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_image_base))
Add("-base:" + StringRef(A->getValue()));
+ if (auto *A = Args.getLastArg(OPT_map))
+ Add("-lldmap:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_o))
Add("-out:" + StringRef(A->getValue()));
@@ -144,16 +146,25 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
else
Add("-out:a.exe");
+ if (auto *A = Args.getLastArg(OPT_pdb)) {
+ Add("-debug");
+ Add("-pdb:" + StringRef(A->getValue()));
+ } else if (Args.hasArg(OPT_strip_debug)) {
+ Add("-debug:symtab");
+ } else if (!Args.hasArg(OPT_strip_all)) {
+ Add("-debug:dwarf");
+ }
+
if (Args.hasArg(OPT_shared))
Add("-dll");
if (Args.hasArg(OPT_verbose))
Add("-verbose");
if (Args.hasArg(OPT_export_all_symbols))
Add("-export-all-symbols");
- if (!Args.hasArg(OPT_strip_all))
- Add("-debug:dwarf");
if (Args.hasArg(OPT_large_address_aware))
Add("-largeaddressaware");
+ if (Args.hasArg(OPT_kill_at))
+ Add("-kill-at");
if (Args.getLastArgValue(OPT_m) != "thumb2pe" &&
Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase))
diff --git a/MinGW/Options.td b/MinGW/Options.td
index f3bf25a2258b..ad699f71134a 100644
--- a/MinGW/Options.td
+++ b/MinGW/Options.td
@@ -14,9 +14,12 @@ def export_all_symbols: F<"export-all-symbols">,
def gc_sections: F<"gc-sections">, HelpText<"Remove unused sections">;
def icf: J<"icf=">, HelpText<"Identical code folding">;
def image_base: S<"image-base">, HelpText<"Base address of the program">;
+def kill_at: F<"kill-at">, HelpText<"Remove @n from exported symbols">;
def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def map: S<"Map">, HelpText<"Output a linker map">;
+def map_eq: J<"Map=">, Alias<map>;
def no_whole_archive: F<"no-whole-archive">,
HelpText<"No longer include all object files for following archives">;
def large_address_aware: Flag<["--"], "large-address-aware">,
@@ -32,6 +35,8 @@ def subs: S<"subsystem">, HelpText<"Specify subsystem">;
def stack: S<"stack">;
def strip_all: F<"strip-all">,
HelpText<"Omit all symbol information from the output binary">;
+def strip_debug: F<"strip-debug">,
+ HelpText<"Omit all debug information, but keep symbol information">;
def whole_archive: F<"whole-archive">,
HelpText<"Include all object files for following archives">;
def verbose: F<"verbose">, HelpText<"Verbose mode">;
@@ -40,6 +45,7 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def _HASH_HASH_HASH : Flag<["-"], "###">,
HelpText<"Print (but do not run) the commands to run for this compilation">;
def mllvm: S<"mllvm">;
+def pdb: S<"pdb">, HelpText<"Specify output PDB debug information file">;
def Xlink : J<"Xlink=">, MetaVarName<"<arg>">,
HelpText<"Pass <arg> to the COFF linker">;
@@ -51,6 +57,7 @@ def build_id: F<"build-id">;
def disable_auto_image_base: F<"disable-auto-image-base">;
def enable_auto_image_base: F<"enable-auto-image-base">;
def enable_auto_import: F<"enable-auto-import">;
+def end_group: F<"end-group">;
def full_shutdown: Flag<["--"], "full-shutdown">;
def high_entropy_va: F<"high-entropy-va">, HelpText<"Enable 64-bit ASLR">;
def major_image_version: S<"major-image-version">;
@@ -59,6 +66,7 @@ def no_seh: F<"no-seh">;
def nxcompat: F<"nxcompat">, HelpText<"Enable data execution prevention">;
def pic_executable: F<"pic-executable">;
def sysroot: J<"sysroot">, HelpText<"Sysroot">;
+def start_group: F<"start-group">;
def tsaware: F<"tsaware">, HelpText<"Create Terminal Server aware executable">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
def version: F<"version">, HelpText<"Display the version number and exit">;
@@ -66,3 +74,4 @@ def version: F<"version">, HelpText<"Display the version number and exit">;
// Alias
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_strip_s: Flag<["-"], "s">, Alias<strip_all>;
+def alias_strip_S: Flag<["-"], "S">, Alias<strip_debug>;
diff --git a/cmake/modules/AddLLD.cmake b/cmake/modules/AddLLD.cmake
index 0d951799cdfe..fa48b428d26b 100644
--- a/cmake/modules/AddLLD.cmake
+++ b/cmake/modules/AddLLD.cmake
@@ -10,7 +10,7 @@ macro(add_lld_library name)
llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS})
set_target_properties(${name} PROPERTIES FOLDER "lld libraries")
- if (LLD_BUILD_TOOLS)
+ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
NOT LLVM_DISTRIBUTION_COMPONENTS)
set(export_to_lldtargets EXPORT lldTargets)
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index dcd6ac0602d3..7ac1f9ce565b 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,21 +1,21 @@
=======================
-LLD 6.0.0 Release Notes
+LLD 7.0.0 Release Notes
=======================
.. contents::
:local:
.. warning::
- These are in-progress notes for the upcoming LLVM 6.0.0 release.
+ These are in-progress notes for the upcoming LLVM 7.0.0 release.
Release notes for previous releases can be found on
`the Download Page <http://releases.llvm.org/download.html>`_.
Introduction
============
-This document contains the release notes for the LLD linker, release 6.0.0.
-Here we describe the status of LLD, including major improvements
-from the previous release. All LLD releases may be downloaded
+This document contains the release notes for the lld linker, release 7.0.0.
+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/>`_.
Non-comprehensive list of changes in this release
diff --git a/docs/WebAssembly.rst b/docs/WebAssembly.rst
index 1df8fa3a82b0..264d221970b1 100644
--- a/docs/WebAssembly.rst
+++ b/docs/WebAssembly.rst
@@ -18,7 +18,7 @@ the WebAssembly tool conventions
https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md.
This is object format that the llvm will produce when run with the
-``wasm32-unknown-unknown-wasm`` target. To build llvm with WebAssembly support
+``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support
currently requires enabling the experimental backed using
``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
diff --git a/docs/conf.py b/docs/conf.py
index 28e16f5b8856..3598fbf50f0d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,9 +48,9 @@ copyright = u'2011-%d, LLVM Project' % date.today().year
# built documents.
#
# The short version.
-version = '6'
+version = '7'
# The full version, including alpha/beta/rc tags.
-release = '6'
+release = '7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/ld.lld.1 b/docs/ld.lld.1
new file mode 100644
index 000000000000..c9662856b891
--- /dev/null
+++ b/docs/ld.lld.1
@@ -0,0 +1,547 @@
+.\" This file is distributed under the University of Illinois Open Source
+.\" License. See LICENSE.TXT for details.
+.\"
+.\" This man page documents only lld's ELF linking support, obtained originally
+.\" from FreeBSD.
+.Dd April 28, 2018
+.Dt LD.LLD 1
+.Os
+.Sh NAME
+.Nm ld.lld
+.Nd ELF linker from the LLVM project
+.Sh SYNOPSIS
+.Nm ld.lld
+.Op Ar options
+.Ar objfile ...
+.Sh DESCRIPTION
+A linker takes one or more object, archive, and library files, and combines
+them into an output file (an executable, a shared library, or another object
+file).
+It relocates code and data from the input files and resolves symbol
+references between them.
+.Pp
+.Nm
+is a drop-in replacement for the GNU BFD and gold linkers.
+It accepts most of the same command line arguments and linker scripts
+as GNU linkers.
+.Pp
+These options are available:
+.Bl -tag -width indent
+.It Fl -allow-multiple-definition
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+.It Fl -as-needed
+Only set
+.Dv DT_NEEDED
+for shared libraries if used.
+.It Fl -auxiliary Ns = Ns Ar value
+Set the
+.Dv DT_AUXILIARY
+field to the specified name.
+.It Fl -Bdynamic
+Link against shared libraries.
+.It Fl -Bstatic
+Do not link against shared libraries.
+.It Fl -Bsymbolic-functions
+Bind defined function symbols locally.
+.It Fl -Bsymbolic
+Bind defined symbols locally.
+.It Fl -build-id Ns = Ns Ar value
+Generate a build ID note.
+.Ar value
+may be one of
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+.Cm tree ,
+.Cm uuid ,
+.Cm 0x Ns Ar hex-string ,
+and
+.Cm none .
+.Cm tree
+is an alias for
+.Cm sha1 .
+Build-IDs of type
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+and
+.Cm tree
+are calculated from the object contents.
+.Cm fast
+is not intended to be cryptographically secure.
+.It Fl -build-id
+Synonym for
+.Fl -build-id Ns = Ns Cm fast .
+.It Fl -color-diagnostics Ns = Ns Ar value
+Use colors in diagnostics.
+.Ar value
+may be one of
+.Cm always ,
+.Cm auto ,
+and
+.Cm never .
+.Cm auto
+enables color if and only if output is to a terminal.
+.It Fl -color-diagnostics
+Alias for
+.Fl -color-diagnostics Ns = Ns Cm auto .
+.It Fl -compress-debug-sections Ns = Ns Ar value
+Compress DWARF debug sections.
+.Ar value
+may be
+.Cm none
+or
+.Cm zlib .
+.It Fl -define-common
+Assign space to common symbols.
+.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
+Define a symbol alias.
+.Ar expression
+may be another symbol or a linker script expression.
+For example,
+.Ql --defsym=foo=bar
+or
+.Ql --defsym=foo=bar+0x100 .
+.It Fl -demangle
+Demangle symbol names.
+.It Fl -disable-new-dtags
+Disable new dynamic tags.
+.It Fl -discard-all
+Delete all local symbols.
+.It Fl -discard-locals
+Delete temporary local symbols.
+.It Fl -discard-none
+Keep all symbols in the symbol table.
+.It Fl -dynamic-linker Ns = Ns Ar value
+Specify the dynamic linker to be used for a dynamically linked executable.
+This is recorded in an ELF segment of type
+.Dv PT_INTERP .
+.It Fl -dynamic-list Ns = Ns Ar file
+Read a list of dynamic symbols from
+.Ar file .
+.It Fl -eh-frame-hdr
+Request creation of
+.Li .eh_frame_hdr
+section and
+.Dv PT_GNU_EH_FRAME
+segment header.
+.It Fl -emit-relocs
+Generate relocations in the output.
+.It Fl -enable-new-dtags
+Enable new dynamic tags.
+.It Fl -end-lib
+End a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -entry Ns = Ns Ar entry
+Name of entry point symbol.
+.It Fl -error-limit Ns = Ns Ar value
+Maximum number of errors to emit before stopping.
+A value of zero indicates that there is no limit.
+.It Fl -error-unresolved-symbols
+Report unresolved symbols as errors.
+.It Fl -exclude-libs Ns = Ns Ar value
+Exclude static libraries from automatic export.
+.It Fl -export-dynamic-symbol Ns = Ns Ar symbol
+Include
+.Ar symbol
+in the dynamic symbol table.
+.It Fl -export-dynamic
+Put symbols in the dynamic symbol table.
+.It Fl -fatal-warnings
+Treat warnings as errors.
+.It Fl -filter Ns = Ns Ar value
+Set the
+.Dv DT_FILTER
+field to the specified value.
+.It Fl -fini Ns = Ns Ar symbol
+Specify a finalizer function.
+.It Fl -format Ns = Ns Ar input-format
+Specify the format of the inputs following this option.
+.Ar input-format
+may be one of
+.Cm binary ,
+.Cm elf ,
+and
+.Cm default .
+.Cm default
+is a synonym for
+.Cm elf .
+.It Fl -gc-sections
+Enable garbage collection of unused sections.
+.It Fl -gdb-index
+Generate
+.Li .gdb_index
+section.
+.It Fl -hash-style Ns = Ns Ar value
+Specify hash style.
+.Ar value
+may be
+.Cm sysv ,
+.Cm gnu ,
+or
+.Cm both .
+.Cm both
+is the default.
+.It Fl -help
+Print a help message.
+.It Fl -icf Ns = Ns Cm all
+Enable identical code folding.
+.It Fl -icf Ns = Ns Cm safe
+Enable safe identical code folding.
+.It Fl -icf Ns = Ns Cm none
+Disable identical code folding.
+.It Fl -image-base Ns = Ns Ar value
+Set the base address to
+.Ar value .
+.It Fl -init Ns = Ns Ar symbol
+Specify an initializer function.
+.It Fl -lto-aa-pipeline Ns = Ns Ar value
+AA pipeline to run during LTO.
+Used in conjunction with
+.Fl -lto-newpm-passes .
+.It Fl -lto-newpm-passes Ns = Ns Ar value
+Passes to run during LTO.
+.It Fl -lto-O Ns Ar opt-level
+Optimization level for LTO.
+.It Fl -lto-partitions Ns = Ns Ar value
+Number of LTO codegen partitions.
+.It Fl L Ar dir
+Add a directory to the library search path.
+.It Fl l Ar libName
+Root name of library to use.
+.It Fl -Map Ns = Ns Ar file
+Print a link map to
+.Ar file .
+.It Fl m Ar value
+Set target emulation.
+.It Fl -no-as-needed
+Always set
+.Dv DT_NEEDED
+for shared libraries.
+.It Fl -no-color-diagnostics
+Do not use colors in diagnostics.
+.It Fl -no-define-common
+Do not assign space to common symbols.
+.It Fl -no-demangle
+Do not demangle symbol names.
+.It Fl -no-dynamic-linker
+Inhibit output of an
+.Li .interp
+section.
+.It Fl -no-gc-sections
+Disable garbage collection of unused sections.
+.It Fl -no-gnu-unique
+Disable STB_GNU_UNIQUE symbol binding.
+.It Fl -no-rosegment
+Do not put read-only non-executable sections in their own segment.
+.It Fl -no-threads
+Do not run the linker multi-threaded.
+.It Fl -no-undefined-version
+Report version scripts that refer undefined symbols.
+.It Fl -no-undefined
+Report unresolved symbols even if the linker is creating a shared library.
+.It Fl -no-whole-archive
+Restores the default behavior of loading archive members.
+.It Fl -noinhibit-exec
+Retain the executable output file whenever it is still usable.
+.It Fl -no-pie
+Do not create a position independent executable.
+.It Fl -nostdlib
+Only search directories specified on the command line.
+.It Fl -oformat Ns = Ns Ar format
+Specify the format for the output object file.
+The only supported
+.Ar format
+is
+.Cm binary ,
+which produces output with no ELF header.
+.It Fl -omagic
+Set the text and data sections to be readable and writable.
+.It Fl -opt-remarks-filename Ar file
+Write optimization remarks in YAML format to
+.Ar file .
+.It Fl -opt-remarks-with-hotness
+Include hotness information in the optimization remarks file.
+.It Fl O Ns Ar value
+Optimize output file size.
+.Ar value
+may be:
+.Pp
+.Bl -tag -width 2n -compact
+.It Cm 0
+Disable string merging.
+.It Cm 1
+Enable string merging.
+.It Cm 2
+Enable string tail merging.
+.El
+.Pp
+.Fl O Ns Cm 1
+is the default.
+.It Fl o Ar path
+Write the output executable, library, or object to
+.Ar path .
+If not specified,
+.Dv a.out
+is used as a default.
+.It Fl -pie
+Create a position independent executable.
+.It Fl -print-gc-sections
+List removed unused sections.
+.It Fl -print-map
+Print a link map to the standard output.
+.It Fl -push-state
+Save the current state of
+.Fl -as-needed ,
+.Fl -static ,
+and
+.Fl -while-archive.
+.It Fl -pop-state
+Undo the effect of
+.Fl -push-state.
+.It Fl -relocatable
+Create relocatable object file.
+.It Fl -reproduce Ns = Ns Ar value
+Dump linker invocation and input files for debugging.
+.It Fl -retain-symbols-file Ns = Ns Ar file
+Retain only the symbols listed in the file.
+.It Fl -rpath Ns = Ns Ar value
+Add a
+.Dv DT_RUNPATH
+to the output.
+.It Fl -rsp-quoting Ns = Ns Ar value
+Quoting style for response files.
+The supported values are
+.Cm windows
+and
+.Cm posix .
+.It Fl -script Ns = Ns Ar file
+Read linker script from
+.Ar file .
+.It Fl -section-start Ns = Ar section Ns = Ns Ar address
+Set address of section.
+.It Fl -shared
+Build a shared object.
+.It Fl -soname Ns = Ns Ar value
+Set
+.Dv DT_SONAME
+to
+.Ar value .
+.It Fl -sort-section Ns = Ns Ar value
+Specifies sections sorting rule when linkerscript is used.
+.It Fl -start-lib
+Start a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -strip-all
+Strip all symbols.
+.It Fl -strip-debug
+Strip debugging information.
+.It Fl -symbol-ordering-file Ns = Ns Ar file
+Lay out sections in the order specified by
+.Ar file .
+.It Fl -sysroot Ns = Ns Ar value
+Set the system root.
+.It Fl -target1-abs
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_ABS32 .
+.It Fl -target1-rel
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_REL32 .
+.It Fl -target2 Ns = Ns Ar type
+Interpret
+.Dv R_ARM_TARGET2
+as
+.Ar type ,
+where
+.Ar type
+is one of
+.Cm rel ,
+.Cm abs ,
+or
+.Cm got-rel .
+.It Fl -Tbss Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .bss
+as the sectionname.
+.It Fl -Tdata Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .data
+as the sectionname.
+.It Fl -thinlto-cache-dir Ns = Ns Ar value
+Path to ThinLTO cached object file directory.
+.It Fl -thinlto-cache-policy Ns = Ns Ar value
+Pruning policy for the ThinLTO cache.
+.It Fl -thinlto-jobs Ns = Ns Ar value
+Number of ThinLTO jobs.
+.It Fl -threads
+Run the linker multi-threaded.
+This option is enabled by default.
+.It Fl -trace-symbol Ns = Ns Ar symbol
+Trace references to
+.Ar symbol .
+.It Fl -trace
+Print the names of the input files.
+.It Fl -Ttext Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .text
+as the sectionname.
+.It Fl -undefined Ns = Ns Ar symbol
+Force
+.Ar symbol
+to be an undefined symbol during linking.
+.It Fl -unresolved-symbols Ns = Ns Ar value
+Determine how to handle unresolved symbols.
+.It Fl -verbose
+Verbose mode.
+.It Fl -version-script Ns = Ns Ar file
+Read version script from
+.Ar file .
+.It Fl V , Fl -version
+Display the version number and exit.
+.It Fl v
+Display the version number and proceed with linking if object files are
+specified.
+.It Fl -warn-backrefs
+Warn about reverse or cyclic dependencies to or between static archives.
+This can be used to ensure linker invocation remains compatible with
+traditional Unix-like linkers.
+.It Fl -warn-common
+Warn about duplicate common symbols.
+.It Fl -warn-unresolved-symbols
+Report unresolved symbols as warnings.
+.It Fl -whole-archive
+Force load of all members in a static library.
+.It Fl -wrap Ns = Ns Ar symbol
+Use wrapper functions for symbol.
+.It Fl z Ar option
+Linker option extensions.
+.Bl -tag -width indent
+.It Cm execstack
+Make the main stack executable.
+Stack permissions are recorded in the
+.Dv PT_GNU_STACK
+segment.
+.It Cm muldefs
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+This is a synonym for
+.Fl -allow-multiple-definition.
+.It Cm nocombreloc
+Disable combining and sorting multiple relocation sections.
+.It Cm nocopyreloc
+Disable the creation of copy relocations.
+.It Cm nodelete
+Set the
+.Dv DF_1_NODELETE
+flag to indicate that the object cannot be unloaded from a process.
+.It Cm nodlopen
+Set the
+.Dv DF_1_NOOPEN
+flag to indcate that the object may not be opened by
+.Xr dlopen 3 .
+.It Cm norelro
+Do not indicate that portions of the object shold be mapped read-only
+after initial relocation processing.
+The object will omit the
+.Dv PT_GNU_RELRO
+segment.
+.It Cm notext
+Allow relocations against read-only segments.
+Sets the
+.Dv DT_TEXTREL flag in the
+.Dv DYNAMIC
+section.
+.It Cm now
+Set the
+.Dv DF_BIND_NOW
+flag to indicate that the run-time loader should perform all relocation
+processing as part of object initialization.
+By default relocations may be performed on demand.
+.It Cm origin
+Set the
+.Dv DF_ORIGIN
+flag to indicate that the object requires
+$ORIGIN
+processing.
+.It Cm retpolineplt
+Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
+.It Cm rodynamic
+Make the
+.Li .dynamic
+section read-only.
+The
+.Dv DT_DEBUG
+tag will not be emitted.
+.It Cm stack-size Ns = Ns Ar size
+Set the main thread's stack size to
+.Ar size .
+The stack size is recorded as the size of the
+.Ar size .
+.Dv PT_GNU_STACK
+program segment.
+.It Cm text
+Do not allow relocations against read-only segments.
+This is the default.
+.It Cm wxneeded
+Create a
+.Dv PT_OPENBSD_WXNEEDED
+segment.
+.El
+.El
+.Sh IMPLEMENTATION NOTES
+.Nm Ap s
+handing of archive files (those with a
+.Pa .a
+file extension) is different from traditional linkers used on Unix-like
+systems.
+.Pp
+Traditional linkers maintain a set of undefined symbols during linking.
+The linker processes each file in the order in which it appears on the
+command line, until the set of undefined symbols becomes empty.
+An object file is linked into the output object when it is encountered,
+with its undefined symbols added to the set.
+Upon encountering an archive file a traditional linker searches the objects
+contained therein, and processes those that satisfy symbols in the unresolved
+set.
+.Pp
+Handling mutually dependent archives may be awkward when using a traditional
+linker.
+Archive files may have to be specified multiple times, or the special command
+line options
+.Fl -start-group
+and
+.Fl -end-group
+may be used to have the linker loop over the files in the group until no new
+symbols are added to the set.
+.Pp
+.Nm
+records all symbols found in objects and archives as it iterates over
+command line arguments.
+When
+.Nm
+encounters an undefined symbol that can be resolved by an object file
+contained in a previously processed archive file, it immediately extracts
+and links it into the output object.
+.Pp
+With certain archive inputs
+.Nm
+may produce different results compared to traditional linkers.
+In practice, large bodies of third party software have been linked with
+.Nm
+without material issues.
+.Pp
+The
+.Fl -warn-backrefs
+option may be used to identify a linker invocation that may be incompatible
+with traditional Unix-like linker behavior.
diff --git a/docs/windows_support.rst b/docs/windows_support.rst
index 6b06d29afafd..780c663a5379 100644
--- a/docs/windows_support.rst
+++ b/docs/windows_support.rst
@@ -56,9 +56,8 @@ Module-definition file
``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.
+ :good:`Done`. LLD can emit PDBs that are at parity with those generated by
+ link.exe. However, LLD does not support /DEBUG:FASTLINK.
Building LLD
diff --git a/include/lld/Common/Driver.h b/include/lld/Common/Driver.h
index 15ec3cd44cb5..f6d92933af62 100644
--- a/include/lld/Common/Driver.h
+++ b/include/lld/Common/Driver.h
@@ -30,7 +30,7 @@ bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
}
namespace mach_o {
-bool link(llvm::ArrayRef<const char *> Args,
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
}
diff --git a/include/lld/Common/ErrorHandler.h b/include/lld/Common/ErrorHandler.h
index 8ae6f46ac59e..f17f7cc99035 100644
--- a/include/lld/Common/ErrorHandler.h
+++ b/include/lld/Common/ErrorHandler.h
@@ -7,21 +7,62 @@
//
//===----------------------------------------------------------------------===//
//
-// In LLD, we have three levels of errors: fatal, error or warn.
+// We designed lld's error handlers with the following goals in mind:
//
-// Fatal makes the program exit immediately with an error message.
-// You shouldn't use it except for reporting a corrupted input file.
+// - Errors can occur at any place where we handle user input, but we don't
+// want them to affect the normal execution path too much. Ideally,
+// handling errors should be as simple as reporting them and exit (but
+// without actually doing exit).
//
-// Error prints out an error message and increment a global variable
-// ErrorCount to record the fact that we met an error condition. It does
-// not exit, so it is safe for a lld-as-a-library use case. It is generally
-// useful because it can report more than one error in a single run.
+// In particular, the design to wrap all functions that could fail with
+// ErrorOr<T> is rejected because otherwise we would have to wrap a large
+// number of functions in lld with ErrorOr. With that approach, if some
+// function F can fail, not only F but all functions that transitively call
+// F have to be wrapped with ErrorOr. That seemed too much.
//
-// Warn doesn't do anything but printing out a given message.
+// - Finding only one error at a time is not sufficient. We want to find as
+// many errors as possible with one execution of the linker. That means the
+// linker needs to keep running after a first error and give up at some
+// checkpoint (beyond which it would find cascading, false errors caused by
+// the previous errors).
//
-// It is not recommended to use llvm::outs() or llvm::errs() directly
-// in LLD because they are not thread-safe. The functions declared in
-// this file are mutually excluded, so you want to use them instead.
+// - We want a simple interface to report errors. Unlike Clang, the data we
+// handle is compiled binary, so we don't need an error reporting mechanism
+// that's as sophisticated as the one that Clang has.
+//
+// The current lld's error handling mechanism is simple:
+//
+// - When you find an error, report it using error() and continue as far as
+// you can. An internal error counter is incremented by one every time you
+// call error().
+//
+// A common idiom to handle an error is calling error() and then returning
+// a reasonable default value. For example, if your function handles a
+// user-supplied alignment value, and if you find an invalid alignment
+// (e.g. 17 which is not 2^n), you may report it using error() and continue
+// as if it were alignment 1 (which is the simplest reasonable value).
+//
+// Note that you should not continue with an invalid value; that breaks the
+// internal consistency. You need to maintain all variables have some sane
+// value even after an error occurred. So, when you have to continue with
+// some value, always use a dummy value.
+//
+// - Find a reasonable checkpoint at where you want to stop the linker, and
+// add code to return from the function if errorCount() > 0. In most cases,
+// a checkpoint already exists, so you don't need to do anything for this.
+//
+// This interface satisfies all the goals that we mentioned above.
+//
+// You should never call fatal() except for reporting a corrupted input file.
+// fatal() immediately terminates the linker, so the function is not desirable
+// if you are using lld as a subroutine in other program, and with that you
+// can find only one error at a time.
+//
+// warn() doesn't do anything but printing out a given message.
+//
+// It is not recommended to use llvm::outs() or llvm::errs() directly in lld
+// because they are not thread-safe. The functions declared in this file are
+// thread-safe.
//
//===----------------------------------------------------------------------===//
@@ -34,6 +75,10 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
+namespace llvm {
+class DiagnosticInfo;
+}
+
namespace lld {
class ErrorHandler {
@@ -74,6 +119,9 @@ inline uint64_t errorCount() { return errorHandler().ErrorCount; }
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+void diagnosticHandler(const llvm::DiagnosticInfo &DI);
+void checkError(Error E);
+
// check functions are convenient functions to strip errors
// from error-or-value objects.
template <class T> T check(ErrorOr<T> E) {
diff --git a/include/lld/Common/Strings.h b/include/lld/Common/Strings.h
index 1a63f75f9ecf..e17b25763781 100644
--- a/include/lld/Common/Strings.h
+++ b/include/lld/Common/Strings.h
@@ -10,14 +10,40 @@
#ifndef LLD_STRINGS_H
#define LLD_STRINGS_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/GlobPattern.h"
#include <string>
+#include <vector>
namespace lld {
// Returns a demangled C++ symbol name. If Name is not a mangled
// name, it returns Optional::None.
llvm::Optional<std::string> demangleItanium(llvm::StringRef Name);
+llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
+
+std::vector<uint8_t> parseHex(llvm::StringRef S);
+bool isValidCIdentifier(llvm::StringRef S);
+
+// Write the contents of the a buffer to a file
+void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
+
+// This class represents multiple glob patterns.
+class StringMatcher {
+public:
+ StringMatcher() = default;
+ explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat);
+
+ bool match(llvm::StringRef S) const;
+
+private:
+ std::vector<llvm::GlobPattern> Patterns;
+};
+
+inline llvm::ArrayRef<uint8_t> toArrayRef(llvm::StringRef S) {
+ return {reinterpret_cast<const uint8_t *>(S.data()), S.size()};
}
+} // namespace lld
#endif
diff --git a/include/lld/Common/TargetOptionsCommandFlags.h b/include/lld/Common/TargetOptionsCommandFlags.h
index 9c4ff7cea3fb..8443b184aa70 100644
--- a/include/lld/Common/TargetOptionsCommandFlags.h
+++ b/include/lld/Common/TargetOptionsCommandFlags.h
@@ -18,4 +18,5 @@
namespace lld {
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel();
+std::string GetCPUStr();
}
diff --git a/include/lld/Common/Timer.h b/include/lld/Common/Timer.h
new file mode 100644
index 000000000000..6654af626919
--- /dev/null
+++ b/include/lld/Common/Timer.h
@@ -0,0 +1,59 @@
+//===- Timer.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_TIMER_H
+#define LLD_COMMON_TIMER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <assert.h>
+#include <chrono>
+#include <map>
+#include <memory>
+
+namespace lld {
+
+class Timer;
+
+struct ScopedTimer {
+ explicit ScopedTimer(Timer &T);
+
+ ~ScopedTimer();
+
+ void stop();
+
+ Timer *T = nullptr;
+};
+
+class Timer {
+public:
+ Timer(llvm::StringRef Name, Timer &Parent);
+
+ static Timer &root();
+
+ void start();
+ void stop();
+ void print();
+
+ double millis() const;
+
+private:
+ explicit Timer(llvm::StringRef Name);
+ void print(int Depth, double TotalDuration, bool Recurse = true) const;
+
+ std::chrono::time_point<std::chrono::high_resolution_clock> StartTime;
+ std::chrono::nanoseconds Total;
+ std::vector<Timer *> Children;
+ std::string Name;
+ Timer *Parent;
+};
+
+} // namespace lld
+
+#endif
diff --git a/include/lld/Common/Version.h b/include/lld/Common/Version.h
index 93de77df5804..23a10ed6dbf3 100644
--- a/include/lld/Common/Version.h
+++ b/include/lld/Common/Version.h
@@ -18,7 +18,7 @@
#include "llvm/ADT/StringRef.h"
namespace lld {
-/// \brief Retrieves a string representing the complete lld version.
+/// Retrieves a string representing the complete lld version.
std::string getLLDVersion();
}
diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h
index 6229d67e25a5..ba10b45411f1 100644
--- a/include/lld/Core/DefinedAtom.h
+++ b/include/lld/Core/DefinedAtom.h
@@ -18,7 +18,7 @@
namespace lld {
class File;
-/// \brief The fundamental unit of linking.
+/// 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
@@ -179,10 +179,10 @@ public:
};
enum DynamicExport {
- /// \brief The linker may or may not export this atom dynamically depending
+ /// 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.
+ /// The linker will always export this atom dynamically.
dynamicExportAlways,
};
@@ -212,26 +212,26 @@ public:
}
};
- /// \brief returns a value for the order of this Atom within its file.
+ /// 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
+ /// 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.
+ /// 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.
+ /// 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
@@ -239,48 +239,48 @@ public:
/// not by the OS loader.
virtual Scope scope() const = 0;
- /// \brief Whether the linker should use direct or indirect access to this
+ /// 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.
+ /// 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.
+ /// 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
+ /// 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
+ /// 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
+ /// 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.
+ /// 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.
+ /// Under which conditions should this atom be dynamically exported.
virtual DynamicExport dynamicExport() const {
return dynamicExportNormal;
}
- /// \brief Code model used by the atom.
+ /// Code model used by the atom.
virtual CodeModel codeModel() const { return codeNA; }
- /// \brief Returns the OS memory protections required for this atom's content
+ /// 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
+ /// returns a reference to the raw (unrelocated) bytes of this Atom's
/// content.
virtual ArrayRef<uint8_t> rawContent() const = 0;
@@ -317,10 +317,10 @@ public:
const void *_it;
};
- /// \brief Returns an iterator to the beginning of this Atom's References.
+ /// 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.
+ /// Returns an iterator to the end of this Atom's References.
virtual reference_iterator end() const = 0;
/// Adds a reference to this atom.
@@ -361,11 +361,11 @@ protected:
~DefinedAtom() override = default;
- /// \brief Returns a pointer to the Reference object that the abstract
+ /// 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
+ /// Adjusts the abstract iterator to "point" to the next Reference
/// object for this Atom.
virtual void incrementIterator(const void *&iter) const = 0;
};
diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h
index 20418688dfa0..54f533576a4b 100644
--- a/include/lld/Core/File.h
+++ b/include/lld/Core/File.h
@@ -43,7 +43,7 @@ class File {
public:
virtual ~File();
- /// \brief Kinds of files that are supported.
+ /// Kinds of files that are supported.
enum Kind {
kindErrorObject, ///< a error object file (.o)
kindNormalizedObject, ///< a normalized file (.o)
@@ -59,7 +59,7 @@ public:
kindArchiveLibrary ///< archive (.a)
};
- /// \brief Returns file kind. Need for dyn_cast<> on File objects.
+ /// Returns file kind. Need for dyn_cast<> on File objects.
Kind kind() const {
return _kind;
}
@@ -114,10 +114,8 @@ 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;
+ using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&);
+ using DerefFn = T* (*)(OwningAtomPtr<T>&);
typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
ConstDerefFn> ConstItTy;
@@ -174,19 +172,19 @@ public:
AtomVector<T> &_v;
};
- /// \brief Must be implemented to return the AtomVector object for
+ /// 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
+ /// 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
+ /// 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
+ /// Must be implemented to return the AtomVector object for
/// all AbsoluteAtoms in this File.
virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
@@ -196,7 +194,7 @@ public:
/// 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(),
+ /// 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).
@@ -214,12 +212,12 @@ public:
}
protected:
- /// \brief only subclasses of File can be instantiated
+ /// 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
+ /// 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(); }
diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h
index 162375905e17..939d64557587 100644
--- a/include/lld/Core/Instrumentation.h
+++ b/include/lld/Core/Instrumentation.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
+/// Provide an Instrumentation API that optionally uses VTune interfaces.
///
//===----------------------------------------------------------------------===//
@@ -24,7 +24,7 @@
namespace lld {
#ifdef LLD_HAS_VTUNE
-/// \brief A unique global scope for instrumentation data.
+/// 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.
@@ -38,7 +38,7 @@ public:
__itt_domain *operator->() const { return _domain; }
};
-/// \brief A global reference to a string constant.
+/// 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.
@@ -54,7 +54,7 @@ public:
operator __itt_string_handle *() const { return _handle; }
};
-/// \brief A task on a single thread. Nests within other tasks.
+/// 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.
@@ -68,7 +68,7 @@ class ScopedTask {
ScopedTask &operator=(const ScopedTask &) = delete;
public:
- /// \brief Create a task in Domain \p d named \p s.
+ /// 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);
}
@@ -83,7 +83,7 @@ public:
return *this;
}
- /// \brief Prematurely end this task.
+ /// Prematurely end this task.
void end() {
if (_domain)
__itt_task_end(_domain);
@@ -93,7 +93,7 @@ public:
~ScopedTask() { end(); }
};
-/// \brief A specific point in time. Allows metadata to be associated.
+/// A specific point in time. Allows metadata to be associated.
class Marker {
public:
Marker(const Domain &d, const StringHandle &s) {
diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h
index eb9510cbd215..52ab1a2480e8 100644
--- a/include/lld/Core/LinkingContext.h
+++ b/include/lld/Core/LinkingContext.h
@@ -16,7 +16,6 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <memory>
@@ -31,7 +30,7 @@ class Writer;
class Node;
class SharedLibraryFile;
-/// \brief The LinkingContext class encapsulates "what and how" to link.
+/// 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
@@ -167,10 +166,10 @@ public:
/// 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.
+ /// is written to the global error handler.
///
/// \returns true if there is an error with the current settings.
- bool validate(raw_ostream &diagnostics);
+ bool validate();
/// Formats symbol name for use in error messages.
virtual std::string demangle(StringRef symbolName) const = 0;
@@ -250,7 +249,7 @@ protected:
private:
/// Validate the subclass bits. Only called by validate.
- virtual bool validateImpl(raw_ostream &diagnostics) = 0;
+ virtual bool validateImpl() = 0;
};
} // end namespace lld
diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h
index 2ea65ae13ace..f2ef10f406f2 100644
--- a/include/lld/Core/PassManager.h
+++ b/include/lld/Core/PassManager.h
@@ -20,7 +20,7 @@ namespace lld {
class SimpleFile;
class Pass;
-/// \brief Owns and runs a collection of passes.
+/// Owns and runs a collection of passes.
///
/// This class is currently just a container for passes and a way to run them.
///
@@ -40,7 +40,7 @@ public:
}
private:
- /// \brief Passes in the order they should run.
+ /// Passes in the order they should run.
std::vector<std::unique_ptr<Pass>> _passes;
};
} // end namespace lld
diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h
index c7baf86af61f..6cf6282ff39c 100644
--- a/include/lld/Core/Reader.h
+++ b/include/lld/Core/Reader.h
@@ -32,7 +32,7 @@ class File;
class LinkingContext;
class MachOLinkingContext;
-/// \brief An abstract class for reading object files, library files, and
+/// 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.
@@ -46,14 +46,14 @@ public:
/// 2) the whole file content buffer if the above is not enough.
virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
- /// \brief Parse a supplied buffer (already filled with the contents of a
+ /// 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
+/// An abstract class for handling alternate yaml representations
/// of object files.
///
/// The YAML syntax allows "tags" which are used to specify the type of
diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h
index fb62a779c0a5..5157c9fddc1a 100644
--- a/include/lld/Core/Resolver.h
+++ b/include/lld/Core/Resolver.h
@@ -28,7 +28,7 @@ namespace lld {
class Atom;
class LinkingContext;
-/// \brief The Resolver is responsible for merging all input object files
+/// The Resolver is responsible for merging all input object files
/// and producing a merged graph.
class Resolver {
public:
@@ -50,7 +50,7 @@ public:
// Handle a shared library file.
llvm::Error handleSharedLibrary(File &);
- /// @brief do work of merging and resolving and return list
+ /// do work of merging and resolving and return list
bool resolve();
std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
@@ -61,7 +61,7 @@ private:
bool undefinesAdded(int begin, int end);
File *getFile(int &index);
- /// \brief The main function that iterates over the files to resolve
+ /// The main function that iterates over the files to resolve
bool resolveUndefines();
void updateReferences();
void deadStripOptimize();
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
index 3aa7abf5d12b..feeed6ae473b 100644
--- a/include/lld/Core/Simple.h
+++ b/include/lld/Core/Simple.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide simple implementations for Atoms and File.
+/// Provide simple implementations for Atoms and File.
///
//===----------------------------------------------------------------------===//
diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h
index 9c39a6ed507c..156c56eafbf7 100644
--- a/include/lld/Core/SymbolTable.h
+++ b/include/lld/Core/SymbolTable.h
@@ -12,7 +12,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/DJB.h"
#include <cstring>
#include <map>
#include <vector>
@@ -27,35 +27,35 @@ class ResolverOptions;
class SharedLibraryAtom;
class UndefinedAtom;
-/// \brief The SymbolTable class is responsible for coalescing atoms.
+/// 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
+ /// add atom to symbol table
bool add(const DefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const UndefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const SharedLibraryAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const AbsoluteAtom &);
- /// @brief returns atom in symbol table for specified name (or nullptr)
+ /// returns atom in symbol table for specified name (or nullptr)
const Atom *findByName(StringRef sym);
- /// @brief returns vector of remaining UndefinedAtoms
+ /// returns vector of remaining UndefinedAtoms
std::vector<const UndefinedAtom *> undefines();
- /// @brief if atom has been coalesced away, return replacement, else return atom
+ /// 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
+ /// if atom has been coalesced away, return true
bool isCoalescedAway(const Atom *);
private:
@@ -65,7 +65,7 @@ private:
static StringRef getEmptyKey() { return StringRef(); }
static StringRef getTombstoneKey() { return StringRef(" ", 1); }
static unsigned getHashValue(StringRef const val) {
- return llvm::HashString(val);
+ return llvm::djbHash(val, 0);
}
static bool isEqual(StringRef const lhs, StringRef const rhs) {
return lhs.equals(rhs);
diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt
index 8b523045de75..2aa61ff8612d 100644
--- a/include/lld/Core/TODO.txt
+++ b/include/lld/Core/TODO.txt
@@ -6,9 +6,6 @@ include/lld/Core
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`__.
diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h
index 1f0ca4cda41f..1cdfabefebd7 100644
--- a/include/lld/Core/Writer.h
+++ b/include/lld/Core/Writer.h
@@ -20,17 +20,17 @@ class File;
class LinkingContext;
class MachOLinkingContext;
-/// \brief The Writer is an abstract class for writing object files, shared
+/// 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
+ /// 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
+ /// 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>> &) {}
diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h
index 9eefa8c4d944..fde65880c3e3 100644
--- a/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -89,7 +89,7 @@ public:
bool exportDynamicSymbols);
void addPasses(PassManager &pm) override;
- bool validateImpl(raw_ostream &diagnostics) override;
+ bool validateImpl() override;
std::string demangle(StringRef symbolName) const override;
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
@@ -201,7 +201,7 @@ public:
uint32_t swiftVersion() const { return _swiftVersion; }
- /// \brief Checks whether a given path on the filesystem exists.
+ /// 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)
@@ -211,7 +211,7 @@ public:
/// 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
+ /// 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
@@ -219,7 +219,7 @@ public:
/// 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
+ /// 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
@@ -228,7 +228,7 @@ public:
llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
StringRef libName) const;
- /// \brief Iterates through all search path entries looking for libName (as
+ /// Iterates through all search path entries looking for libName (as
/// specified by -lFoo).
llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
@@ -236,11 +236,11 @@ public:
/// the path with syslibroot.
void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
- /// \brief Iterates through all framework directories looking for
+ /// 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.
+ /// 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
@@ -249,28 +249,28 @@ public:
/// installed dynamic library.
uint32_t compatibilityVersion() const { return _compatibilityVersion; }
- /// \brief The dylib's current version, in the the raw uint32 format.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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
@@ -282,7 +282,7 @@ public:
/// loaded flat_namespace dylibs must be resolvable at build time.
bool useFlatNamespace() const { return _flatNamespace; }
- /// \brief How to handle undefined symbols.
+ /// How to handle undefined symbols.
///
/// Options are:
/// * error: Report an error and terminate linking.
@@ -294,7 +294,7 @@ public:
/// runtime.
UndefinedMode undefinedMode() const { return _undefinedMode; }
- /// \brief The path to the executable that will load the bundle at runtime.
+ /// 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
@@ -331,7 +331,7 @@ public:
/// 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.
+ /// Add a section based on a command-line sectcreate option.
void addSectCreateSection(StringRef seg, StringRef sect,
std::unique_ptr<MemoryBuffer> content);
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
index 5de863aa7f37..0f225c322122 100644
--- a/lib/Core/LinkingContext.cpp
+++ b/lib/Core/LinkingContext.cpp
@@ -20,8 +20,8 @@ LinkingContext::LinkingContext() = default;
LinkingContext::~LinkingContext() = default;
-bool LinkingContext::validate(raw_ostream &diagnostics) {
- return validateImpl(diagnostics);
+bool LinkingContext::validate() {
+ return validateImpl();
}
llvm::Error LinkingContext::writeFile(const File &linkedFile) const {
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 097a8177ea1f..ff67c282f47e 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lld_library(lldDriver
Support
LINK_LIBS
+ lldCommon
lldCore
lldMachO
lldReaderWriter
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
index a019e9c32800..ad22845207e1 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -13,6 +13,8 @@
///
//===----------------------------------------------------------------------===//
+#include "lld/Common/Args.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/LLVM.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/Error.h"
@@ -110,11 +112,11 @@ parseMemberFiles(std::unique_ptr<File> file) {
return members;
}
-std::vector<std::unique_ptr<File>>
-loadFile(MachOLinkingContext &ctx, StringRef path,
- raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+std::vector<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx,
+ StringRef path, bool wholeArchive,
+ bool upwardDylib) {
if (ctx.logInputFiles())
- diag << path << "\n";
+ message(path);
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
if (std::error_code ec = mbOrErr.getError())
@@ -155,10 +157,9 @@ static std::string canonicalizePath(StringRef path) {
}
static void addFile(StringRef path, MachOLinkingContext &ctx,
- bool loadWholeArchive,
- bool upwardDylib, raw_ostream &diag) {
+ bool loadWholeArchive, bool upwardDylib) {
std::vector<std::unique_ptr<File>> files =
- loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+ loadFile(ctx, path, loadWholeArchive, upwardDylib);
for (std::unique_ptr<File> &file : files)
ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
}
@@ -166,8 +167,7 @@ static void addFile(StringRef path, MachOLinkingContext &ctx,
// 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) {
+ MachOLinkingContext &ctx) {
// Map in export list file.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(exportFilePath);
@@ -197,8 +197,7 @@ static std::error_code parseExportsList(StringRef exportFilePath,
/// libfrob.a(bar.o):_bar
/// x86_64:_foo64
static std::error_code parseOrderFile(StringRef orderFilePath,
- MachOLinkingContext &ctx,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx) {
// Map in order file.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(orderFilePath);
@@ -252,8 +251,7 @@ static std::error_code parseOrderFile(StringRef orderFilePath,
// per line. The <dir> prefix is prepended to each partial path.
//
static llvm::Error loadFileList(StringRef fileListPath,
- MachOLinkingContext &ctx, bool forceLoad,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx, bool forceLoad) {
// If there is a comma, split off <dir>.
std::pair<StringRef, StringRef> opt = fileListPath.split(',');
StringRef filePath = opt.first;
@@ -286,9 +284,9 @@ static llvm::Error loadFileList(StringRef fileListPath,
+ "'");
}
if (ctx.testingFileUsage()) {
- diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+ message("Found filelist entry " + canonicalizePath(path));
}
- addFile(path, ctx, forceLoad, false, diagnostics);
+ addFile(path, ctx, forceLoad, false);
buffer = lineAndRest.second;
}
return llvm::Error::success();
@@ -317,8 +315,7 @@ static void parseLLVMOptions(const LinkingContext &ctx) {
namespace lld {
namespace mach_o {
-bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
- raw_ostream &diagnostics) {
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
// Parse command line options using DarwinLdOptions.td
DarwinLdOptTable table;
unsigned missingIndex;
@@ -326,17 +323,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("missing arg value for '" +
+ Twine(parsedArgs.getArgString(missingIndex)) + "' expected " +
+ Twine(missingCount) + " argument(s).");
return false;
}
for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) {
- diagnostics << "warning: ignoring unknown argument: "
- << unknownArg->getAsString(parsedArgs) << "\n";
+ warn("ignoring unknown argument: " +
+ Twine(unknownArg->getAsString(parsedArgs)));
}
+ errorHandler().Verbose = parsedArgs.hasArg(OPT_v);
+ errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
+
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
bool isStaticExecutable = false;
@@ -367,8 +367,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("unknown arch named '" + Twine(archStr->getValue()) + "'");
return false;
}
}
@@ -386,7 +385,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("-arch not specified and could not be inferred");
return false;
}
}
@@ -402,7 +401,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::macOSX;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed macosx_version_min value\n";
+ error("malformed macosx_version_min value");
return false;
}
break;
@@ -410,7 +409,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::iOS;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed ios_version_min value\n";
+ error("malformed ios_version_min value");
return false;
}
break;
@@ -418,7 +417,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::iOS_simulator;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed ios_simulator_version_min value\n";
+ error("malformed ios_simulator_version_min value");
return false;
}
break;
@@ -452,14 +451,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("image_base expects a hex number");
return false;
} else if (baseAddress < ctx.pageZeroSize()) {
- diagnostics << "error: image_base overlaps with __PAGEZERO\n";
+ error("image_base overlaps with __PAGEZERO");
return false;
} else if (baseAddress % ctx.pageSize()) {
- diagnostics << "error: image_base must be a multiple of page size ("
- << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+ error("image_base must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
return false;
}
@@ -488,13 +487,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
+ error("-compatibility_version can only be used with -dylib");
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
- diagnostics << "error: -compatibility_version value is malformed\n";
+ error("-compatibility_version value is malformed");
return false;
}
ctx.setCompatibilityVersion(parsedVers);
@@ -502,12 +500,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("-current_version can only be used with -dylib");
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
- diagnostics << "error: -current_version value is malformed\n";
+ error("-current_version value is malformed");
return false;
}
ctx.setCurrentVersion(parsedVers);
@@ -526,17 +524,19 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
alignStr += 2;
unsigned long long alignValue;
if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
- diagnostics << "error: -sectalign alignment value '"
- << alignStr << "' not a valid number\n";
+ error("-sectalign alignment value '" + Twine(alignStr) +
+ "' not a valid number");
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";
+ std::string Msg;
+ llvm::raw_string_ostream OS(Msg);
+ OS << "alignment for '-sectalign " << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using " << llvm::format("0x%08X", align);
+ OS.flush();
+ warn(Msg);
}
ctx.addSectionAlignment(segName, sectName, align);
}
@@ -562,18 +562,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ warn("-keep_private_externs only used in -r mode");
}
// 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";
- }
- }
+ if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info))
+ if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue()))
+ warn(ec.message() + ", processing '-dependency_info " +
+ depInfo->getValue());
// 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
@@ -639,31 +635,28 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
+ if (errorHandler().Verbose) {
+ message("Library search paths:");
for (auto path : ctx.searchDirs()) {
- diagnostics << " " << path << '\n';
+ message(" " + path);
}
- diagnostics << "Framework search paths:\n";
+ message("Framework search paths:");
for (auto path : ctx.frameworkDirs()) {
- diagnostics << " " << path << '\n';
+ message(" " + path);
}
}
// 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;
+ error("-exported_symbols_list cannot be combined with "
+ "-unexported_symbol[s_list]");
+ 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";
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-exported_symbols_list " +
+ expFile->getValue());
return false;
}
}
@@ -671,9 +664,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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;
+ error("-exported_symbol cannot be combined with "
+ "-unexported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
ctx.addExportSymbol(symbol->getValue());
@@ -682,17 +675,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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;
+ error("-unexported_symbols_list cannot be combined with "
+ "-exported_symbol[s_list]");
+ 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";
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-unexported_symbols_list " +
+ expFile->getValue());
return false;
}
}
@@ -700,9 +690,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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;
+ error("-unexported_symbol cannot be combined with "
+ "-exported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
ctx.addExportSymbol(symbol->getValue());
@@ -711,30 +701,26 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
- }
- }
+ if (mod->getOption().getID() == OPT_multi_module)
+ warn("-multi_module is obsolete and being ignored");
+ else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB)
+ warn("-single_module being ignored. It is only for use when producing a "
+ "dylib");
}
// 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";
+ error("-objc_gc_compaction is not supported");
return false;
}
if (parsedArgs.getLastArg(OPT_objc_gc)) {
- diagnostics << "error: -objc_gc is not supported\n";
+ error("-objc_gc is not supported");
return false;
}
if (parsedArgs.getLastArg(OPT_objc_gc_only)) {
- diagnostics << "error: -objc_gc_only is not supported\n";
+ error("-objc_gc_only is not supported");
return false;
}
@@ -746,22 +732,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("-pie can only be used when targeting Mac OS X 10.5 or later");
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";
+ error("-pie can only be used when targeting iOS 4.2 or later");
return false;
}
break;
case MachOLinkingContext::OS::iOS_simulator:
if (pie->getOption().getID() == OPT_no_pie) {
- diagnostics << "iOS simulator programs must be built PIE\n";
+ error("iOS simulator programs must be built PIE");
return false;
}
break;
@@ -774,12 +758,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ warn(pie->getSpelling() +
+ " being ignored. It is only used when linking main executables");
break;
default:
- diagnostics << pie->getSpelling()
- << " can only used when linking main executables\n";
+ error(pie->getSpelling() +
+ " can only used when linking main executables");
return false;
}
}
@@ -934,7 +918,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
uint32_t sdkVersion = 0;
if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
sdkVersion)) {
- diagnostics << "error: malformed sdkVersion value\n";
+ error("malformed sdkVersion value");
return false;
}
ctx.setSdkVersion(sdkVersion);
@@ -943,9 +927,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
+ warn("-sdk_version is required when emitting min version load command. "
+ "Setting sdk version to match provided min version");
ctx.setSdkVersion(ctx.osMinVersion());
}
@@ -954,7 +937,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
uint64_t version = 0;
if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
version)) {
- diagnostics << "error: malformed source_version value\n";
+ error("malformed source_version value");
return false;
}
ctx.setSourceVersion(version);
@@ -964,12 +947,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("stack_size expects a hex number");
return false;
}
if ((stackSizeVal % ctx.pageSize()) != 0) {
- diagnostics << "error: stack_size must be a multiple of page size ("
- << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+ error("stack_size must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
return false;
}
@@ -982,12 +965,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-order_file " + orderFile->getValue()
+ + "'");
return false;
}
}
@@ -1011,8 +991,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
+ error("invalid option to -undefined [ warning | error | suppress | "
+ "dynamic_lookup ]");
return false;
}
@@ -1026,8 +1006,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// 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";
+ error("can't use -undefined warning or suppress with "
+ "-twolevel_namespace");
return false;
}
}
@@ -1046,19 +1026,16 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
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";
- }
+ if (ctx.os() == MachOLinkingContext::OS::macOSX)
+ error("-rpath can only be used when targeting OS X 10.5 or later");
+ else
+ error("-rpath can only be used when targeting iOS 2.0 or later");
return false;
}
break;
default:
- diagnostics << "error: -rpath can only be used when creating "
- "a dynamic final linked image\n";
+ error("-rpath can only be used when creating a dynamic final linked "
+ "image");
return false;
}
@@ -1068,7 +1045,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
}
// Parse the LLVM options before we process files in case the file handling
- // makes use of things like DEBUG().
+ // makes use of things like LLVM_DEBUG().
parseLLVMOptions(ctx);
// Handle input files and sectcreate.
@@ -1079,52 +1056,46 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
default:
continue;
case OPT_INPUT:
- addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics);
+ addFile(arg->getValue(), ctx, globalWholeArchive, false);
break;
case OPT_upward_library:
- addFile(arg->getValue(), ctx, false, true, diagnostics);
+ addFile(arg->getValue(), ctx, false, true);
break;
case OPT_force_load:
- addFile(arg->getValue(), ctx, true, false, diagnostics);
+ addFile(arg->getValue(), ctx, true, false);
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";
+ error("Unable to find library for " + arg->getSpelling() +
+ arg->getValue());
return false;
} else if (ctx.testingFileUsage()) {
- diagnostics << "Found " << (upward ? "upward " : " ") << "library "
- << canonicalizePath(resolvedPath.getValue()) << '\n';
+ message(Twine("Found ") + (upward ? "upward " : " ") + "library " +
+ canonicalizePath(resolvedPath.getValue()));
}
- addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
- upward, diagnostics);
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
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";
+ error("Unable to find framework for " + arg->getSpelling() + " " +
+ arg->getValue());
return false;
} else if (ctx.testingFileUsage()) {
- diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
- << canonicalizePath(resolvedPath.getValue()) << '\n';
+ message(Twine("Found ") + (upward ? "upward " : " ") + "framework " +
+ canonicalizePath(resolvedPath.getValue()));
}
- addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
- upward, diagnostics);
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
break;
case OPT_filelist:
- if (auto ec = loadFileList(arg->getValue(),
- ctx, globalWholeArchive,
- diagnostics)) {
+ if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) {
handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) {
- diagnostics << "error: ";
- EI.log(diagnostics);
- diagnostics << ", processing '-filelist " << arg->getValue() << "'\n";
+ error(EI.message() + ", processing '-filelist " + arg->getValue());
});
return false;
}
@@ -1138,7 +1109,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
MemoryBuffer::getFile(fileName);
if (!contentOrErr) {
- diagnostics << "error: can't open -sectcreate file " << fileName << "\n";
+ error("can't open -sectcreate file " + Twine(fileName));
return false;
}
@@ -1149,12 +1120,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
}
if (ctx.getNodes().empty()) {
- diagnostics << "No input files\n";
+ error("No input files");
return false;
}
// Validate the combination of options used.
- return ctx.validate(diagnostics);
+ return ctx.validate();
}
static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
@@ -1170,9 +1141,18 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
}
/// This is where the link is actually performed.
-bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
+bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
+ raw_ostream &Error) {
+ errorHandler().LogName = llvm::sys::path::filename(args[0]);
+ errorHandler().ErrorLimitExceededMsg =
+ "too many errors emitted, stopping now (use "
+ "'-error-limit 0' to see all errors)";
+ errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
+ errorHandler().ColorDiagnostics = Error.has_colors();
+
MachOLinkingContext ctx;
- if (!parse(args, ctx, diagnostics))
+ if (!parse(args, ctx))
return false;
if (ctx.doNothing())
return true;
@@ -1214,9 +1194,10 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
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());
+ *errorHandler().ErrorOS << "Failed to run passes on file '"
+ << ctx.outputPath() << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
return false;
}
@@ -1227,11 +1208,18 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
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());
+ *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
+ << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
return false;
}
+ // Call exit() if we can to avoid calling destructors.
+ if (CanExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+
return true;
}
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
index fa07f33646e7..3bbde8bf1c1c 100644
--- a/lib/Driver/DarwinLdOptions.td
+++ b/lib/Driver/DarwinLdOptions.td
@@ -227,6 +227,14 @@ def t : Flag<["-"], "t">,
HelpText<"Print the names of the input files as ld processes them">;
def v : Flag<["-"], "v">,
HelpText<"Print linker information">;
+def error_limit : Separate<["-", "--"], "error-limit">,
+ MetaVarName<"<number>">,
+ HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+// Ignored options
+def lto_library : Separate<["-"], "lto_library">,
+ MetaVarName<"<path>">,
+ HelpText<"Ignored for compatibility with other linkers">;
// Obsolete options
def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
index 04c0bee76989..2f52d9d34312 100644
--- a/lib/ReaderWriter/FileArchive.cpp
+++ b/lib/ReaderWriter/FileArchive.cpp
@@ -38,7 +38,7 @@ namespace lld {
namespace {
-/// \brief The FileArchive class represents an Archive Library file
+/// The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
@@ -46,7 +46,7 @@ public:
: 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
+ /// 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);
@@ -77,7 +77,7 @@ public:
return file;
}
- /// \brief parse each member
+ /// parse each member
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
if (std::error_code ec = parse())
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index aee9959ca6b8..8cb6710857e3 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -674,7 +674,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
return;
case delta32Anon:
- // The value we write here should be the the delta to the target
+ // The value we write here should be 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:
@@ -690,7 +690,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
*loc64 = ref.addend() + inAtomAddress - fixupAddress;
return;
case delta64Anon:
- // The value we write here should be the the delta to the target
+ // The value we write here should be 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:
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
index f2fc34772496..37d1de432c0f 100644
--- a/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -26,6 +26,7 @@ add_lld_library(lldMachO
Support
LINK_LIBS
+ lldCommon
lldCore
lldYAML
${LLVM_PTHREAD_LIB}
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index 1e210409237f..fa0aaa103eeb 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -282,7 +282,7 @@ public:
private:
llvm::Error perform(SimpleFile &mergedFile) override {
- DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+ LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
std::map<const Atom *, const Atom *> dwarfFrames;
@@ -319,7 +319,7 @@ private:
// Finally, we can start creating pages based on these entries.
- DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
+ LLVM_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
@@ -336,11 +336,13 @@ private:
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");
+ LLVM_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())
@@ -360,7 +362,7 @@ private:
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");
+ LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
@@ -369,14 +371,15 @@ private:
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));
+ LLVM_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');
+ LLVM_DEBUG(llvm::dbgs()
+ << ", personality="
+ << unwindEntry.personalityFunction->name()
+ << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+ LLVM_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.
@@ -454,7 +457,7 @@ private:
const std::map<const Atom *, const Atom *> &dwarfFrames) {
std::vector<CompactUnwindEntry> unwindInfos;
- DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
+ LLVM_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!).
@@ -465,10 +468,10 @@ private:
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');
+ LLVM_DEBUG(llvm::dbgs()
+ << " Entry for " << atom->name() << ", final encoding="
+ << llvm::format("0x%08x", unwindInfos.back().encoding)
+ << '\n');
}
return unwindInfos;
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 7bca07eb16d6..9058e4f562e2 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -191,7 +191,7 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
// 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));
+ LLVM_DEBUG(reason = formatReason("override", lc._override, rc._override));
return lc._override < rc._override;
}
@@ -200,8 +200,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
if (leftPerms != rightPerms) {
- DEBUG(reason =
- formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+ LLVM_DEBUG(
+ reason = formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
return leftPerms < rightPerms;
}
@@ -210,7 +210,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
DefinedAtom::ContentType rightType = rightRoot->contentType();
if (leftType != rightType) {
- DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
+ LLVM_DEBUG(reason =
+ formatReason("contentType", (int)leftType, (int)rightType));
return leftType < rightType;
}
@@ -226,8 +227,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
const File *rightFile = &rightRoot->file();
if (leftFile != rightFile) {
- DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
- (int)rightFile->ordinal()));
+ LLVM_DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+ (int)rightFile->ordinal()));
return leftFile->ordinal() < rightFile->ordinal();
}
@@ -236,8 +237,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
uint64_t rightOrdinal = rightRoot->ordinal();
if (leftOrdinal != rightOrdinal) {
- DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
- (int)rightRoot->ordinal()));
+ LLVM_DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+ (int)rightRoot->ordinal()));
return leftOrdinal < rightOrdinal;
}
@@ -251,7 +252,7 @@ static bool compareAtoms(const LayoutPass::SortKey &lc,
LayoutPass::SortOverride customSorter) {
std::string reason;
bool result = compareAtomsSub(lc, rc, customSorter, reason);
- DEBUG({
+ LLVM_DEBUG({
StringRef comp = result ? "<" : ">=";
llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
<< "' " << comp << " '"
@@ -441,7 +442,7 @@ void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
/// Perform the actual pass
llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
- DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
@@ -450,12 +451,12 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
buildFollowOnTable(atomRange);
// Check the structure of followon graph if running in debug mode.
- DEBUG(checkFollowonChain(atomRange));
+ LLVM_DEBUG(checkFollowonChain(atomRange));
// Build override maps
buildOrdinalOverrideMap(atomRange);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "unsorted atoms:\n";
printDefinedAtoms(atomRange);
});
@@ -465,15 +466,15 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
[&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
return compareAtoms(l, r, _customSorter);
});
- DEBUG(checkTransitivity(vec, _customSorter));
+ LLVM_DEBUG(checkTransitivity(vec, _customSorter));
undecorate(atomRange, vec);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "sorted atoms:\n";
printDefinedAtoms(atomRange);
});
- DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
return llvm::Error::success();
}
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 4ef7a62a8297..ce423d03aae3 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "lld/Common/ErrorHandler.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "ArchHandler.h"
#include "File.h"
@@ -579,29 +580,26 @@ MachOLinkingContext::findPathForFramework(StringRef fwName) const{
return llvm::None;
}
-bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
+bool MachOLinkingContext::validateImpl() {
// 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";
+ error("-current_version can only be used with dylibs");
return false;
}
if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
- diagnostics
- << "error: -compatibility_version can only be used with dylibs\n";
+ error("-compatibility_version can only be used with dylibs");
return false;
}
if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
- diagnostics
- << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
+ error("-mark_dead_strippable_dylib can only be used with dylibs");
return false;
}
if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
- diagnostics
- << "error: -bundle_loader can only be used with Mach-O bundles\n";
+ error("-bundle_loader can only be used with Mach-O bundles");
return false;
}
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 3b07a40f9bf2..473de894894e 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -906,7 +906,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
abbrevData.getU8(&abbrevOffset);
uint32_t name;
llvm::dwarf::Form form;
- llvm::DWARFFormParams formParams = {version, addrSize, Format};
+ llvm::dwarf::FormParams formParams = {version, addrSize, Format};
TranslationUnitSource tu;
while ((name = abbrevData.getULEB128(&abbrevOffset)) |
(form = static_cast<llvm::dwarf::Form>(
@@ -1431,8 +1431,8 @@ llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
- DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
- << file->path() << "\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+ << file->path() << "\n");
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
// Create atoms from each section.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index eb8475881de8..12fb7c3c1e99 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -32,9 +32,9 @@ configure_lit_site_cfg(
set(LLD_TEST_DEPS lld)
if (NOT LLD_BUILT_STANDALONE)
list(APPEND LLD_TEST_DEPS
- FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm
- llc llvm-config llvm-objdump llvm-readelf llvm-readobj yaml2obj obj2yaml
- llvm-mc llvm-lib llvm-pdbutil opt
+ FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-dis
+ llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump
+ llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj
)
endif()
@@ -53,6 +53,12 @@ add_lit_testsuite(check-lld "Running lld test suite"
DEPENDS ${LLD_TEST_DEPS}
)
+add_lit_testsuites(LLD ${CMAKE_CURRENT_SOURCE_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
diff --git a/test/COFF/Inputs/far-arm64-abs.s b/test/COFF/Inputs/far-arm64-abs.s
new file mode 100644
index 000000000000..98ccbac5e751
--- /dev/null
+++ b/test/COFF/Inputs/far-arm64-abs.s
@@ -0,0 +1,6 @@
+.global too_far26
+.global too_far19
+.global too_far14
+too_far26 = 0x08011000
+too_far19 = 0x00111000
+too_far14 = 0x00021000
diff --git a/test/COFF/Inputs/generic.yaml b/test/COFF/Inputs/generic.yaml
new file mode 100644
index 000000000000..88c87655cf47
--- /dev/null
+++ b/test/COFF/Inputs/generic.yaml
@@ -0,0 +1,282 @@
+--- !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: 4883EC1831C0C7442414000000004889542408894C24044883C418C3
+ - 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: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004220000'
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 04000000F10000002F0000002D003C1101000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000760000002A0047110000000000000000000000001C000000000000000000000003100000000000000000006D61696E000D003E117400000001006172676300120045114F0100000400000017000000000005000D003E110010000001006172677600120045114F01000008000000170000000000050002004F110000F20000002800000000000000000000001C00000000000000020000001C00000000000000020000001700000003000000F40000001800000001000000100139E9A066A1995A99DD01F5A392F26D7C0000F30000003000000000443A5C7372635C6C6C766D6275696C645C636C5C52656C656173655C7836345C67656E657269632E63707000000000
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ ]
+ Machine: X64
+ FrontendMajor: 7
+ FrontendMinor: 0
+ FrontendBuild: 0
+ FrontendQFE: 0
+ BackendMajor: 7000
+ BackendMinor: 0
+ BackendBuild: 0
+ BackendQFE: 0
+ Version: 'clang version 7.0.0 '
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 28
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4099
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: argc
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 335
+ Flags: 0
+ BasePointerOffset: 4
+ Range:
+ OffsetStart: 23
+ ISectStart: 0
+ Range: 5
+ Gaps:
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 4096
+ Flags: [ IsParameter ]
+ VarName: argv
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 335
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 23
+ ISectStart: 0
+ Range: 5
+ Gaps:
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 28
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 2
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 23
+ LineStart: 3
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+ Kind: MD5
+ Checksum: 39E9A066A1995A99DD01F5A392F26D7C
+ - !StringTable
+ Strings:
+ - 'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+ - ''
+ - ''
+ - ''
+ Relocations:
+ - VirtualAddress: 100
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 139
+ SymbolName: .text
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 143
+ SymbolName: .text
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 174
+ SymbolName: .text
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 178
+ SymbolName: .text
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 196
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 200
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 040000000A000210700600000C0001000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F1
+ Types:
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 1648
+ Attrs: 65548
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116, 4096 ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 116
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 2
+ ArgumentList: 4097
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4098
+ Name: main
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 000000001C00000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ 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: 28
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 594448369
+ 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: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1192424177
+ Number: 4
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 48
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 149686238
+ Number: 5
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 324
+ NumberOfRelocations: 8
+ NumberOfLinenumbers: 0
+ CheckSum: 4196717433
+ Number: 6
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 68
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 485351071
+ Number: 7
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 722740324
+ Number: 8
+ - 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/globals-dia-func-collision3.obj b/test/COFF/Inputs/globals-dia-func-collision3.obj
new file mode 100644
index 000000000000..ce9b87379617
--- /dev/null
+++ b/test/COFF/Inputs/globals-dia-func-collision3.obj
Binary files differ
diff --git a/test/COFF/Inputs/globals-dia-vfunc-collision.obj b/test/COFF/Inputs/globals-dia-vfunc-collision.obj
new file mode 100644
index 000000000000..3191c3ea2b28
--- /dev/null
+++ b/test/COFF/Inputs/globals-dia-vfunc-collision.obj
Binary files differ
diff --git a/test/COFF/Inputs/globals-dia-vfunc-collision2.obj b/test/COFF/Inputs/globals-dia-vfunc-collision2.obj
new file mode 100644
index 000000000000..f40610216675
--- /dev/null
+++ b/test/COFF/Inputs/globals-dia-vfunc-collision2.obj
Binary files differ
diff --git a/test/COFF/Inputs/globals-dia-vfunc-simple.obj b/test/COFF/Inputs/globals-dia-vfunc-simple.obj
new file mode 100644
index 000000000000..f0a9b4da836d
--- /dev/null
+++ b/test/COFF/Inputs/globals-dia-vfunc-simple.obj
Binary files differ
diff --git a/test/COFF/Inputs/guardcf-align-foobar.yaml b/test/COFF/Inputs/guardcf-align-foobar.yaml
new file mode 100644
index 000000000000..7878c459a4fd
--- /dev/null
+++ b/test/COFF/Inputs/guardcf-align-foobar.yaml
@@ -0,0 +1,51 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text.foo
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 31C0C3
+ - Name: .text.bar
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: FFE1
+symbols:
+ - Name: .text.foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 3
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 3963538403
+ Number: 1
+ - Name: .text.bar
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1143549852
+ Number: 2
+ - Name: foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ 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_EXTERNAL
+...
diff --git a/test/COFF/Inputs/loadconfig-cfg-x64.s b/test/COFF/Inputs/loadconfig-cfg-x64.s
new file mode 100644
index 000000000000..1440b115f46a
--- /dev/null
+++ b/test/COFF/Inputs/loadconfig-cfg-x64.s
@@ -0,0 +1,11 @@
+# This is the _load_config_used definition needed for /guard:cf tests.
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
diff --git a/test/COFF/Inputs/natvis-1.natvis b/test/COFF/Inputs/natvis-1.natvis
new file mode 100644
index 000000000000..8797a363655e
--- /dev/null
+++ b/test/COFF/Inputs/natvis-1.natvis
@@ -0,0 +1 @@
+1st Natvis Test
diff --git a/test/COFF/Inputs/natvis-2.natvis b/test/COFF/Inputs/natvis-2.natvis
new file mode 100644
index 000000000000..50ba44306c4a
--- /dev/null
+++ b/test/COFF/Inputs/natvis-2.natvis
@@ -0,0 +1 @@
+Second Natvis Test
diff --git a/test/COFF/Inputs/natvis-3.natvis b/test/COFF/Inputs/natvis-3.natvis
new file mode 100644
index 000000000000..a10b1a120a69
--- /dev/null
+++ b/test/COFF/Inputs/natvis-3.natvis
@@ -0,0 +1 @@
+Third Natvis Test
diff --git a/test/COFF/Inputs/order.yaml b/test/COFF/Inputs/order.yaml
new file mode 100644
index 000000000000..02e91d12261d
--- /dev/null
+++ b/test/COFF/Inputs/order.yaml
@@ -0,0 +1,76 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: unrelated2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 2
+ 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
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn4
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn1
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/otherFunc.s b/test/COFF/Inputs/otherFunc.s
new file mode 100644
index 000000000000..ae8b9228a61a
--- /dev/null
+++ b/test/COFF/Inputs/otherFunc.s
@@ -0,0 +1,7 @@
+.global otherFunc
+.global MessageBoxA
+.text
+otherFunc:
+ ret
+MessageBoxA:
+ ret
diff --git a/test/COFF/Inputs/pdb-file-statics-a.yaml b/test/COFF/Inputs/pdb-file-statics-a.yaml
new file mode 100644
index 000000000000..957eb5aee869
--- /dev/null
+++ b/test/COFF/Inputs/pdb-file-statics-a.yaml
@@ -0,0 +1,1866 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_OBJNAME
+ ObjNameSym:
+ Signature: 0
+ ObjectName: 'D:\src\llvmbuild\cl\Debug\x64\a.obj'
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ SecurityChecks, HotPatch ]
+ Machine: X64
+ FrontendMajor: 19
+ FrontendMinor: 11
+ FrontendBuild: 25547
+ FrontendQFE: 0
+ BackendMajor: 19
+ BackendMinor: 11
+ BackendBuild: 25547
+ BackendQFE: 0
+ Version: 'Microsoft (R) Optimizing Compiler'
+ - !Symbols
+ Records:
+ - Kind: S_LDATA32
+ DataSym:
+ Type: 116
+ DisplayName: x
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4193
+ UDTName: '__vc_attributes::event_sourceAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4185
+ UDTName: '__vc_attributes::event_sourceAttribute::optimize_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4182
+ UDTName: '__vc_attributes::event_sourceAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4178
+ UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4172
+ UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4168
+ UDTName: '__vc_attributes::helper_attributes::usageAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4162
+ UDTName: '__vc_attributes::helper_attributes::usageAttribute::usage_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4158
+ UDTName: '__vc_attributes::threadingAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4150
+ UDTName: '__vc_attributes::threadingAttribute::threading_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4146
+ UDTName: '__vc_attributes::aggregatableAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4138
+ UDTName: '__vc_attributes::aggregatableAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4134
+ UDTName: '__vc_attributes::event_receiverAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4124
+ UDTName: '__vc_attributes::event_receiverAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4120
+ UDTName: '__vc_attributes::moduleAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4106
+ UDTName: '__vc_attributes::moduleAttribute::type_e'
+ - !FileChecksums
+ Checksums:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp'
+ Kind: MD5
+ Checksum: 70DD90BF2C1A2E8D7C450DFA55E3062D
+ - !InlineeLines
+ HasExtraFiles: false
+ Sites:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp'
+ LineNum: 8
+ Inlinee: 4099
+ - !StringTable
+ Strings:
+ - 'd:\src\llvmbuild\cl\debug\x64\a.cpp'
+ - 'D:\src\llvmbuild\cl\Debug\x64\a.obj'
+ - !Symbols
+ Records:
+ - Kind: S_BUILDINFO
+ BuildInfoSym:
+ BuildId: 4203
+ Relocations:
+ - VirtualAddress: 132
+ SymbolName: '?x@@3HA'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 136
+ SymbolName: '?x@@3HA'
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Types:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116 ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 3
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 1
+ ArgumentList: 4096
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 1648
+ Attrs: 65548
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: a
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116, 4098 ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 116
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 2
+ ArgumentList: 4100
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4101
+ Name: main
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: b
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::moduleAttribute'
+ UniqueName: '.?AUmoduleAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: dll
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: exe
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: service
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4
+ Name: unspecified
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: EXE
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: SERVICE
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 6
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4105
+ Name: '__vc_attributes::moduleAttribute::type_e'
+ UniqueName: '.?AW4type_e@moduleAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'd:\src\llvmbuild\cl\debug\x64\predefined c++ attributes (compiler internal)'
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4106
+ SourceFile: 4107
+ LineNumber: 482
+ - Kind: LF_MODIFIER
+ Modifier:
+ ModifiedType: 112
+ Modifiers: [ None, Const ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4109
+ Attrs: 65548
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4106, 4110, 4110, 4110, 116, 48, 4110, 116,
+ 4110, 4110, 116, 48, 48, 4110, 4110 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4104
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4104
+ ThisType: 4112
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 15
+ ArgumentList: 4111
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4106 ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4104
+ ThisType: 4112
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4114
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4104
+ ThisType: 4112
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4116
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4113
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4115
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4117
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4106
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 3
+ MethodList: 4118
+ Name: moduleAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 8
+ Name: name
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 16
+ Name: version
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 24
+ Name: uuid
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 32
+ Name: lcid
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 36
+ Name: control
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 40
+ Name: helpstring
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 48
+ Name: helpstringcontext
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 56
+ Name: helpstringdll
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 64
+ Name: helpfile
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 72
+ Name: helpcontext
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 76
+ Name: hidden
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 77
+ Name: restricted
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 80
+ Name: custom
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4110
+ FieldOffset: 88
+ Name: resource_name
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 19
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4119
+ Name: '__vc_attributes::moduleAttribute'
+ UniqueName: '.?AUmoduleAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 96
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4120
+ SourceFile: 4107
+ LineNumber: 481
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::event_receiverAttribute'
+ UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: native
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: com
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: managed
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4123
+ Name: '__vc_attributes::event_receiverAttribute::type_e'
+ UniqueName: '.?AW4type_e@event_receiverAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4124
+ SourceFile: 4107
+ LineNumber: 136
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4124, 48 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4122
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4122
+ ThisType: 4127
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 2
+ ArgumentList: 4126
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4124 ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4122
+ ThisType: 4127
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4129
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4122
+ ThisType: 4127
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4116
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4128
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4130
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4131
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4124
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 3
+ MethodList: 4132
+ Name: event_receiverAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4124
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 4
+ Name: layout_dependent
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 6
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4133
+ Name: '__vc_attributes::event_receiverAttribute'
+ UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4134
+ SourceFile: 4107
+ LineNumber: 135
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::aggregatableAttribute'
+ UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: never
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: allowed
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: always
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4137
+ Name: '__vc_attributes::aggregatableAttribute::type_e'
+ UniqueName: '.?AW4type_e@aggregatableAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4138
+ SourceFile: 4107
+ LineNumber: 545
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4138 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4136
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4136
+ ThisType: 4141
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4140
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4136
+ ThisType: 4141
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4116
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4142
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4143
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4138
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4144
+ Name: aggregatableAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4138
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 4
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4145
+ Name: '__vc_attributes::aggregatableAttribute'
+ UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4146
+ SourceFile: 4107
+ LineNumber: 544
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::threadingAttribute'
+ UniqueName: '.?AUthreadingAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: apartment
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: single
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: free
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4
+ Name: neutral
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 5
+ Name: both
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 5
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4149
+ Name: '__vc_attributes::threadingAttribute::threading_e'
+ UniqueName: '.?AW4threading_e@threadingAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4150
+ SourceFile: 4107
+ LineNumber: 423
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4150 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4148
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4148
+ ThisType: 4153
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4152
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4148
+ ThisType: 4153
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4116
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4154
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4155
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4150
+ Name: threading_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4156
+ Name: threadingAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4150
+ FieldOffset: 0
+ Name: value
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 4
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4157
+ Name: '__vc_attributes::threadingAttribute'
+ UniqueName: '.?AUthreadingAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4158
+ SourceFile: 4107
+ LineNumber: 422
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::helper_attributes::usageAttribute'
+ UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: eAnyUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: eCoClassUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: eCOMInterfaceUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 6
+ Name: eInterfaceUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 8
+ Name: eMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16
+ Name: eMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 32
+ Name: eInterfaceMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 64
+ Name: eInterfaceMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 128
+ Name: eCoClassMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 256
+ Name: eCoClassMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 768
+ Name: eGlobalMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1024
+ Name: eGlobalDataUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2048
+ Name: eClassUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4096
+ Name: eInterfaceParameterUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 12288
+ Name: eMethodParameterUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16384
+ Name: eIDLModuleUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 32768
+ Name: eAnonymousUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 65536
+ Name: eTypedefUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 131072
+ Name: eUnionUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 262144
+ Name: eEnumUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 524288
+ Name: eDefineTagUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1048576
+ Name: eStructUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2097152
+ Name: eLocalUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4194304
+ Name: ePropertyUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 8388608
+ Name: eEventUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16777216
+ Name: eTemplateUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16777216
+ Name: eModuleUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 33554432
+ Name: eIllegalUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 67108864
+ Name: eAsynchronousUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4161535
+ Name: eAnyIDLUsage
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 30
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4161
+ Name: '__vc_attributes::helper_attributes::usageAttribute::usage_e'
+ UniqueName: '.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4162
+ SourceFile: 4107
+ LineNumber: 51
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 117 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4160
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4160
+ ThisType: 4165
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4164
+ ThisPointerAdjustment: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4162
+ Name: usage_e
+ - Kind: LF_ONEMETHOD
+ OneMethod:
+ Type: 4166
+ Attrs: 3
+ VFTableOffset: -1
+ Name: usageAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 117
+ FieldOffset: 0
+ Name: value
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 3
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4167
+ Name: '__vc_attributes::helper_attributes::usageAttribute'
+ UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4168
+ SourceFile: 4107
+ LineNumber: 49
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: eBoolean
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: eInteger
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: eFloat
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: eDouble
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 4
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4171
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e'
+ UniqueName: '.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4172
+ SourceFile: 4107
+ LineNumber: 38
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4172 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4170
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4170
+ ThisType: 4175
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4174
+ ThisPointerAdjustment: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4172
+ Name: type_e
+ - Kind: LF_ONEMETHOD
+ OneMethod:
+ Type: 4176
+ Attrs: 3
+ VFTableOffset: -1
+ Name: v1_alttypeAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4172
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 3
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4177
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4178
+ SourceFile: 4107
+ LineNumber: 37
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::event_sourceAttribute'
+ UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: native
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: com
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: managed
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4181
+ Name: '__vc_attributes::event_sourceAttribute::type_e'
+ UniqueName: '.?AW4type_e@event_sourceAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4182
+ SourceFile: 4107
+ LineNumber: 1142
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: speed
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: size
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 2
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4184
+ Name: '__vc_attributes::event_sourceAttribute::optimize_e'
+ UniqueName: '.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4185
+ SourceFile: 4107
+ LineNumber: 1145
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4182 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4180
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4180
+ ThisType: 4188
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4187
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4180
+ ThisType: 4188
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4116
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4189
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4190
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4182
+ Name: type_e
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4185
+ Name: optimize_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4191
+ Name: event_sourceAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4182
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4185
+ FieldOffset: 4
+ Name: optimize
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 8
+ Name: decorate
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 7
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4192
+ Name: '__vc_attributes::event_sourceAttribute'
+ UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 12
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4193
+ SourceFile: 4107
+ LineNumber: 1141
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'D:\src\llvmbuild\cl\Debug\x64'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\bin\HostX64\x64\cl.exe'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: '-Z7 -O1 -c -MT -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\ATLMFC\include" -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include" -I"C:\Program'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: ' Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\shared" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\um"'
+ - Kind: LF_SUBSTR_LIST
+ StringList:
+ StringIndices: [ 4197, 4198 ]
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 4199
+ String: ' -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\winrt" -TP -X'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: a.cpp
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'D:\src\llvmbuild\cl\Debug\x64\vc140.pdb'
+ - Kind: LF_BUILDINFO
+ BuildInfo:
+ ArgIndices: [ 4195, 4196, 4201, 4202, 4200 ]
+ - Name: .bss
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 4883EC288B0D0000000085C97405E8000000004883C428C3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: '?x@@3HA'
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 15
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 24
+ DbgStart: 4
+ DbgEnd: 19
+ FunctionType: 4099
+ Flags: [ HasOptimizedDebugInfo ]
+ DisplayName: a
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: __formal
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 0
+ ISectStart: 0
+ Range: 10
+ Gaps:
+ - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+ DefRangeFramePointerRelFullScopeSym:
+ Register: 48
+ - Kind: S_CALLEES
+ CallerSym:
+ FuncID: [ 4103 ]
+ - Kind: S_FILESTATIC
+ FileStaticSym:
+ Index: 116
+ ModFilenameOffset: 37
+ Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ]
+ Name: x
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 10
+ ISectStart: 0
+ Range: 9
+ Gaps:
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 40
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, Inlined ]
+ - Kind: S_REGREL32
+ RegRelativeSym:
+ Offset: 48
+ Type: 116
+ Register: CVRegRSP
+ VarName: __formal
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 24
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 7
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 4
+ LineStart: 8
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 14
+ LineStart: 9
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 19
+ LineStart: 10
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 80
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 84
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 132
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 136
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 208
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 212
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 4883EC288B050000000085C0740D8BC8E8000000008B05000000004883C428C3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: '?x@@3HA'
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 17
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 23
+ SymbolName: '?x@@3HA'
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 32
+ DbgStart: 4
+ DbgEnd: 27
+ FunctionType: 4102
+ Flags: [ HasOptimizedDebugInfo ]
+ DisplayName: main
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: argc
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 0
+ ISectStart: 0
+ Range: 16
+ Gaps:
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 1
+ Range:
+ OffsetStart: 27
+ ISectStart: 0
+ Range: 5
+ Gaps:
+ - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+ DefRangeFramePointerRelFullScopeSym:
+ Register: 48
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 4098
+ Flags: [ IsParameter ]
+ VarName: argv
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 331
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 0
+ ISectStart: 0
+ Range: 21
+ Gaps:
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 331
+ MayHaveNoName: 1
+ Range:
+ OffsetStart: 27
+ ISectStart: 0
+ Range: 5
+ Gaps:
+ - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+ DefRangeFramePointerRelFullScopeSym:
+ Register: 56
+ - Kind: S_INLINESITE
+ InlineSiteSym:
+ Inlinee: 4099
+ - Kind: S_CALLEES
+ CallerSym:
+ FuncID: [ 4103 ]
+ - Kind: S_INLINESITE_END
+ ScopeEndSym:
+ - Kind: S_FILESTATIC
+ FileStaticSym:
+ Index: 116
+ ModFilenameOffset: 37
+ Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ]
+ Name: x
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 17
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 10
+ ISectStart: 0
+ Range: 22
+ Gaps:
+ - GapStartOffset: 11
+ Range: 6
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 40
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling ]
+ - Kind: S_INLINEES
+ CallerSym:
+ FuncID: [ 4099 ]
+ - Kind: S_REGREL32
+ RegRelativeSym:
+ Offset: 48
+ Type: 116
+ Register: CVRegRSP
+ VarName: argc
+ - Kind: S_REGREL32
+ RegRelativeSym:
+ Offset: 56
+ Type: 4098
+ Register: CVRegRSP
+ VarName: argv
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 32
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 12
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 4
+ LineStart: 13
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 27
+ LineStart: 15
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 79
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 83
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 95
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 99
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 134
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 138
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 150
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 154
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 229
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 233
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 336
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 340
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004420000'
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '000000001800000000000000'
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ SymbolName: '$unwind$?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - Name: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004420000'
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '000000002000000000000000'
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: '$LN7'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: '$LN7'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ SymbolName: '$unwind$main'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+symbols:
+ - Name: '@comp.id'
+ Value: 17130443
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 2147484048
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 47
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1120
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6700
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .bss
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '?x@@3HA'
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 24
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 211387054
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 264
+ NumberOfRelocations: 8
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 32
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3834856183
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 384
+ NumberOfRelocations: 14
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 7
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '?b@@YAXH@Z'
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '?a@@YAXH@Z'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: main
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '$LN5'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN7'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 264583633
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$unwind$?a@@YAXH@Z'
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 10
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 2942184094
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$pdata$?a@@YAXH@Z'
+ Value: 0
+ SectionNumber: 10
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 11
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 264583633
+ Number: 7
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$unwind$main'
+ Value: 0
+ SectionNumber: 11
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 12
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 4185285206
+ Number: 7
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$pdata$main'
+ Value: 0
+ SectionNumber: 12
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb-file-statics-b.yaml b/test/COFF/Inputs/pdb-file-statics-b.yaml
new file mode 100644
index 000000000000..8b7a311f0f8b
--- /dev/null
+++ b/test/COFF/Inputs/pdb-file-statics-b.yaml
@@ -0,0 +1,1552 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_OBJNAME
+ ObjNameSym:
+ Signature: 0
+ ObjectName: 'D:\src\llvmbuild\cl\Debug\x64\b.obj'
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ SecurityChecks, HotPatch ]
+ Machine: X64
+ FrontendMajor: 19
+ FrontendMinor: 11
+ FrontendBuild: 25547
+ FrontendQFE: 0
+ BackendMajor: 19
+ BackendMinor: 11
+ BackendBuild: 25547
+ BackendQFE: 0
+ Version: 'Microsoft (R) Optimizing Compiler'
+ - !Symbols
+ Records:
+ - Kind: S_LDATA32
+ DataSym:
+ Type: 116
+ DisplayName: y
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4189
+ UDTName: '__vc_attributes::event_sourceAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4181
+ UDTName: '__vc_attributes::event_sourceAttribute::optimize_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4178
+ UDTName: '__vc_attributes::event_sourceAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4174
+ UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4168
+ UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4164
+ UDTName: '__vc_attributes::helper_attributes::usageAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4158
+ UDTName: '__vc_attributes::helper_attributes::usageAttribute::usage_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4154
+ UDTName: '__vc_attributes::threadingAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4146
+ UDTName: '__vc_attributes::threadingAttribute::threading_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4142
+ UDTName: '__vc_attributes::aggregatableAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4134
+ UDTName: '__vc_attributes::aggregatableAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4130
+ UDTName: '__vc_attributes::event_receiverAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4120
+ UDTName: '__vc_attributes::event_receiverAttribute::type_e'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4116
+ UDTName: '__vc_attributes::moduleAttribute'
+ - Kind: S_UDT
+ UDTSym:
+ Type: 4102
+ UDTName: '__vc_attributes::moduleAttribute::type_e'
+ - !FileChecksums
+ Checksums:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\b.cpp'
+ Kind: MD5
+ Checksum: 8B4E383DAF442E63771294D52BF55155
+ - !StringTable
+ Strings:
+ - 'd:\src\llvmbuild\cl\debug\x64\b.cpp'
+ - 'D:\src\llvmbuild\cl\Debug\x64\b.obj'
+ - !Symbols
+ Records:
+ - Kind: S_BUILDINFO
+ BuildInfoSym:
+ BuildId: 4199
+ Relocations:
+ - VirtualAddress: 132
+ SymbolName: '?y@@3HA'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 136
+ SymbolName: '?y@@3HA'
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Types:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116 ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 3
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 1
+ ArgumentList: 4096
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: b
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: a
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::moduleAttribute'
+ UniqueName: '.?AUmoduleAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: dll
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: exe
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: service
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4
+ Name: unspecified
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: EXE
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: SERVICE
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 6
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4101
+ Name: '__vc_attributes::moduleAttribute::type_e'
+ UniqueName: '.?AW4type_e@moduleAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'd:\src\llvmbuild\cl\debug\x64\predefined c++ attributes (compiler internal)'
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4102
+ SourceFile: 4103
+ LineNumber: 482
+ - Kind: LF_MODIFIER
+ Modifier:
+ ModifiedType: 112
+ Modifiers: [ None, Const ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4105
+ Attrs: 65548
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4102, 4106, 4106, 4106, 116, 48, 4106, 116,
+ 4106, 4106, 116, 48, 48, 4106, 4106 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4100
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4100
+ ThisType: 4108
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 15
+ ArgumentList: 4107
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4102 ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4100
+ ThisType: 4108
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4110
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4100
+ ThisType: 4108
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4112
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4109
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4111
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4113
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4102
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 3
+ MethodList: 4114
+ Name: moduleAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4102
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 8
+ Name: name
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 16
+ Name: version
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 24
+ Name: uuid
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 32
+ Name: lcid
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 36
+ Name: control
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 40
+ Name: helpstring
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 48
+ Name: helpstringcontext
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 56
+ Name: helpstringdll
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 64
+ Name: helpfile
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 72
+ Name: helpcontext
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 76
+ Name: hidden
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 77
+ Name: restricted
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 80
+ Name: custom
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4106
+ FieldOffset: 88
+ Name: resource_name
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 19
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4115
+ Name: '__vc_attributes::moduleAttribute'
+ UniqueName: '.?AUmoduleAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 96
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4116
+ SourceFile: 4103
+ LineNumber: 481
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::event_receiverAttribute'
+ UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: native
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: com
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: managed
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4119
+ Name: '__vc_attributes::event_receiverAttribute::type_e'
+ UniqueName: '.?AW4type_e@event_receiverAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4120
+ SourceFile: 4103
+ LineNumber: 136
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4120, 48 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4118
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4118
+ ThisType: 4123
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 2
+ ArgumentList: 4122
+ ThisPointerAdjustment: 0
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4120 ]
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4118
+ ThisType: 4123
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4125
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4118
+ ThisType: 4123
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4112
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4124
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4126
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4127
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4120
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 3
+ MethodList: 4128
+ Name: event_receiverAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4120
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 4
+ Name: layout_dependent
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 6
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4129
+ Name: '__vc_attributes::event_receiverAttribute'
+ UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4130
+ SourceFile: 4103
+ LineNumber: 135
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::aggregatableAttribute'
+ UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: never
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: allowed
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: always
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4133
+ Name: '__vc_attributes::aggregatableAttribute::type_e'
+ UniqueName: '.?AW4type_e@aggregatableAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4134
+ SourceFile: 4103
+ LineNumber: 545
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4134 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4132
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4132
+ ThisType: 4137
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4136
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4132
+ ThisType: 4137
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4112
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4138
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4139
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4134
+ Name: type_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4140
+ Name: aggregatableAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4134
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 4
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4141
+ Name: '__vc_attributes::aggregatableAttribute'
+ UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4142
+ SourceFile: 4103
+ LineNumber: 544
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::threadingAttribute'
+ UniqueName: '.?AUthreadingAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: apartment
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: single
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: free
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4
+ Name: neutral
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 5
+ Name: both
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 5
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4145
+ Name: '__vc_attributes::threadingAttribute::threading_e'
+ UniqueName: '.?AW4threading_e@threadingAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4146
+ SourceFile: 4103
+ LineNumber: 423
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4146 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4144
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4144
+ ThisType: 4149
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4148
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4144
+ ThisType: 4149
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4112
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4150
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4151
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4146
+ Name: threading_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4152
+ Name: threadingAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4146
+ FieldOffset: 0
+ Name: value
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 4
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4153
+ Name: '__vc_attributes::threadingAttribute'
+ UniqueName: '.?AUthreadingAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4154
+ SourceFile: 4103
+ LineNumber: 422
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::helper_attributes::usageAttribute'
+ UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: eAnyUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: eCoClassUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: eCOMInterfaceUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 6
+ Name: eInterfaceUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 8
+ Name: eMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16
+ Name: eMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 32
+ Name: eInterfaceMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 64
+ Name: eInterfaceMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 128
+ Name: eCoClassMemberUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 256
+ Name: eCoClassMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 768
+ Name: eGlobalMethodUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1024
+ Name: eGlobalDataUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2048
+ Name: eClassUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4096
+ Name: eInterfaceParameterUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 12288
+ Name: eMethodParameterUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16384
+ Name: eIDLModuleUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 32768
+ Name: eAnonymousUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 65536
+ Name: eTypedefUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 131072
+ Name: eUnionUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 262144
+ Name: eEnumUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 524288
+ Name: eDefineTagUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1048576
+ Name: eStructUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2097152
+ Name: eLocalUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4194304
+ Name: ePropertyUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 8388608
+ Name: eEventUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16777216
+ Name: eTemplateUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 16777216
+ Name: eModuleUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 33554432
+ Name: eIllegalUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 67108864
+ Name: eAsynchronousUsage
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 4161535
+ Name: eAnyIDLUsage
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 30
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4157
+ Name: '__vc_attributes::helper_attributes::usageAttribute::usage_e'
+ UniqueName: '.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4158
+ SourceFile: 4103
+ LineNumber: 51
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 117 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4156
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4156
+ ThisType: 4161
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4160
+ ThisPointerAdjustment: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4158
+ Name: usage_e
+ - Kind: LF_ONEMETHOD
+ OneMethod:
+ Type: 4162
+ Attrs: 3
+ VFTableOffset: -1
+ Name: usageAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 117
+ FieldOffset: 0
+ Name: value
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 3
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4163
+ Name: '__vc_attributes::helper_attributes::usageAttribute'
+ UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4164
+ SourceFile: 4103
+ LineNumber: 49
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: eBoolean
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: eInteger
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: eFloat
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 3
+ Name: eDouble
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 4
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4167
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e'
+ UniqueName: '.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4168
+ SourceFile: 4103
+ LineNumber: 38
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4168 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4166
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4166
+ ThisType: 4171
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4170
+ ThisPointerAdjustment: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4168
+ Name: type_e
+ - Kind: LF_ONEMETHOD
+ OneMethod:
+ Type: 4172
+ Attrs: 3
+ VFTableOffset: -1
+ Name: v1_alttypeAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4168
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 3
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4173
+ Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute'
+ UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4174
+ SourceFile: 4103
+ LineNumber: 37
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: '__vc_attributes::event_sourceAttribute'
+ UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: native
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: com
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: managed
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4177
+ Name: '__vc_attributes::event_sourceAttribute::type_e'
+ UniqueName: '.?AW4type_e@event_sourceAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4178
+ SourceFile: 4103
+ LineNumber: 1142
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: speed
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: size
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 2
+ Options: [ None, Nested, HasUniqueName ]
+ FieldList: 4180
+ Name: '__vc_attributes::event_sourceAttribute::optimize_e'
+ UniqueName: '.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@'
+ UnderlyingType: 116
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4181
+ SourceFile: 4103
+ LineNumber: 1145
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4178 ]
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4176
+ Attrs: 66572
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4176
+ ThisType: 4184
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 1
+ ArgumentList: 4183
+ ThisPointerAdjustment: 0
+ - Kind: LF_MFUNCTION
+ MemberFunction:
+ ReturnType: 3
+ ClassType: 4176
+ ThisType: 4184
+ CallConv: NearC
+ Options: [ None, Constructor ]
+ ParameterCount: 0
+ ArgumentList: 4112
+ ThisPointerAdjustment: 0
+ - Kind: LF_METHODLIST
+ MethodOverloadList:
+ Methods:
+ - Type: 4185
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Type: 4186
+ Attrs: 3
+ VFTableOffset: -1
+ Name: ''
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4178
+ Name: type_e
+ - Kind: LF_NESTTYPE
+ NestedType:
+ Type: 4181
+ Name: optimize_e
+ - Kind: LF_METHOD
+ OverloadedMethod:
+ NumOverloads: 2
+ MethodList: 4187
+ Name: event_sourceAttribute
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4178
+ FieldOffset: 0
+ Name: type
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4181
+ FieldOffset: 4
+ Name: optimize
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 48
+ FieldOffset: 8
+ Name: decorate
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 7
+ Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ]
+ FieldList: 4188
+ Name: '__vc_attributes::event_sourceAttribute'
+ UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 12
+ - Kind: LF_UDT_SRC_LINE
+ UdtSourceLine:
+ UDT: 4189
+ SourceFile: 4103
+ LineNumber: 1141
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'D:\src\llvmbuild\cl\Debug\x64'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\bin\HostX64\x64\cl.exe'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: '-Z7 -O1 -c -MT -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\ATLMFC\include" -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include" -I"C:\Program'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: ' Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\shared" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\um"'
+ - Kind: LF_SUBSTR_LIST
+ StringList:
+ StringIndices: [ 4193, 4194 ]
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 4195
+ String: ' -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\winrt" -TP -X'
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: b.cpp
+ - Kind: LF_STRING_ID
+ StringId:
+ Id: 0
+ String: 'D:\src\llvmbuild\cl\Debug\x64\vc140.pdb'
+ - Kind: LF_BUILDINFO
+ BuildInfo:
+ ArgIndices: [ 4191, 4192, 4197, 4198, 4196 ]
+ - Name: .bss
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 4883EC288B0D0000000085C97405E8000000004883C428C3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: '?y@@3HA'
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 15
+ SymbolName: '?a@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 24
+ DbgStart: 4
+ DbgEnd: 19
+ FunctionType: 4098
+ Flags: [ HasOptimizedDebugInfo ]
+ DisplayName: b
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: __formal
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 0
+ ISectStart: 0
+ Range: 10
+ Gaps:
+ - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+ DefRangeFramePointerRelFullScopeSym:
+ Register: 48
+ - Kind: S_CALLEES
+ CallerSym:
+ FuncID: [ 4099 ]
+ - Kind: S_FILESTATIC
+ FileStaticSym:
+ Index: 116
+ ModFilenameOffset: 37
+ Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ]
+ Name: y
+ - Kind: S_DEFRANGE_REGISTER
+ DefRangeRegisterSym:
+ Register: 18
+ MayHaveNoName: 0
+ Range:
+ OffsetStart: 10
+ ISectStart: 0
+ Range: 9
+ Gaps:
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 40
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling ]
+ - Kind: S_REGREL32
+ RegRelativeSym:
+ Offset: 48
+ Type: 116
+ Register: CVRegRSP
+ VarName: __formal
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 24
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'd:\src\llvmbuild\cl\debug\x64\b.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 7
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 4
+ LineStart: 8
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 14
+ LineStart: 9
+ IsStatement: true
+ EndDelta: 0
+ - Offset: 19
+ LineStart: 10
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 80
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 84
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 132
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 136
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 208
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 212
+ SymbolName: '?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004420000'
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '000000001800000000000000'
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ SymbolName: '$unwind$?b@@YAXH@Z'
+ Type: IMAGE_REL_AMD64_ADDR32NB
+symbols:
+ - Name: '@comp.id'
+ Value: 17130443
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 2147484048
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 47
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1096
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6636
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .bss
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '?y@@3HA'
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 24
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 211387054
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 264
+ NumberOfRelocations: 8
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '?a@@YAXH@Z'
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '?b@@YAXH@Z'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '$LN5'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 264583633
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$unwind$?b@@YAXH@Z'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 2942184094
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '$pdata$?b@@YAXH@Z'
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb-globals.yaml b/test/COFF/Inputs/pdb-globals.yaml
index 98ef914d9041..669522d7811f 100644
--- a/test/COFF/Inputs/pdb-globals.yaml
+++ b/test/COFF/Inputs/pdb-globals.yaml
@@ -125,29 +125,21 @@ sections:
Type: 116
Flags: [ IsParameter ]
VarName: argc
- - Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
- Kind: S_LOCAL
LocalSym:
Type: 4099
Flags: [ IsParameter ]
VarName: argv
- - Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
- Kind: S_LOCAL
LocalSym:
Type: 4103
Flags: [ ]
VarName: P
- - Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
- Kind: S_LOCAL
LocalSym:
Type: 116
Flags: [ ]
VarName: N
- - Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
- Kind: S_PROC_ID_END
ScopeEndSym:
- Kind: S_LPROC32_ID
@@ -408,8 +400,6 @@ sections:
Type: 4108
Flags: [ IsParameter ]
VarName: this
- - Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
- Kind: S_PROC_ID_END
ScopeEndSym:
Relocations:
diff --git a/test/COFF/Inputs/pdb-hashes-1.yaml b/test/COFF/Inputs/pdb-hashes-1.yaml
index ad9e69188f51..158f936100f3 100644
--- a/test/COFF/Inputs/pdb-hashes-1.yaml
+++ b/test/COFF/Inputs/pdb-hashes-1.yaml
@@ -1,13 +1,13 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
- SectionData: 5589E55683EC188B450C8B4D088D55F4C745F8000000008B7508894DF089D18934248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3
- Relocations:
+ SectionData: 5589E55683EC188B450C8B4D08C745F8000000008B55088D75F4894DF089F18914248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3
+ Relocations:
- VirtualAddress: 38
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_REL32
@@ -33,25 +33,25 @@ sections:
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001700000000002A000D003E11001000000100617267760012004511160000000C0000001700000000002A000A003E1109100000000066001200451116000000F4FFFFFF1700000000002A0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000017000000040000003000000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B00000010019303CF100D518DAF59C31DA01FEF4AFC0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001400000000002D000D003E11001000000100617267760012004511160000000C0000001400000000002D000A003E1109100000000066001200451116000000F4FFFFFF1400000000002D0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000014000000040000002D00000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B0000001001D3AE9D06B0C1F06ABE75A0557053ED6B0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 65
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -85,9 +85,9 @@ sections:
RvaStart: 4
SavedRegsSize: 8
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 65
DbgStart: 0
DbgEnd: 0
@@ -95,72 +95,96 @@ sections:
Flags: [ ]
DisplayName: main
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 116
Flags: [ IsParameter ]
VarName: argc
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4096
Flags: [ IsParameter ]
VarName: argv
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 12
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4105
Flags: [ ]
VarName: f
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: -12
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 65
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
EndDelta: 0
- - Offset: 23
+ - Offset: 20
LineStart: 4
IsStatement: false
EndDelta: 0
- - Offset: 48
+ - Offset: 45
LineStart: 5
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4105
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
Kind: MD5
Checksum: 65C9E387F88362A8EB2B49539DD5A655
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
Kind: MD5
- Checksum: 9303CF100D518DAF59C31DA01FEF4AFC
+ Checksum: D3AE9D06B0C1F06ABE75A0557053ED6B
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
- 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = '
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: _main
Type: IMAGE_REL_I386_DIR32NB
@@ -198,28 +222,28 @@ sections:
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000210700400000A8000000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000210041000000A8000000A00011201000000740000001A0009100300000004100000051000000B00010006100000000000001A0003120D15030074000000000058001115030007100000466F6F002A0005150200000208100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E000616091000000A100000020000000E0002160410000007100000466F6F00
- Types:
+ Types:
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 1136
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116, 4096 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 2
ArgumentList: 4097
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 0
FunctionType: 4098
Name: main
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -229,14 +253,14 @@ sections:
VTableShape: 0
Size: 0
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4100
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4100
ThisType: 4101
@@ -246,21 +270,21 @@ sections:
ArgumentList: 4102
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4103
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4104
@@ -270,47 +294,47 @@ sections:
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4105
SourceFile: 4106
LineNumber: 2
- Kind: LF_MFUNC_ID
- MemberFuncId:
+ MemberFuncId:
ClassType: 4100
FunctionType: 4103
Name: Foo
- Name: '.debug$H'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: C5C93301000000009E56666824DC4B12E25261D4E09E6E9DA0F4EE31FDEC3D2D96287486127C66070B248ED52E421F55074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E99E616EF06A14EA74A2420F9062A1FB04917E5975E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D894CEAE81AEF8680D723D403D9A4481F0E28683A98
- GlobalHashes:
+ SectionData: C5C9330100000100800309EE1ED8BB5B5397319F1CC14E2CDF04AA3125BBC50E95CEBA304A2C449323ADA4E788EB7A90B5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B26FFBFD620CFB362
+ GlobalHashes:
Version: 0
- HashAlgorithm: 0
- HashValues:
- - 9E56666824DC4B12E25261D4E09E6E9DA0F4EE31
- - FDEC3D2D96287486127C66070B248ED52E421F55
- - 074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84
- - BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E9
- - 9E616EF06A14EA74A2420F9062A1FB04917E5975
- - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7
- - 97DD91CA4D7F1953C314442D5549419E78044E38
- - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0
- - C0A9021B711ACC4F67008974EBF441031BDD653F
- - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA
- - 0AF6C1846743F43D846BB19517E12E8873BBA90C
- - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89
- - 4CEAE81AEF8680D723D403D9A4481F0E28683A98
+ HashAlgorithm: 1
+ HashValues:
+ - 800309EE1ED8BB5B
+ - 5397319F1CC14E2C
+ - DF04AA3125BBC50E
+ - 95CEBA304A2C4493
+ - 23ADA4E788EB7A90
+ - B5DECADF1A832BA4
+ - 6632585CDC7606E4
+ - B97B86241E5F45B0
+ - BCD2406E22465E11
+ - A528BEF0A7F589C7
+ - 6079F1186C40C216
+ - 5091EFEBD5B5446B
+ - 26FFBFD620CFB362
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 04000000F500000064000000000000000000000020000000000000000400000000000000520000000600000004000000010000001F0000000000000004000000000000007F0000000500040000000000030000001D000000000000000400000000000000BD0000000300040000000000F10000007B000000320047110000000000000000000000002000000000000000000000000C100000000000000000004E533A3A466F6F3A3A466F6F000D003E1105100000010074686973001200451116000000FCFFFFFF0F000000000011000A003E1174000000010078001200451116000000080000000F0000000000110002004F1100F2000000200000000000000000000000200000001800000001000000140000000000000003000000
- Subsections:
+ Subsections:
- !FrameData
- Frames:
+ Frames:
- CodeSize: 32
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -336,9 +360,9 @@ sections:
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 32
DbgStart: 0
DbgEnd: 0
@@ -346,35 +370,51 @@ sections:
Flags: [ ]
DisplayName: 'NS::Foo::Foo'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4101
Flags: [ IsParameter ]
VarName: this
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: -4
+ Range:
+ OffsetStart: 15
+ ISectStart: 0
+ Range: 17
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 116
Flags: [ IsParameter ]
VarName: x
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 15
+ ISectStart: 0
+ Range: 17
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 32
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
EndDelta: 0
- Columns:
- Relocations:
+ Columns:
+ Relocations:
- VirtualAddress: 12
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -402,18 +442,18 @@ sections:
- VirtualAddress: 256
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_SECTION
-symbols:
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 65
NumberOfRelocations: 2
NumberOfLinenumbers: 0
- CheckSum: 4176946275
+ CheckSum: 1827148029
Number: 1
- Name: .data
Value: 0
@@ -421,7 +461,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -433,7 +473,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -445,7 +485,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 32
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -464,7 +504,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -476,11 +516,11 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 832
NumberOfRelocations: 11
NumberOfLinenumbers: 0
- CheckSum: 4106171226
+ CheckSum: 372945565
Number: 6
- Name: '.debug$S'
Value: 0
@@ -488,7 +528,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 284
NumberOfRelocations: 9
NumberOfLinenumbers: 0
@@ -501,7 +541,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 316
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -513,11 +553,11 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 268
+ SectionDefinition:
+ Length: 112
NumberOfRelocations: 0
NumberOfLinenumbers: 0
- CheckSum: 3965031229
+ CheckSum: 1535721080
Number: 8
- Name: '@feat.00'
Value: 1
diff --git a/test/COFF/Inputs/pdb-hashes-2-missing.yaml b/test/COFF/Inputs/pdb-hashes-2-missing.yaml
index 74f3a62fcc23..41cba5065dea 100644
--- a/test/COFF/Inputs/pdb-hashes-2-missing.yaml
+++ b/test/COFF/Inputs/pdb-hashes-2-missing.yaml
@@ -1,8 +1,8 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
@@ -22,25 +22,25 @@ sections:
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 25
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -66,9 +66,9 @@ sections:
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 25
DbgStart: 0
DbgEnd: 0
@@ -76,22 +76,30 @@ sections:
Flags: [ ]
DisplayName: 'NS::func'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4099
Flags: [ IsParameter ]
VarName: f
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 7
+ ISectStart: 0
+ Range: 18
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 25
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
@@ -100,26 +108,26 @@ sections:
LineStart: 4
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4106
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
Kind: MD5
Checksum: 59DFAC75D18675AED1AD169FE316317E
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- ''
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: '?func@NS@@YAHABUFoo@1@@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -145,13 +153,13 @@ sections:
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1
- Types:
+ Types:
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: NS
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -161,32 +169,32 @@ sections:
VTableShape: 0
Size: 0
- Kind: LF_MODIFIER
- Modifier:
+ Modifier:
ModifiedType: 4097
Modifiers: [ None, Const ]
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4098
Attrs: 32810
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 4099 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 1
ArgumentList: 4100
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4097
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4097
ThisType: 4102
@@ -196,21 +204,21 @@ sections:
ArgumentList: 4103
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4104
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4105
@@ -220,27 +228,27 @@ sections:
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4106
SourceFile: 4107
LineNumber: 2
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 4096
FunctionType: 4101
Name: func
-symbols:
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 25
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -252,7 +260,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -264,7 +272,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -276,7 +284,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -288,11 +296,11 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 584
NumberOfRelocations: 7
NumberOfLinenumbers: 0
- CheckSum: 2847177244
+ CheckSum: 917356735
Number: 5
- Name: '.debug$T'
Value: 0
@@ -300,7 +308,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 320
NumberOfRelocations: 0
NumberOfLinenumbers: 0
diff --git a/test/COFF/Inputs/pdb-hashes-2.yaml b/test/COFF/Inputs/pdb-hashes-2.yaml
index 63e9fc02ad5a..51ea512f1aa4 100644
--- a/test/COFF/Inputs/pdb-hashes-2.yaml
+++ b/test/COFF/Inputs/pdb-hashes-2.yaml
@@ -1,8 +1,8 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
@@ -22,25 +22,25 @@ sections:
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 25
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -66,9 +66,9 @@ sections:
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 25
DbgStart: 0
DbgEnd: 0
@@ -76,22 +76,30 @@ sections:
Flags: [ ]
DisplayName: 'NS::func'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4099
Flags: [ IsParameter ]
VarName: f
- Kind: S_DEFRANGE_REGISTER_REL
- DefRangeRegisterRelSym:
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 7
+ ISectStart: 0
+ Range: 18
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 25
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
@@ -100,26 +108,26 @@ sections:
LineStart: 4
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4106
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
Kind: MD5
Checksum: 59DFAC75D18675AED1AD169FE316317E
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- ''
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: '?func@NS@@YAHABUFoo@1@@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -145,13 +153,13 @@ sections:
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1
- Types:
+ Types:
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: NS
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -161,32 +169,32 @@ sections:
VTableShape: 0
Size: 0
- Kind: LF_MODIFIER
- Modifier:
+ Modifier:
ModifiedType: 4097
Modifiers: [ None, Const ]
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4098
Attrs: 32810
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 4099 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 1
ArgumentList: 4100
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4097
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4097
ThisType: 4102
@@ -196,21 +204,21 @@ sections:
ArgumentList: 4103
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4104
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4105
@@ -220,49 +228,49 @@ sections:
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4106
SourceFile: 4107
LineNumber: 2
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 4096
FunctionType: 4101
Name: func
- Name: '.debug$H'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: C5C9330100000000EC145CD76AEFE74E78880D531132B3BB8FFACEF79E616EF06A14EA74A2420F9062A1FB04917E59759949E334BA18509ED692F3C65CE242D8450EBC78B81B63AF8316DC324562EB9F0D4A0D708E8A25C263DB05943C19B84A36719E1E414DDA3EDBDF005322238D70F9058EEDC5C50EF11BC849618B51FD89E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D89DCBC783AF285D9DBB672F67A81E36906B2038B57
- GlobalHashes:
+ SectionData: C5C93301000001004A061540B751965F23ADA4E788EB7A9032673B3BABE3CA5356B1521BDAE4BEA70661C95750D0206E896FB09488EE8E1BB5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B5AAD8721C21DF3E6
+ GlobalHashes:
Version: 0
- HashAlgorithm: 0
- HashValues:
- - EC145CD76AEFE74E78880D531132B3BB8FFACEF7
- - 9E616EF06A14EA74A2420F9062A1FB04917E5975
- - 9949E334BA18509ED692F3C65CE242D8450EBC78
- - B81B63AF8316DC324562EB9F0D4A0D708E8A25C2
- - 63DB05943C19B84A36719E1E414DDA3EDBDF0053
- - 22238D70F9058EEDC5C50EF11BC849618B51FD89
- - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7
- - 97DD91CA4D7F1953C314442D5549419E78044E38
- - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0
- - C0A9021B711ACC4F67008974EBF441031BDD653F
- - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA
- - 0AF6C1846743F43D846BB19517E12E8873BBA90C
- - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89
- - DCBC783AF285D9DBB672F67A81E36906B2038B57
-symbols:
+ HashAlgorithm: 1
+ HashValues:
+ - 4A061540B751965F
+ - 23ADA4E788EB7A90
+ - 32673B3BABE3CA53
+ - 56B1521BDAE4BEA7
+ - 0661C95750D0206E
+ - 896FB09488EE8E1B
+ - B5DECADF1A832BA4
+ - 6632585CDC7606E4
+ - B97B86241E5F45B0
+ - BCD2406E22465E11
+ - A528BEF0A7F589C7
+ - 6079F1186C40C216
+ - 5091EFEBD5B5446B
+ - 5AAD8721C21DF3E6
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 25
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -274,7 +282,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -286,7 +294,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -298,7 +306,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -310,11 +318,11 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 584
NumberOfRelocations: 7
NumberOfLinenumbers: 0
- CheckSum: 2847177244
+ CheckSum: 917356735
Number: 5
- Name: '.debug$T'
Value: 0
@@ -322,7 +330,7 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 320
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -334,11 +342,11 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 288
+ SectionDefinition:
+ Length: 120
NumberOfRelocations: 0
NumberOfLinenumbers: 0
- CheckSum: 2348181452
+ CheckSum: 358820662
Number: 7
- Name: '@feat.00'
Value: 1
diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml
index e422a6241f27..0fc41723bdc2 100644
--- a/test/COFF/Inputs/pdb-scopes-a.yaml
+++ b/test/COFF/Inputs/pdb-scopes-a.yaml
@@ -53,7 +53,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -93,7 +93,7 @@ sections:
RegRelativeSym:
Offset: 64
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: argc
- Kind: S_BLOCK32
BlockSym:
@@ -104,7 +104,7 @@ sections:
RegRelativeSym:
Offset: 32
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_END
ScopeEndSym:
@@ -117,7 +117,7 @@ sections:
RegRelativeSym:
Offset: 36
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: y
- Kind: S_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml
index b1c602143c3f..c0ee98b0d64c 100644
--- a/test/COFF/Inputs/pdb-scopes-b.yaml
+++ b/test/COFF/Inputs/pdb-scopes-b.yaml
@@ -53,7 +53,7 @@ sections:
RegRelativeSym:
Offset: 64
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_BLOCK32
BlockSym:
@@ -64,7 +64,7 @@ sections:
RegRelativeSym:
Offset: 32
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: y
- Kind: S_END
ScopeEndSym:
@@ -77,7 +77,7 @@ sections:
RegRelativeSym:
Offset: 36
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: w
- Kind: S_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
index 78c68168127b..8425c4f63b70 100644
--- a/test/COFF/Inputs/pdb-type-server-simple-a.yaml
+++ b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
@@ -53,7 +53,7 @@ sections:
RegRelativeSym:
Offset: 32
Type: 4102
- Register: RSP
+ Register: CVRegRSP
VarName: f
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-simple-b.yaml b/test/COFF/Inputs/pdb-type-server-simple-b.yaml
index 56e97d530894..3b511cb0d861 100644
--- a/test/COFF/Inputs/pdb-type-server-simple-b.yaml
+++ b/test/COFF/Inputs/pdb-type-server-simple-b.yaml
@@ -53,7 +53,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: p
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb_lines_1_relative.yaml b/test/COFF/Inputs/pdb_lines_1_relative.yaml
new file mode 100644
index 000000000000..947de419d6b8
--- /dev/null
+++ b/test/COFF/Inputs/pdb_lines_1_relative.yaml
@@ -0,0 +1,401 @@
+--- !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: 4883EC28C744242400000000E800000000B82A0000004883C428C3
+ Relocations:
+ - VirtualAddress: 13
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_REL32
+ - 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: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004420000'
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 4883EC28E800000000904883C428C3
+ Relocations:
+ - VirtualAddress: 5
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 04000000F10000002F0000002D003C1100000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000300000002A0047110000000000000000000000001B000000000000000000000002100000000000000000006D61696E0002004F11F20000003000000000000000000000001B00000000000000030000002400000000000000020000000C000000030000001100000004000000F400000030000000010000001001EA6429BCE282CCF3F0E3CD93B216EB410000110000001001061EB73ABB642532857A4F1D9CBAC3230000F30000001C000000002E5C7064625F6C696E65735F312E63002E5C666F6F2E6800000000
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ ]
+ Machine: X64
+ FrontendMajor: 7
+ FrontendMinor: 0
+ FrontendBuild: 0
+ FrontendQFE: 0
+ BackendMajor: 7000
+ BackendMinor: 0
+ BackendBuild: 0
+ BackendQFE: 0
+ Version: 'clang version 7.0.0 '
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 27
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4098
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 27
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: '.\pdb_lines_1.c'
+ Lines:
+ - Offset: 0
+ LineStart: 2
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 12
+ LineStart: 3
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 17
+ LineStart: 4
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: '.\pdb_lines_1.c'
+ Kind: MD5
+ Checksum: EA6429BCE282CCF3F0E3CD93B216EB41
+ - FileName: '.\foo.h'
+ Kind: MD5
+ Checksum: 061EB73ABB642532857A4F1D9CBAC323
+ - !StringTable
+ Strings:
+ - '.\pdb_lines_1.c'
+ - '.\foo.h'
+ - ''
+ - ''
+ - ''
+ Relocations:
+ - VirtualAddress: 100
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 124
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 128
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0400000006000112000000000E0008107400000000000000001000001200011600000000011000006D61696E00F3F2F10E0008100300000000000000001000000E0001160000000003100000666F6F00
+ Types:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 116
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: main
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 3
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4099
+ Name: foo
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 000000001B00000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - Name: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0104010004420000'
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 04000000F10000002F000000290047110000000000000000000000000F00000000000000000000000410000000000000000000666F6F0002004F1100F20000003000000000000000000000000F000000180000000300000024000000000000000200000004000000030000000900000004000000
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 15
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4100
+ Flags: [ ]
+ DisplayName: foo
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 15
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: '.\foo.h'
+ Lines:
+ - Offset: 0
+ LineStart: 2
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 4
+ LineStart: 3
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 9
+ LineStart: 4
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 68
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 72
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 000000000F00000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ 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: 27
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 3051916600
+ 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: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 264583633
+ Number: 4
+ - Name: .text
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 15
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 236440503
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: foo
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 10
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 264583633
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 48
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 149686238
+ Number: 6
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 264
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 2204933783
+ Number: 7
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 11
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 116
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 2691661839
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 80
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 3541780432
+ Number: 8
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 567356797
+ Number: 9
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 12
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3642757804
+ Number: 5
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: bar
+ 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/pdb_lines_2_relative.yaml b/test/COFF/Inputs/pdb_lines_2_relative.yaml
new file mode 100644
index 000000000000..1b051d82d9a4
--- /dev/null
+++ b/test/COFF/Inputs/pdb_lines_2_relative.yaml
@@ -0,0 +1,190 @@
+--- !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: C3
+ - 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: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 04000000F10000002F0000002D003C1100000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F10000002F0000002900471100000000000000000000000001000000000000000000000002100000000000000000006261720002004F1100F2000000200000000000000000000000010000000000000001000000140000000000000002000000F400000018000000010000001001DF91CB3A2B8D917486574BB50CAC4CC70000F300000014000000002E5C7064625F6C696E65735F322E6300000000
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ ]
+ Machine: X64
+ FrontendMajor: 7
+ FrontendMinor: 0
+ FrontendBuild: 0
+ FrontendQFE: 0
+ BackendMajor: 7000
+ BackendMinor: 0
+ BackendBuild: 0
+ BackendQFE: 0
+ Version: 'clang version 7.0.0 '
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 1
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4098
+ Flags: [ ]
+ DisplayName: bar
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 1
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: '.\pdb_lines_2.c'
+ Lines:
+ - Offset: 0
+ LineStart: 2
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: '.\pdb_lines_2.c'
+ Kind: MD5
+ Checksum: DF91CB3A2B8D917486574BB50CAC4CC7
+ - !StringTable
+ Strings:
+ - '.\pdb_lines_2.c'
+ - ''
+ - ''
+ - ''
+ Relocations:
+ - VirtualAddress: 100
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 124
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 128
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0400000006000112000000000E0008100300000000000000001000000E000116000000000110000062617200
+ Types:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 3
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: 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: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 40735498
+ 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: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 48
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 149686238
+ Number: 4
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 216
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 2383431754
+ Number: 5
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 44
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 179171995
+ Number: 6
+ - Name: bar
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/arm64-branch-range.test b/test/COFF/arm64-branch-range.test
new file mode 100644
index 000000000000..0b581e9c464d
--- /dev/null
+++ b/test/COFF/arm64-branch-range.test
@@ -0,0 +1,16 @@
+// REQUIRES: aarch64
+
+// RUN: echo -e '.globl _start\n _start:\n bl too_far26\n' > %t.main26.s
+// RUN: echo -e '.globl _start\n _start:\n b.ne too_far19\n' > %t.main19.s
+// RUN: echo -e '.globl _start\n _start:\n tbz x0, #0, too_far14\n' > %t.main14.s
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main26.s -o %t.main26.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main19.s -o %t.main19.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main14.s -o %t.main14.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/far-arm64-abs.s -o %t.far.obj
+
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main26.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main19.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main14.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+
+// CHECK: relocation out of range
diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test
index 57590dcf733a..c7b8b7c28466 100644
--- a/test/COFF/arm64-relocs-imports.test
+++ b/test/COFF/arm64-relocs-imports.test
@@ -38,43 +38,57 @@
# BEFORE: 74: 00 00 00 00 <unknown>
# BEFORE: 78: 01 00 00 00 <unknown>
# BEFORE: 7c: 01 00 00 00 <unknown>
+# BEFORE: 80: 00 00 00 91 add x0, x0, #0
+# BEFORE: 84: 00 00 40 91 add x0, x0, #0, lsl #12
+# BEFORE: 88: 00 00 40 f9 ldr x0, [x0]
+# BEFORE: 8c: 01 00 00 00 <unknown>
+# BEFORE: 90: 20 1a 09 30 adr x0, #74565
+# BEFORE: 94: 01 00 00 54 b.ne #0
+# BEFORE: 98: 00 00 00 36 tbz w0, #0, #0
# AFTER: Disassembly of section .text:
-# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]!
-# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096
-# AFTER: 140002008: 00 18 00 91 add x0, x0, #6
-# AFTER: 14000200c: 1d 00 00 94 bl #116
-# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8]
-# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8]
-# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8]
-# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8]
-# AFTER: 140002020: 00 21 00 39 strb w0, [x8, #8]
-# AFTER: 140002024: 00 11 00 79 strh w0, [x8, #8]
-# AFTER: 140002028: 00 09 00 b9 str w0, [x8, #8]
-# AFTER: 14000202c: 00 05 00 f9 str x0, [x8, #8]
-# AFTER: 140002030: 00 41 40 3d ldr b0, [x8, #16]
-# AFTER: 140002034: 00 21 40 7d ldr h0, [x8, #16]
-# AFTER: 140002038: 00 11 40 bd ldr s0, [x8, #16]
-# AFTER: 14000203c: 00 09 40 fd ldr d0, [x8, #16]
-# AFTER: 140002040: 00 05 c0 3d ldr q0, [x8, #16]
-# AFTER: 140002044: 00 41 00 3d str b0, [x8, #16]
-# AFTER: 140002048: 00 21 00 7d str h0, [x8, #16]
-# AFTER: 14000204c: 00 11 00 bd str s0, [x8, #16]
-# AFTER: 140002050: 00 09 00 fd str d0, [x8, #16]
-# AFTER: 140002054: 00 05 80 3d str q0, [x8, #16]
-# AFTER: 140002058: 00 09 40 f9 ldr x0, [x8, #16]
-# AFTER: 14000205c: 00 00 00 b0 adrp x0, #4096
-# AFTER: 140002060: 00 fc 47 f9 ldr x0, [x0, #4088]
-# AFTER: 140002064: e0 03 1f 2a mov w0, wzr
-# AFTER: 140002068: fe 07 41 f8 ldr x30, [sp], #16
-# AFTER: 14000206c: c0 03 5f d6 ret
-# AFTER: 140002070: 10 10 00 40 <unknown>
-# AFTER: 140002074: 01 00 00 00 <unknown>
-# AFTER: 140002078: 09 10 00 00 <unknown>
-# AFTER: 14000207c: 09 00 00 00 <unknown>
-# AFTER: 140002080: 10 00 00 b0 adrp x16, #4096
-# AFTER: 140002084: 10 1e 40 f9 ldr x16, [x16, #56]
-# AFTER: 140002088: 00 02 1f d6 br x16
+# AFTER: 140001000: fe 0f 1f f8 str x30, [sp, #-16]!
+# AFTER: 140001004: 00 00 00 b0 adrp x0, #4096
+# AFTER: 140001008: 00 18 00 91 add x0, x0, #6
+# AFTER: 14000100c: 24 00 00 94 bl #144
+# AFTER: 140001010: 00 21 40 39 ldrb w0, [x8, #8]
+# AFTER: 140001014: 00 11 40 79 ldrh w0, [x8, #8]
+# AFTER: 140001018: 00 09 40 b9 ldr w0, [x8, #8]
+# AFTER: 14000101c: 00 05 40 f9 ldr x0, [x8, #8]
+# AFTER: 140001020: 00 21 00 39 strb w0, [x8, #8]
+# AFTER: 140001024: 00 11 00 79 strh w0, [x8, #8]
+# AFTER: 140001028: 00 09 00 b9 str w0, [x8, #8]
+# AFTER: 14000102c: 00 05 00 f9 str x0, [x8, #8]
+# AFTER: 140001030: 00 41 40 3d ldr b0, [x8, #16]
+# AFTER: 140001034: 00 21 40 7d ldr h0, [x8, #16]
+# AFTER: 140001038: 00 11 40 bd ldr s0, [x8, #16]
+# AFTER: 14000103c: 00 09 40 fd ldr d0, [x8, #16]
+# AFTER: 140001040: 00 05 c0 3d ldr q0, [x8, #16]
+# AFTER: 140001044: 00 41 00 3d str b0, [x8, #16]
+# AFTER: 140001048: 00 21 00 7d str h0, [x8, #16]
+# AFTER: 14000104c: 00 11 00 bd str s0, [x8, #16]
+# AFTER: 140001050: 00 09 00 fd str d0, [x8, #16]
+# AFTER: 140001054: 00 05 80 3d str q0, [x8, #16]
+# AFTER: 140001058: 00 09 40 f9 ldr x0, [x8, #16]
+# AFTER: 14000105c: 00 00 00 f0 adrp x0, #12288
+# AFTER: 140001060: 00 fc 47 f9 ldr x0, [x0, #4088]
+# AFTER: 140001064: e0 03 1f 2a mov w0, wzr
+# AFTER: 140001068: fe 07 41 f8 ldr x30, [sp], #16
+# AFTER: 14000106c: c0 03 5f d6 ret
+# AFTER: 140001070: 10 20 00 40 <unknown>
+# AFTER: 140001074: 01 00 00 00 <unknown>
+# AFTER: 140001078: 09 20 00 00 <unknown>
+# AFTER: 14000107c: 09 00 00 00 <unknown>
+# AFTER: 140001080: 00 20 0e 91 add x0, x0, #904
+# AFTER: 140001084: 00 04 40 91 add x0, x0, #1, lsl #12
+# AFTER: 140001088: 00 c4 41 f9 ldr x0, [x0, #904]
+# AFTER: 14000108c: 03 00 00 00 <unknown>
+# AFTER: 140001090: e0 95 09 30 adr x0, #78525
+# AFTER: 140001094: 41 00 00 54 b.ne #8
+# AFTER: 140001098: 20 00 00 36 tbz w0, #0, #4
+# AFTER: 14000109c: 10 00 00 b0 adrp x16, #4096
+# AFTER: 1400010a0: 10 2a 40 f9 ldr x16, [x16, #80]
+# AFTER: 1400010a4: 00 02 1f d6 br x16
--- !COFF
header:
@@ -84,7 +98,7 @@ sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD608000000000000000100000001000000
+ SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a09300100005400000036
Relocations:
- VirtualAddress: 4
SymbolName: .Lstr
@@ -167,6 +181,27 @@ sections:
- VirtualAddress: 124
SymbolName: .Lglobal
Type: IMAGE_REL_ARM64_SECREL
+ - VirtualAddress: 128
+ SymbolName: .Lglobal5000
+ Type: IMAGE_REL_ARM64_SECREL_LOW12A
+ - VirtualAddress: 132
+ SymbolName: .Lglobal5000
+ Type: IMAGE_REL_ARM64_SECREL_HIGH12A
+ - VirtualAddress: 136
+ SymbolName: .Lglobal5000
+ Type: IMAGE_REL_ARM64_SECREL_LOW12L
+ - VirtualAddress: 140
+ SymbolName: .Lglobal
+ Type: IMAGE_REL_ARM64_SECTION
+ - VirtualAddress: 144
+ SymbolName: .Lglobal
+ Type: IMAGE_REL_ARM64_REL21
+ - VirtualAddress: 148
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH19
+ - VirtualAddress: 152
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH14
- Name: .data
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
Alignment: 4
@@ -240,4 +275,10 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .Lglobal5000
+ Value: 5000
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
...
diff --git a/test/COFF/armnt-movt32t.test b/test/COFF/armnt-movt32t.test
index 7c6965efed6a..6a0640c76fc3 100644
--- a/test/COFF/armnt-movt32t.test
+++ b/test/COFF/armnt-movt32t.test
@@ -11,7 +11,7 @@
# BEFORE: 8: 70 47 bx lr
# AFTER: Disassembly of section .text:
-# AFTER: 0: 41 f2 00 00 movw r0, #4096
+# AFTER: 0: 42 f2 00 00 movw r0, #8192
# AFTER: 4: c0 f2 40 00 movt r0, #64
# AFTER: 8: 70 47 bx lr
diff --git a/test/COFF/associative-comdat.s b/test/COFF/associative-comdat.s
index dd5419533c16..a3d069b53571 100644
--- a/test/COFF/associative-comdat.s
+++ b/test/COFF/associative-comdat.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t1.obj
# RUN: llvm-mc -triple=x86_64-windows-msvc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj
@@ -9,14 +10,15 @@
# CHECK: Sections [
# CHECK: Section {
-# CHECK: Number: 1
-# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
-# CHECK-NEXT: VirtualSize: 0x4
-# CHECK: Section {
+# CHECK: Number: 2
# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00)
# This is the critical check to show that only *one* definition of
# foo_assoc was retained. This *must* be 8, not 16.
# CHECK-NEXT: VirtualSize: 0x8
+# CHECK: Section {
+# CHECK: Number: 3
+# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK-NEXT: VirtualSize: 0x4
.text
.def main;
diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test
index ce0b27621caf..6441bb2be30d 100644
--- a/test/COFF/baserel.test
+++ b/test/COFF/baserel.test
@@ -9,35 +9,35 @@
# BASEREL: BaseReloc [
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x2007
+# BASEREL-NEXT: Address: 0x1007
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x200C
+# BASEREL-NEXT: Address: 0x100C
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x201E
+# BASEREL-NEXT: Address: 0x101E
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ABSOLUTE
-# BASEREL-NEXT: Address: 0x2000
+# BASEREL-NEXT: Address: 0x1000
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x3007
+# BASEREL-NEXT: Address: 0x4007
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x300C
+# BASEREL-NEXT: Address: 0x400C
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x301E
+# BASEREL-NEXT: Address: 0x401E
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ABSOLUTE
-# BASEREL-NEXT: Address: 0x3000
+# BASEREL-NEXT: Address: 0x4000
# BASEREL-NEXT: }
#
# NOBASEREL: BaseReloc [
diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test
index e8d5d65008d5..37dfc5732f48 100644
--- a/test/COFF/combined-resources.test
+++ b/test/COFF/combined-resources.test
@@ -11,8 +11,8 @@
# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \
# RUN: FileCheck %s
-CHECK: ResourceTableRVA: 0x1000
-CHECK-NEXT: ResourceTableSize: 0xC1C
+CHECK: ResourceTableRVA: 0x2000
+CHECK-NEXT: ResourceTableSize: 0xC20
CHECK-DAG: Resources [
CHECK-NEXT: Total Number of Resources: 13
CHECK-DAG: .rsrc Data (
@@ -49,19 +49,19 @@ CHECK-NEXT: 01D0: 00000000 00000000 00000000 00000100 |................|
CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000 |................|
CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000 |................|
CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000 |................|
-CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000 |....9...........|
-CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000 |....(...........|
-CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000 |....(...........|
-CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000 |....0...........|
-CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000 |................|
-CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000 |D...l...........|
-CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000 ||...*...........|
-CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000 |<...6...........|
-CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000 |t...C...........|
-CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000 |....B...........|
+CHECK-NEXT: 0210: 002B0000 39000000 00000000 00000000 |.+..9...........|
+CHECK-NEXT: 0220: C8230000 28030000 00000000 00000000 |.#..(...........|
+CHECK-NEXT: 0230: F0260000 28030000 00000000 00000000 |.&..(...........|
+CHECK-NEXT: 0240: D02A0000 30000000 00000000 00000000 |.*..0...........|
+CHECK-NEXT: 0250: 182A0000 2E000000 00000000 00000000 |.*..............|
+CHECK-NEXT: 0260: 482A0000 6C000000 00000000 00000000 |H*..l...........|
+CHECK-NEXT: 0270: 80230000 2A000000 00000000 00000000 |.#..*...........|
+CHECK-NEXT: 0280: B0230000 18000000 00000000 00000000 |.#..............|
+CHECK-NEXT: 0290: 082C0000 18000000 00000000 00000000 |.,..............|
+CHECK-NEXT: 02A0: B82A0000 18000000 00000000 00000000 |.*..............|
+CHECK-NEXT: 02B0: 402B0000 36000000 00000000 00000000 |@+..6...........|
+CHECK-NEXT: 02C0: 782B0000 43000000 00000000 00000000 |x+..C...........|
+CHECK-NEXT: 02D0: C02B0000 42000000 00000000 00000000 |.+..B...........|
CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00 |..M.Y.A.C.C.E.L.|
CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600 |E.R.A.T.O.R.S...|
CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00 |C.U.R.S.O.R...O.|
@@ -71,14 +71,14 @@ CHECK-NEXT: 0330: 45004100 54002200 0B005300 54005200 |E.A.T."...S.T.R.|
CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900 |I.N.G.A.R.R.A.Y.|
CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500 |..M.Y.R.E.S.O.U.|
CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400 |R.C.E...R.A.N.D.|
-CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500 |O.M.D.A.T.......|
-CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000 |H.e.l.l.o.......|
+CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000000 |O.M.D.A.T.......|
+CHECK-NEXT: 0380: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...|
CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000 |................|
-CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300 |................|
-CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200 |......D.L.......|
-CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000 |....(...........|
-CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000 |................|
-CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF |................|
+CHECK-NEXT: 03A0: 00000000 00000000 00000000 00000000 |................|
+CHECK-NEXT: 03B0: 11000300 E7030000 0D004400 4C040000 |..........D.L...|
+CHECK-NEXT: 03C0: 82001200 BC010000 28000000 10000000 |........(.......|
+CHECK-NEXT: 03D0: 10000000 01001800 00000000 00030000 |................|
+CHECK-NEXT: 03E0: C40E0000 C40E0000 00000000 00000000 |................|
CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -86,50 +86,50 @@ CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF |....|||xxxuuu...|
-CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF |................|
-CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575 |..........yyyuuu|
-CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF |................|
-CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF |..........}}}...|
-CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393 |................|
-CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF |................|
-CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D |................|
-CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF |................|
-CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF |......~~~.......|
-CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5 |................|
-CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989 |................|
-CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1 |................|
-CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E |................|
-CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8 |................|
-CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF |................|
-CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC |................|
-CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF |................|
+CHECK-NEXT: 0460: FFFFFFFF FF7F7F7F 7C7C7C78 78787575 |........|||xxxuu|
+CHECK-NEXT: 0470: 75FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |u...............|
+CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF FFFFFFFF 979797FF |................|
+CHECK-NEXT: 0490: FFFFFFFF FF838383 AAAAAADB DBDB7979 |..............yy|
+CHECK-NEXT: 04A0: 79757575 FFFFFFFF FFFFFFFF FFFFFFFF |yuuu............|
+CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF FFFFFFFF 9C9C9C98 |................|
+CHECK-NEXT: 04C0: 9898FFFF FF888888 DBDBDBB7 B7B77D7D |..............}}|
+CHECK-NEXT: 04D0: 7DFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |}...............|
+CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF FFFFFFFF A0A0A09C |................|
+CHECK-NEXT: 04F0: 9C9C9393 93ADADAD F2F2F284 84848181 |................|
+CHECK-NEXT: 0500: 81FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF FFFFFFFF A4A4A4D7 |................|
+CHECK-NEXT: 0520: D7D79D9D 9DD0D0D0 EEEEEE91 91918D8D |................|
+CHECK-NEXT: 0530: 8DFFFFFF FFFFFF81 81817E7E 7EFFFFFF |..........~~~...|
+CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF FFFFFFFF A9A9A9F2 |................|
+CHECK-NEXT: 0550: F2F2E5E5 E5E2E2E2 95959591 91918D8D |................|
+CHECK-NEXT: 0560: 8D898989 868686FF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF FFFFFFFF ADADADF2 |................|
+CHECK-NEXT: 0580: F2F2E1E1 E1DFDFDF E7E7E7E4 E4E4BBBB |................|
+CHECK-NEXT: 0590: BB8E8E8E FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF FFFFFFFF B5B5B5F2 |................|
+CHECK-NEXT: 05B0: F2F2E8E8 E8E7E7E7 EAEAEAC6 C6C69E9E |................|
+CHECK-NEXT: 05C0: 9EFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF FFFFFFFF B9B9B9F4 |................|
+CHECK-NEXT: 05E0: F4F4ECEC ECEDEDED CBCBCBA7 A7A7FFFF |................|
CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................|
-CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF FFFFFFFF BDBDBDF7 |................|
+CHECK-NEXT: 0610: F7F7EFEF EFD0D0D0 AFAFAFFF FFFFFFFF |................|
CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................|
-CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF FFFFFFFF C1C1C1F7 |................|
+CHECK-NEXT: 0640: F7F7D5D5 D5B6B6B6 FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE |................|
-CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF FFFFFFFF C4C4C4D9 |................|
+CHECK-NEXT: 0670: D9D9BEBE BEFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................|
-CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF FFFFFFFF C8C8C8C5 |................|
+CHECK-NEXT: 06A0: C5C5FFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................|
+CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF FFFFFFFF CBCBCBFF |................|
CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000 |............(...|
-CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000 |................|
-CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000 |................|
-CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 06F0: 28000000 10000000 10000000 01001800 |(...............|
+CHECK-NEXT: 0700: 00000000 00030000 C40E0000 C40E0000 |................|
+CHECK-NEXT: 0710: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -142,29 +142,29 @@ CHECK-NEXT: 07A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801 |................|
-CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
+CHECK-NEXT: 07E0: FFFFFFFF A0E3A901 B31801B3 1801B318 |................|
+CHECK-NEXT: 07F0: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00 |.....3..I.......|
-CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF |.3..3...........|
+CHECK-NEXT: 0810: FFFFFFFF 01B31800 D7331CDB 49DBF9E2 |.........3..I...|
+CHECK-NEXT: 0820: 9BEFAF00 D73300D7 3301B318 FFFFFFFF |.....3..3.......|
CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........|
-CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF |....U...........|
+CHECK-NEXT: 0840: FFFFFFFF 01B31800 DE55F6FE F9DBFAE7 |.........U......|
+CHECK-NEXT: 0850: FEFFFE86 EFAE00DE 5501B318 FFFFFFFF |........U.......|
CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB |.....v.....vW...|
-CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF |..U.............|
+CHECK-NEXT: 0870: FFFFFFFF 01B31800 E676DBFB EC00E676 |.........v.....v|
+CHECK-NEXT: 0880: 57EFA5FB FFFD55EE A401B318 FFFFFFFF |W.....U.........|
CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................|
-CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 08A0: FFFFFFFF 01B31800 ED9800ED 9800ED98 |................|
+CHECK-NEXT: 08B0: 00ED9887 F7CFFEFF FF01B318 FFFFFFFF |................|
CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................|
-CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 08D0: FFFFFFFF 01B31800 F4BA00F4 BA00F4BA |................|
+CHECK-NEXT: 08E0: 00F4BA00 F4BA9CFB E401B318 FFFFFFFF |................|
CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................|
-CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0900: FFFFFFFF 01B31800 FBDB00FB DB00FBDB |................|
+CHECK-NEXT: 0910: 00FBDB00 FBDB00FB DB01B318 FFFFFFFF |................|
CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801 |................|
-CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
+CHECK-NEXT: 0930: FFFFFFFF 9FE2A801 B31801B3 1801B318 |................|
+CHECK-NEXT: 0940: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -177,37 +177,37 @@ CHECK-NEXT: 09D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500 |..........d.y.u.|
-CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100 |....e.s.h.a.l.a.|
-CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100 |....f.k.a.o.y.a.|
-CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00 |................|
-CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300 |....,.....T.e.s.|
-CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00 |t......P........|
-CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00 |..........C.o.n.|
-CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000 |t.i.n.u.e.:.....|
-CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00 |...P....B.......|
-CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000 |......&.O.K.....|
-CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800 |......X.......H.|
-CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000 |................|
-CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000 |..d.f.i.s.h.....|
-CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000 |e.s.a.l.a.d.....|
-CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973 |f.d.u.c.k...this|
-CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E | is a user defin|
-CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063 |ed resource.it c|
-CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472 |ontains many str|
-CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973 |ings........this|
-CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974 | is a random bit|
-CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65 | of data that me|
-CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14 |ans nothing..#..|
-CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969 |....zhe4 shi4 yi|
-CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520 |1ge4 sui2ji1 de |
-CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969 |shu4ju4, zhe4 yi|
-CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65 |4wei4zhe shen2me|
-CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573 |..#.........Dies|
-CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C | ist ein zuf..ll|
-CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174 |iges Bit von Dat|
-CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062 |en, die nichts b|
-CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000 |edeutet..#......|
-CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400 |..............D.|
-CHECK-NEXT: 0C10: 4C040000 82001200 BC010000 |L...........|
+CHECK-NEXT: 0A10: FFFFFFFF FFFFFFFF 00000000 00006400 |..............d.|
+CHECK-NEXT: 0A20: 79007500 00000000 65007300 68006100 |y.u.....e.s.h.a.|
+CHECK-NEXT: 0A30: 6C006100 00008000 66006B00 61006F00 |l.a.....f.k.a.o.|
+CHECK-NEXT: 0A40: 79006100 00000000 0000C080 00000000 |y.a.............|
+CHECK-NEXT: 0A50: 02000A00 0A00C800 2C010000 00005400 |........,.....T.|
+CHECK-NEXT: 0A60: 65007300 74000000 01000250 00000000 |e.s.t......P....|
+CHECK-NEXT: 0A70: 0A000A00 E6000E00 0100FFFF 82004300 |..............C.|
+CHECK-NEXT: 0A80: 6F006E00 74006900 6E007500 65003A00 |o.n.t.i.n.u.e.:.|
+CHECK-NEXT: 0A90: 00000000 00000150 00000000 42008600 |.......P....B...|
+CHECK-NEXT: 0AA0: A1000D00 0200FFFF 80002600 4F004B00 |..........&.O.K.|
+CHECK-NEXT: 0AB0: 00000000 00000000 11005800 A4000000 |..........X.....|
+CHECK-NEXT: 0AC0: 0D004800 2E160000 82001200 BC010000 |..H.............|
+CHECK-NEXT: 0AD0: 00000000 00006400 66006900 73006800 |......d.f.i.s.h.|
+CHECK-NEXT: 0AE0: 00000000 65007300 61006C00 61006400 |....e.s.a.l.a.d.|
+CHECK-NEXT: 0AF0: 00008000 66006400 75006300 6B000000 |....f.d.u.c.k...|
+CHECK-NEXT: 0B00: 74686973 20697320 61207573 65722064 |this is a user d|
+CHECK-NEXT: 0B10: 6566696E 65642072 65736F75 72636500 |efined resource.|
+CHECK-NEXT: 0B20: 69742063 6F6E7461 696E7320 6D616E79 |it contains many|
+CHECK-NEXT: 0B30: 20737472 696E6773 00000000 00000000 | strings........|
+CHECK-NEXT: 0B40: 74686973 20697320 61207261 6E646F6D |this is a random|
+CHECK-NEXT: 0B50: 20626974 206F6620 64617461 20746861 | bit of data tha|
+CHECK-NEXT: 0B60: 74206D65 616E7320 6E6F7468 696E6700 |t means nothing.|
+CHECK-NEXT: 0B70: A9230E14 F4F60000 7A686534 20736869 |.#......zhe4 shi|
+CHECK-NEXT: 0B80: 34207969 31676534 20737569 326A6931 |4 yi1ge4 sui2ji1|
+CHECK-NEXT: 0B90: 20646520 73687534 6A75342C 207A6865 | de shu4ju4, zhe|
+CHECK-NEXT: 0BA0: 34207969 34776569 347A6865 20736865 |4 yi4wei4zhe she|
+CHECK-NEXT: 0BB0: 6E326D65 00A9230E 14F4F600 00000000 |n2me..#.........|
+CHECK-NEXT: 0BC0: 44696573 20697374 2065696E 207A7566 |Dies ist ein zuf|
+CHECK-NEXT: 0BD0: C3A46C6C 69676573 20426974 20766F6E |..lliges Bit von|
+CHECK-NEXT: 0BE0: 20446174 656E2C20 64696520 6E696368 | Daten, die nich|
+CHECK-NEXT: 0BF0: 74732062 65646575 74657400 A9230E14 |ts bedeutet..#..|
+CHECK-NEXT: 0C00: F4F60000 00000000 11000300 E7030000 |................|
+CHECK-NEXT: 0C10: 0D004400 4C040000 82001200 BC010000 |..D.L...........|
CHECK-NEXT: )
diff --git a/test/COFF/common-alignment.test b/test/COFF/common-alignment.test
index a4ee15729107..db02d9157c85 100644
--- a/test/COFF/common-alignment.test
+++ b/test/COFF/common-alignment.test
@@ -4,8 +4,8 @@
# 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 10 10 00 40
+# CHECK: 1000: b8 00 20 00 40
+# CHECK: 1005: b8 10 20 00 40
--- !COFF
header:
@@ -23,10 +23,6 @@ sections:
- VirtualAddress: 6
SymbolName: bssdata4_align16
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
- Name: .drectve
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
Alignment: 1
@@ -45,18 +41,6 @@ symbols:
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
diff --git a/test/COFF/common.test b/test/COFF/common.test
index 4a00153f3e93..7d11da2ae150 100644
--- a/test/COFF/common.test
+++ b/test/COFF/common.test
@@ -4,11 +4,11 @@
# 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 70 10 00 40
+# CHECK: 1000: b8 00 20 00 40
+# CHECK: 1005: b8 04 20 00 40
+# CHECK: 100a: b8 20 20 00 40
+# CHECK: 100f: b8 60 20 00 40
+# CHECK: 1014: b8 70 20 00 40
--- !COFF
header:
@@ -35,10 +35,6 @@ sections:
- 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
@@ -52,18 +48,6 @@ symbols:
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
diff --git a/test/COFF/crt-chars.test b/test/COFF/crt-chars.test
new file mode 100644
index 000000000000..e685631bb504
--- /dev/null
+++ b/test/COFF/crt-chars.test
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s
+
+# CHECK: Name: .CRT
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: ]
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 010203
+# CHECK-NEXT: )
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .CRT$XCZ
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 03
+ - Name: .CRT$XCU
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 02
+ - Name: .CRT$XCA
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+symbols:
+...
diff --git a/test/COFF/ctors_dtors_priority.s b/test/COFF/ctors_dtors_priority.s
index 60562ba57a52..efa03543027b 100644
--- a/test/COFF/ctors_dtors_priority.s
+++ b/test/COFF/ctors_dtors_priority.s
@@ -22,9 +22,9 @@ main:
.quad 2
# CHECK: Contents of section .ctors:
-# CHECK-NEXT: 140001000 01000000 00000000 02000000 00000000
-# CHECK-NEXT: 140001010 03000000 00000000
-
-# CHECK: Contents of section .dtors:
# CHECK-NEXT: 140002000 01000000 00000000 02000000 00000000
# CHECK-NEXT: 140002010 03000000 00000000
+
+# CHECK: Contents of section .dtors:
+# CHECK-NEXT: 140003000 01000000 00000000 02000000 00000000
+# CHECK-NEXT: 140003010 03000000 00000000
diff --git a/test/COFF/debug-reloc.s b/test/COFF/debug-reloc.s
new file mode 100644
index 000000000000..57ab9bf9cdbc
--- /dev/null
+++ b/test/COFF/debug-reloc.s
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+
+# RUN: lld-link -lldmingw -debug:dwarf -out:%t.exe -entry:mainfunc -subsystem:console %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s -check-prefix SECTIONS
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix RELOCS
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -check-prefix HEADERS
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck %s -check-prefix DEBUG
+
+# SECTIONS: Number: 2
+# SECTIONS-NEXT: Name: .buildid (2E 62 75 69 6C 64 69 64)
+# SECTIONS-NEXT: VirtualSize: 0x35
+# SECTIONS-NEXT: VirtualAddress: 0x2000
+# SECTIONS: Number: 3
+# SECTIONS-NEXT: Name: .data (2E 64 61 74 61 00 00 00)
+# SECTIONS-NEXT: VirtualSize: 0x8
+# SECTIONS-NEXT: VirtualAddress: 0x3000
+
+# RELOCS: BaseReloc [
+# RELOCS-NEXT: Entry {
+# RELOCS-NEXT: Type: DIR64
+# RELOCS-NEXT: Address: 0x3000
+# RELOCS-NEXT: }
+# RELOCS-NEXT: Entry {
+# RELOCS-NEXT: Type: ABSOLUTE
+# RELOCS-NEXT: Address: 0x3000
+# RELOCS-NEXT: }
+# RELOCS-NEXT: ]
+
+# HEADERS: DebugRVA: 0x2000
+# HEADERS: DebugSize: 0x1C
+
+# DEBUG: DebugDirectory [
+# DEBUG: DebugEntry {
+# DEBUG: Type: CodeView (0x2)
+# DEBUG: SizeOfData: 0x19
+# DEBUG: AddressOfRawData: 0x201C
+# DEBUG: PointerToRawData: 0x61C
+
+ .text
+ .def mainfunc;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl mainfunc
+mainfunc:
+.Lfunc_begin0:
+ xorl %eax, %eax
+ retq
+
+ .data
+ .globl ptr
+ptr:
+ .quad mainfunc
+
+ .section .debug_info,"dr"
+ .quad .Lfunc_begin0
diff --git a/test/COFF/def-export-stdcall.s b/test/COFF/def-export-stdcall.s
index 851ac6d975b9..fd1ec2ca3ace 100644
--- a/test/COFF/def-export-stdcall.s
+++ b/test/COFF/def-export-stdcall.s
@@ -32,8 +32,7 @@
# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: __imp_@fastcall@8
# DECORATED-IMPLIB-NEXT: @fastcall@8
-# TODO: To match link.exe, this one should also be Name type: name.
-# DECORATED-IMPLIB: Name type: noprefix
+# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: __imp__stdcall@8
# DECORATED-IMPLIB-NEXT: _stdcall@8
# DECORATED-IMPLIB: Name type: name
@@ -41,12 +40,12 @@
# DECORATED-IMPLIB-NEXT: vectorcall@@8
# DECORATED-EXPORTS: Name: @fastcall@8
-# TODO: To match link.exe, this one should actually be _stdcall@8
-# DECORATED-EXPORTS: Name: stdcall@8
+# DECORATED-EXPORTS: Name: _stdcall@8
# DECORATED-EXPORTS: Name: vectorcall@@8
-# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall@8\n @fastcall@8" > %t.def
+# GNU tools don't support vectorcall at the moment, but test it for completeness.
+# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall@8\n @fastcall@8\n vectorcall@@8" > %t.def
# RUN: lld-link -lldmingw -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib
# RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-MINGW-IMPLIB %s
# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-MINGW-EXPORTS %s
@@ -57,9 +56,39 @@
# DECORATED-MINGW-IMPLIB: Name type: noprefix
# DECORATED-MINGW-IMPLIB-NEXT: __imp__stdcall@8
# DECORATED-MINGW-IMPLIB-NEXT: _stdcall@8
+# GNU tools don't support vectorcall, but this test is just to track that
+# lld's behaviour remains consistent over time.
+# DECORATED-MINGW-IMPLIB: Name type: name
+# DECORATED-MINGW-IMPLIB-NEXT: __imp_vectorcall@@8
+# DECORATED-MINGW-IMPLIB-NEXT: vectorcall@@8
# DECORATED-MINGW-EXPORTS: Name: @fastcall@8
# DECORATED-MINGW-EXPORTS: Name: stdcall@8
+# DECORATED-MINGW-EXPORTS: Name: vectorcall@@8
+
+# RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib
+# RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s
+
+# RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib
+# RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s
+
+# MINGW-KILL-AT-IMPLIB: Name type: noprefix
+# MINGW-KILL-AT-IMPLIB: __imp__fastcall
+# MINGW-KILL-AT-IMPLIB-NEXT: _fastcall
+# MINGW-KILL-AT-IMPLIB: Name type: noprefix
+# MINGW-KILL-AT-IMPLIB-NEXT: __imp__stdcall
+# MINGW-KILL-AT-IMPLIB-NEXT: _stdcall
+# GNU tools don't support vectorcall, but this test is just to track that
+# lld's behaviour remains consistent over time.
+# MINGW-KILL-AT-IMPLIB: Name type: noprefix
+# MINGW-KILL-AT-IMPLIB-NEXT: __imp__vectorcall
+# MINGW-KILL-AT-IMPLIB-NEXT: _vectorcall
+
+# MINGW-KILL-AT-EXPORTS: Name: fastcall
+# MINGW-KILL-AT-EXPORTS: Name: stdcall
+# MINGW-KILL-AT-EXPORTS: Name: vectorcall
.def _stdcall@8;
diff --git a/test/COFF/default-alignment.test b/test/COFF/default-alignment.test
new file mode 100644
index 000000000000..da8ea06a77ee
--- /dev/null
+++ b/test/COFF/default-alignment.test
@@ -0,0 +1,21 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:__ImageBase /subsystem:console
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .rdata:
+# CHECK-NEXT: 01000000 00000000 00000000 00000000
+# CHECK-NEXT: 02
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ SectionData: 01
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ SectionData: 02
+symbols:
+...
diff --git a/test/COFF/delayimports-armnt.yaml b/test/COFF/delayimports-armnt.yaml
index 231b4bc5c1f1..a080d028d20f 100644
--- a/test/COFF/delayimports-armnt.yaml
+++ b/test/COFF/delayimports-armnt.yaml
@@ -20,7 +20,7 @@
# IMPORT-NEXT: UnloadDelayImportTable: 0x0
# IMPORT-NEXT: Import {
# IMPORT-NEXT: Symbol: function (0)
-# IMPORT-NEXT: Address: 0x401019
+# IMPORT-NEXT: Address: 0x40100D
# IMPORT-NEXT: }
# IMPORT-NEXT: }
#
@@ -35,11 +35,11 @@
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ARM_MOV32(T)
-# BASEREL-NEXT: Address: 0x1018
+# BASEREL-NEXT: Address: 0x1022
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
-# BASEREL-NEXT: Type: ARM_MOV32(T)
-# BASEREL-NEXT: Address: 0x102E
+# BASEREL-NEXT: Type: ABSOLUTE
+# BASEREL-NEXT: Address: 0x1000
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: HIGHLOW
@@ -51,19 +51,19 @@
# BASEREL-NEXT: }
# BASEREL-NEXT: ]
#
-# DISASM: 401018: 43 f2 08 0c movw r12, #12296
-# DISASM-NEXT: 40101c: c0 f2 40 0c movt r12, #64
-# DISASM-NEXT: 401020: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr}
-# DISASM-NEXT: 401024: 0d f2 10 0b addw r11, sp, #16
-# DISASM-NEXT: 401028: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7}
-# DISASM-NEXT: 40102c: 61 46 mov r1, r12
-# DISASM-NEXT: 40102e: 42 f2 00 00 movw r0, #8192
-# DISASM-NEXT: 401032: c0 f2 40 00 movt r0, #64
-# DISASM-NEXT: 401036: ff f7 e3 ff bl #-58
-# DISASM-NEXT: 40103a: 84 46 mov r12, r0
-# DISASM-NEXT: 40103c: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7}
-# DISASM-NEXT: 401040: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr}
-# DISASM-NEXT: 401044: 60 47 bx r12
+# DISASM: 40100c: 43 f2 08 0c movw r12, #12296
+# DISASM-NEXT: c0 f2 40 0c movt r12, #64
+# DISASM-NEXT: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr}
+# DISASM-NEXT: 0d f2 10 0b addw r11, sp, #16
+# DISASM-NEXT: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7}
+# DISASM-NEXT: 61 46 mov r1, r12
+# DISASM-NEXT: 42 f2 00 00 movw r0, #8192
+# DISASM-NEXT: c0 f2 40 00 movt r0, #64
+# DISASM-NEXT: ff f7 e9 ff bl #-46
+# DISASM-NEXT: 84 46 mov r12, r0
+# DISASM-NEXT: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7}
+# DISASM-NEXT: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr}
+# DISASM-NEXT: 60 47 bx r12
--- !COFF
header:
diff --git a/test/COFF/delayimports.test b/test/COFF/delayimports.test
index 2c27d58dc793..c6888b31720e 100644
--- a/test/COFF/delayimports.test
+++ b/test/COFF/delayimports.test
@@ -7,35 +7,35 @@
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: ModuleHandle: 0x3018
+IMPORT-NEXT: ImportAddressTable: 0x3020
+IMPORT-NEXT: ImportNameTable: 0x2040
IMPORT-NEXT: BoundDelayImportTable: 0x0
IMPORT-NEXT: UnloadDelayImportTable: 0x0
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: ExitProcess (0)
-IMPORT-NEXT: Address: 0x140002066
+IMPORT-NEXT: Address: 0x140001066
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: (50)
-IMPORT-NEXT: Address: 0x1400020BD
+IMPORT-NEXT: Address: 0x1400010BD
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: MessageBoxA (0)
-IMPORT-NEXT: Address: 0x140002114
+IMPORT-NEXT: Address: 0x140001114
IMPORT-NEXT: }
IMPORT-NEXT: }
BASEREL: BaseReloc [
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1020
+BASEREL-NEXT: Address: 0x3020
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1028
+BASEREL-NEXT: Address: 0x3028
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1030
+BASEREL-NEXT: Address: 0x3030
BASEREL-NEXT: }
diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test
index 006eecff4d95..9aa8f8697d4c 100644
--- a/test/COFF/delayimports32.test
+++ b/test/COFF/delayimports32.test
@@ -2,7 +2,7 @@
# 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: /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
@@ -13,75 +13,75 @@ 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: 0x4040
+IMPORT-NEXT: ModuleHandle: 0x3018
+IMPORT-NEXT: ImportAddressTable: 0x3020
+IMPORT-NEXT: ImportNameTable: 0x2040
IMPORT-NEXT: BoundDelayImportTable: 0x0
IMPORT-NEXT: UnloadDelayImportTable: 0x0
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: ExitProcess (0)
-IMPORT-NEXT: Address: 0x402029
+IMPORT-NEXT: Address: 0x401029
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: MessageBoxA (0)
-IMPORT-NEXT: Address: 0x40203E
+IMPORT-NEXT: Address: 0x40103E
IMPORT-NEXT: }
IMPORT-NEXT: }
BASEREL: BaseReloc [
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x1020
+BASEREL-NEXT: Address: 0x1005
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x1024
+BASEREL-NEXT: Address: 0x100C
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2005
+BASEREL-NEXT: Address: 0x101F
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x200C
+BASEREL-NEXT: Address: 0x1025
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x201F
+BASEREL-NEXT: Address: 0x102C
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2025
+BASEREL-NEXT: Address: 0x1031
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x202C
+BASEREL-NEXT: Address: 0x1041
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2031
+BASEREL-NEXT: Address: 0x1046
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2041
+BASEREL-NEXT: Address: 0x3020
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2046
+BASEREL-NEXT: Address: 0x3024
BASEREL-NEXT: }
BASEREL-NEXT: ]
-DISASM: 202b: 68 20 10 40 00 pushl $4198432
-DISASM-NEXT: 2030: 68 00 40 40 00 pushl $4210688
-DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <.text>
-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 40 40 00 pushl $4210688
-DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <.text>
-DISASM-NEXT: 204f: 5a popl %edx
-DISASM-NEXT: 2050: 59 popl %ecx
-DISASM-NEXT: 2051: ff e0 jmpl *%eax
+DISASM: 102b: 68 20 30 40 00 pushl $4206624
+DISASM-NEXT: 1030: 68 00 20 40 00 pushl $4202496
+DISASM-NEXT: 1035: e8 c6 ff ff ff calll -58 <.text>
+DISASM-NEXT: 103a: 5a popl %edx
+DISASM-NEXT: 103b: 59 popl %ecx
+DISASM-NEXT: 103c: ff e0 jmpl *%eax
+DISASM-NEXT: 103e: 51 pushl %ecx
+DISASM-NEXT: 103f: 52 pushl %edx
+DISASM-NEXT: 1040: 68 24 30 40 00 pushl $4206628
+DISASM-NEXT: 1045: 68 00 20 40 00 pushl $4202496
+DISASM-NEXT: 104a: e8 b1 ff ff ff calll -79 <.text>
+DISASM-NEXT: 104f: 5a popl %edx
+DISASM-NEXT: 1050: 59 popl %ecx
+DISASM-NEXT: 1051: ff e0 jmpl *%eax
diff --git a/test/COFF/dll.test b/test/COFF/dll.test
index abd39f4eeb24..f04e28c561bf 100644
--- a/test/COFF/dll.test
+++ b/test/COFF/dll.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
# RUN: /export:mangled
@@ -26,7 +27,7 @@ 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: lld-link -opt:noicf /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:
diff --git a/test/COFF/dllexport-mingw.s b/test/COFF/dllexport-mingw.s
index 8bf035b36dcf..a96003b5ed22 100644
--- a/test/COFF/dllexport-mingw.s
+++ b/test/COFF/dllexport-mingw.s
@@ -1,4 +1,4 @@
-# REQEUIRES: x86
+# REQUIRES: x86
# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj
diff --git a/test/COFF/dllexport.s b/test/COFF/dllexport.s
new file mode 100644
index 000000000000..78d97c978748
--- /dev/null
+++ b/test/COFF/dllexport.s
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj
+
+# RUN: lld-link -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib
+# RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-IMPLIB %s
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s
+
+# DECORATED-IMPLIB: Name type: name
+# DECORATED-IMPLIB-NEXT: __imp_@fastcall@8
+# DECORATED-IMPLIB-NEXT: @fastcall@8
+# DECORATED-IMPLIB: Name type: name
+# DECORATED-IMPLIB-NEXT: __imp__stdcall@8
+# DECORATED-IMPLIB-NEXT: _stdcall@8
+# DECORATED-IMPLIB: Name type: noprefix
+# DECORATED-IMPLIB-NEXT: __imp___underscored
+# DECORATED-IMPLIB-NEXT: __underscored
+# DECORATED-IMPLIB: Name type: name
+# DECORATED-IMPLIB-NEXT: __imp_vectorcall@@8
+# DECORATED-IMPLIB-NEXT: vectorcall@@8
+
+# DECORATED-EXPORTS: Name: @fastcall@8
+# DECORATED-EXPORTS: Name: _stdcall@8
+# DECORATED-EXPORTS: Name: _underscored
+# DECORATED-EXPORTS: Name: vectorcall@@8
+
+ .def _stdcall@8;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl _stdcall@8
+ .globl @fastcall@8
+ .globl vectorcall@@8
+ .globl __underscored
+_stdcall@8:
+ movl 8(%esp), %eax
+ addl 4(%esp), %eax
+ retl $8
+@fastcall@8:
+ movl 8(%esp), %eax
+ addl 4(%esp), %eax
+ retl $8
+vectorcall@@8:
+ movl 8(%esp), %eax
+ addl 4(%esp), %eax
+ retl $8
+__underscored:
+ ret
+
+ .def _dllmain;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl _dllmain
+_dllmain:
+ retl
+
+.section .drectve
+.ascii "-export:__underscored -export:_stdcall@8 -export:@fastcall@8 -export:vectorcall@@8"
diff --git a/test/COFF/driver.test b/test/COFF/driver.test
index 36de6c200cb1..aef7046d198b 100644
--- a/test/COFF/driver.test
+++ b/test/COFF/driver.test
@@ -4,3 +4,14 @@ MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory
# RUN: lld-link --version | FileCheck -check-prefix=VERSION %s
VERSION: {{LLD [0-9]+\.[0-9]+}}
+
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj
+# RUN: not lld-link /out:%t.exe %t.dll 2>&1 | FileCheck -check-prefix=BADFILE %s
+BADFILE: bad file type. Did you specify a DLL instead of an import library?
+
+# RUN: lld-link /lib /help | FileCheck -check-prefix=LIBHELP %s
+LIBHELP: OVERVIEW: LLVM Lib
+
+# RUN: not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s
+LIBBAD: ignoring /lib since it's not the first argument
diff --git a/test/COFF/duplicate.test b/test/COFF/duplicate.test
index c2f743ebc28f..e2d3181c98f2 100644
--- a/test/COFF/duplicate.test
+++ b/test/COFF/duplicate.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o alpha.obj %S/Inputs/alpha.ll
RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o beta.obj %S/Inputs/beta.ll
RUN: lld-link /out:alpha.dll /dll alpha.obj /implib:alpha.lib
diff --git a/test/COFF/entry-inference3.test b/test/COFF/entry-inference3.test
new file mode 100644
index 000000000000..7de14e10fe8d
--- /dev/null
+++ b/test/COFF/entry-inference3.test
@@ -0,0 +1,35 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: mainCRTStartup
+
+--- !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: mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/error-limit.test b/test/COFF/error-limit.test
index 3eebd12aaabe..09c3b9d07f30 100644
--- a/test/COFF/error-limit.test
+++ b/test/COFF/error-limit.test
@@ -3,27 +3,27 @@ RUN: 21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s
DEFAULT: could not open 01
DEFAULT: could not open 20
-DEFAULT-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+DEFAULT-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors)
DEFAULT-NOT: could not open 21
-RUN: not lld-link /ERRORLIMIT:5 01 02 03 04 05 06 07 08 09 10 2>&1 \
+RUN: not lld-link /errorlimit:5 01 02 03 04 05 06 07 08 09 10 2>&1 \
RUN: | FileCheck -check-prefix=LIMIT5 %s
LIMIT5: could not open 01
LIMIT5: could not open 05
-LIMIT5-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+LIMIT5-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors)
LIMIT5-NOT: could not open 06
-RUN: not lld-link /ERRORLIMIT:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
+RUN: not lld-link /errorlimit:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
RUN: 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s
UNLIMITED: could not open 01
UNLIMITED: could not open 20
UNLIMITED: could not open 21
UNLIMITED: could not open 22
-UNLIMITED-NOT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+UNLIMITED-NOT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors)
-RUN: not lld-link /ERRORLIMIT:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \
+RUN: not lld-link /errorlimit:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \
RUN: 15 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=WRONG %s
-WRONG: /ERRORLIMIT: number expected, but got XYZ
+WRONG: /errorlimit: number expected, but got XYZ
diff --git a/test/COFF/export-all.s b/test/COFF/export-all.s
index 96c7dca5df29..5509a8dbac91 100644
--- a/test/COFF/export-all.s
+++ b/test/COFF/export-all.s
@@ -1,4 +1,4 @@
-# REQEUIRES: x86
+# REQUIRES: x86
# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj
diff --git a/test/COFF/export-armnt.yaml b/test/COFF/export-armnt.yaml
index 367dabf70d88..88d198c59b6c 100644
--- a/test/COFF/export-armnt.yaml
+++ b/test/COFF/export-armnt.yaml
@@ -9,10 +9,10 @@
# CHECK: DLL name: export-armnt.yaml.tmp.dll
# CHECK: Ordinal RVA Name
# CHECK-NEXT: 0 0
-# CHECK-NEXT: 1 0x1000 exportdata
-# CHECK-NEXT: 2 0x2005 exportfn1
-# CHECK-NEXT: 3 0x2009 exportfn2
-# CHECK-NEXT: 4 0x2009 exportfn3
+# CHECK-NEXT: 1 0x3000 exportdata
+# CHECK-NEXT: 2 0x1005 exportfn1
+# CHECK-NEXT: 3 0x1009 exportfn2
+# CHECK-NEXT: 4 0x1009 exportfn3
--- !COFF
header:
diff --git a/test/COFF/export.test b/test/COFF/export.test
index 174f4ac55d9d..a00a29c13d4c 100644
--- a/test/COFF/export.test
+++ b/test/COFF/export.test
@@ -86,6 +86,10 @@ 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
+# RUN: echo "EXPORTS foo=kernel32.foobar" > %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# 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
diff --git a/test/COFF/export32.test b/test/COFF/export32.test
index 34cd1a73319e..9218ac2829d1 100644
--- a/test/COFF/export32.test
+++ b/test/COFF/export32.test
@@ -2,6 +2,10 @@
#
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+# RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s
# CHECK1: Export Table:
# CHECK1: DLL name: export32.test.tmp.dll
@@ -10,6 +14,12 @@
# CHECK1-NEXT: 1 0x1008 exportfn1
# CHECK1-NEXT: 2 0x1010 exportfn2
+# HEADER-MERGE: ExportTableRVA: 0x2000
+# HEADER-MERGE-NEXT: ExportTableSize: 0x7E
+# HEADER-MERGE: Name: .rdata
+# HEADER-MERGE-NEXT: VirtualSize: 0x7E
+# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
+
# 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
diff --git a/test/COFF/filename-casing.s b/test/COFF/filename-casing.s
index e210aea9358a..0834c034ee74 100644
--- a/test/COFF/filename-casing.s
+++ b/test/COFF/filename-casing.s
@@ -6,8 +6,10 @@
# RUN: llvm-lib /out:%T/MixedCase.lib %T/MixedCase.obj
# RUN: not lld-link /machine:x64 /entry:main %T/MixedCase.lib 2>&1 | FileCheck -check-prefix=ARCHIVE %s
-# OBJECT: MixedCase.obj: undefined symbol: f
-# ARCHIVE: MixedCase.lib(MixedCase.obj): undefined symbol: f
+# OBJECT: undefined symbol: f
+# OBJECT-NEXT: >>> referenced by {{.*}}MixedCase.obj:(main)
+# ARCHIVE: undefined symbol: f
+# ARCHIVE-NEXT: >>> referenced by {{.*}}MixedCase.lib(MixedCase.obj):(main)
.globl main
main:
diff --git a/test/COFF/fixed.test b/test/COFF/fixed.test
new file mode 100644
index 000000000000..6975fed0846b
--- /dev/null
+++ b/test/COFF/fixed.test
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+#
+# RUN: lld-link %t.obj /fixed %p/Inputs/std32.lib /subsystem:console \
+# RUN: /entry:main@0 /debug /out:%t.fixed.exe
+# RUN: llvm-readobj -file-headers %t.fixed.exe | \
+# RUN: FileCheck -check-prefix=EXEFIXED %s
+#
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN: /entry:main@0 /debug /out:%t.exe
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=EXEREL %s
+#
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+#
+# RUN: lld-link %t.obj /dll /fixed /debug /out:%t.fixed.dll
+# RUN: llvm-readobj -file-headers %t.fixed.dll | FileCheck -check-prefix=DLLFIXED %s
+#
+# RUN: lld-link %t.obj /dll /debug /out:%t.dll
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=DLLREL %s
+
+EXEFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+DLLFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+EXEREL: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+DLLREL: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
diff --git a/test/COFF/force.test b/test/COFF/force.test
index b96c1f84cd44..20c4e1a6457f 100644
--- a/test/COFF/force.test
+++ b/test/COFF/force.test
@@ -4,8 +4,10 @@
# RUN: lld-link /out:%t.exe /entry:main %t.obj /force >& %t.log
# RUN: FileCheck -check-prefix=WARN %s < %t.log
-# ERROR: error: {{.*}}.obj: undefined symbol: foo
-# WARN: warning: {{.*}}.obj: undefined symbol: foo
+# ERROR: error: undefined symbol: foo
+# ERROR-NEXT: >>> referenced by {{.*}}.obj
+# WARN: warning: undefined symbol: foo
+# WARN-NEXT: >>> referenced by {{.*}}.obj
--- !COFF
header:
diff --git a/test/COFF/gfids-corrupt.s b/test/COFF/gfids-corrupt.s
new file mode 100644
index 000000000000..92cd321c09c1
--- /dev/null
+++ b/test/COFF/gfids-corrupt.s
@@ -0,0 +1,84 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -opt:noref -guard:nolongjmp -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERRS
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s
+
+# ERRS: warning: ignoring .gfids$y symbol table index section in object {{.*}}gfids-corrupt{{.*}}
+# ERRS: warning: ignoring invalid symbol table index in section .gfids$y in object {{.*}}gfids-corrupt{{.*}}
+
+# The table is arbitrary, really.
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 2
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that gfids are present.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+@feat.00 = 0x800
+
+ .def f1; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,f1
+ .global f1
+f1:
+ movl $42, %eax
+ retq
+
+ .def f2; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,f2
+ .global f2
+f2:
+ movl $13, %eax
+ retq
+
+ .section .data,"dw",one_only,fp1
+ .globl fp1
+fp1:
+ .quad f1
+
+ .section .data,"dw",one_only,fp2
+ .globl fp2
+fp2:
+ .quad f2
+
+ .section .gfids$y,"dr",associative,fp1
+ .symidx f1
+ .byte 0
+
+ .section .gfids$y,"dr",associative,fp2
+ .symidx f2
+ .long 0x400
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ callq *fp1(%rip)
+ callq *fp2(%rip)
+ xor %eax, %eax
+ retq
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
diff --git a/test/COFF/gfids-fallback.s b/test/COFF/gfids-fallback.s
new file mode 100644
index 000000000000..53fff17ce0bd
--- /dev/null
+++ b/test/COFF/gfids-fallback.s
@@ -0,0 +1,97 @@
+# REQUIRES: x86
+# RUN: grep -B99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t1.obj
+# RUN: grep -A99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t2.obj
+# RUN: lld-link %t1.obj %t2.obj -guard:nolongjmp -out:%t.exe -entry:main -opt:noref
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s
+
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 3
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that no gfids are present. All symbols used by relocations in this
+# file will be considered address-taken.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+@feat.00 = 0
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ subq $8, %rsp
+ leaq foo(%rip), %rdx
+ callq bar
+ movl $0, %eax
+ addq $8, %rsp
+ retq
+
+# Should not appear in gfids table.
+ .def baz; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,baz
+ .globl baz
+baz:
+ mov $1, %eax
+ retq
+
+ .def qux; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,qux
+ .globl qux
+qux:
+ mov $2, %eax
+ retq
+
+ .def quxx; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,quxx
+ .globl quxx
+quxx:
+ mov $3, %eax
+ retq
+
+# Load config.
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
+
+# SPLITMARKER
+
+# Indicate that gfids are present. This file does not take any addresses.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+@feat.00 = 0x800
+
+ .def foo; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,foo
+ .global foo
+foo:
+ movl $42, %eax
+ retq
+
+ .def bar; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,bar
+ .global bar
+bar:
+ movl $13, %eax
+ retq
diff --git a/test/COFF/gfids-gc.s b/test/COFF/gfids-gc.s
new file mode 100644
index 000000000000..22fdbf19ce45
--- /dev/null
+++ b/test/COFF/gfids-gc.s
@@ -0,0 +1,131 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC
+
+# This assembly is meant to mimic what CL emits for this kind of C code when
+# /Gw (-fdata-sections) is enabled:
+# int f() { return 42; }
+# int g() { return 13; }
+# int (*fp1)() = &f;
+# int (*fp2)() = &g;
+# int main() {
+# return fp1();
+# }
+# Compile with 'cl -c -guard:cf -Gw -O1' and note the two associative .gfids$y
+# sections.
+
+# Expect 3 entries: main, f, and g.
+
+# CHECK-NOGC: ImageBase: 0x140000000
+# CHECK-NOGC: LoadConfig [
+# CHECK-NOGC: SEHandlerTable: 0x0
+# CHECK-NOGC: SEHandlerCount: 0
+# CHECK-NOGC: GuardCFCheckFunction: 0x0
+# CHECK-NOGC: GuardCFCheckDispatch: 0x0
+# CHECK-NOGC: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK-NOGC: GuardCFFunctionCount: 3
+# CHECK-NOGC: GuardFlags: 0x500
+# CHECK-NOGC: GuardAddressTakenIatEntryTable: 0x0
+# CHECK-NOGC: GuardAddressTakenIatEntryCount: 0
+# CHECK-NOGC: GuardLongJumpTargetTable: 0x0
+# CHECK-NOGC: GuardLongJumpTargetCount: 0
+# CHECK-NOGC: ]
+# CHECK-NOGC: GuardFidTable [
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: ]
+
+# Expect 2 entries: main and f. fp2 was discarded, so g was only used as a
+# direct call target.
+
+# CHECK-GC: ImageBase: 0x140000000
+# CHECK-GC: LoadConfig [
+# CHECK-GC: SEHandlerTable: 0x0
+# CHECK-GC: SEHandlerCount: 0
+# CHECK-GC: GuardCFCheckFunction: 0x0
+# CHECK-GC: GuardCFCheckDispatch: 0x0
+# CHECK-GC: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK-GC: GuardCFFunctionCount: 2
+# CHECK-GC: GuardFlags: 0x500
+# CHECK-GC: GuardAddressTakenIatEntryTable: 0x0
+# CHECK-GC: GuardAddressTakenIatEntryCount: 0
+# CHECK-GC: GuardLongJumpTargetTable: 0x0
+# CHECK-GC: GuardLongJumpTargetCount: 0
+# CHECK-GC: ]
+# CHECK-GC: GuardFidTable [
+# CHECK-GC-NEXT: 0x14000{{.*}}
+# CHECK-GC-NEXT: 0x14000{{.*}}
+# CHECK-GC-NEXT: ]
+
+
+# We need @feat.00 to have 0x800 to indicate .gfids are present.
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 0x801
+
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ # Call g directly so that it is not dead stripped.
+ callq g
+ rex64 jmpq *fp1(%rip)
+
+ .def f;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,f
+f:
+ movl $42, %eax
+ retq
+
+ .section .data,"dw",one_only,fp1
+ .globl fp1
+fp1:
+ .quad f
+
+ .section .gfids$y,"dr",associative,fp1
+ .symidx f
+
+# Section GC will remove the following, so 'g' should not be present in the
+# guard fid table.
+
+ .def g;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,g
+g:
+ movl $13, %eax
+ retq
+
+ .section .data,"dw",one_only,fp2
+ .globl fp2
+fp2:
+ .quad g
+
+ .section .gfids$y,"dr",associative,fp2
+ .symidx g
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
diff --git a/test/COFF/gfids-icf.s b/test/COFF/gfids-icf.s
new file mode 100644
index 000000000000..b0b4d7019fc1
--- /dev/null
+++ b/test/COFF/gfids-icf.s
@@ -0,0 +1,88 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:icf -entry:main
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK
+
+# This assembly is meant to mimic what CL emits for this kind of C code:
+# int icf1() { return 42; }
+# int icf2() { return 42; }
+# int (*fp1)() = &icf1;
+# int (*fp2)() = &icf2;
+# int main() {
+# return fp1();
+# return fp2();
+# }
+
+# 'icf1' and 'icf2' are address taken, but should be merged into one entry.
+# There are two entries in the table because 'main' is included.
+
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 2
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that gfids are present.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+@feat.00 = 0x800
+
+ .def icf1; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,icf1
+ .global icf1
+icf1:
+ movl $42, %eax
+ retq
+
+ .def icf2; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,icf2
+ .global icf2
+icf2:
+ movl $42, %eax
+ retq
+
+# Take their two addresses.
+ .data
+ .globl fp1
+fp1:
+ .quad icf1
+ .globl fp2
+fp2:
+ .quad icf2
+
+ .section .gfids$y,"dr"
+ .symidx icf1
+ .symidx icf2
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ callq *fp1(%rip)
+ callq *fp2(%rip)
+ xor %eax, %eax
+ retq
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
diff --git a/test/COFF/guard-longjmp.s b/test/COFF/guard-longjmp.s
new file mode 100644
index 000000000000..a6d115d3ed39
--- /dev/null
+++ b/test/COFF/guard-longjmp.s
@@ -0,0 +1,104 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s
+
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 1
+# CHECK: GuardFlags: 0x10500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x14000{{.*}}
+# CHECK: GuardLongJumpTargetCount: 1
+# CHECK: ]
+# CHECK: GuardLJmpTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# This assembly is reduced from C code like:
+# #include <setjmp.h>
+# jmp_buf buf;
+# void g() { longjmp(buf, 1); }
+# void f() {
+# if (setjmp(buf))
+# return;
+# g();
+# }
+# int main() { f(); }
+
+# We need @feat.00 to have 0x800 to indicate /guard:cf.
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 0x801
+ .def f; .scl 2; .type 32; .endef
+ .globl f
+f:
+ pushq %rbp
+ subq $32, %rsp
+ leaq 32(%rsp), %rbp
+ leaq buf(%rip), %rcx
+ leaq -32(%rbp), %rdx
+ callq _setjmp
+.Lljmp1:
+ testl %eax, %eax
+ je .LBB1_1
+ addq $32, %rsp
+ popq %rbp
+ retq
+.LBB1_1: # %if.end
+ leaq buf(%rip), %rcx
+ movl $1, %edx
+ callq longjmp
+ ud2
+
+ # Record the longjmp target.
+ .section .gljmp$y,"dr"
+ .symidx .Lljmp1
+ .text
+
+ # Provide setjmp/longjmp stubs.
+ .def _setjmp; .scl 2; .type 32; .endef
+ .globl _setjmp
+_setjmp:
+ retq
+
+ .def longjmp; .scl 2; .type 32; .endef
+ .globl longjmp
+longjmp:
+ retq
+
+ .def main; .scl 2; .type 32; .endef
+ .globl main # -- Begin function main
+main: # @main
+ subq $40, %rsp
+ callq f
+ xorl %eax, %eax
+ addq $40, %rsp
+ retq
+
+ .comm buf,256,4 # @buf
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 12, 1, 0
+ .quad __guard_iat_table
+ .quad __guard_iat_count
+ .quad __guard_longjmp_table
+ .quad __guard_fids_count
+ .fill 84, 1, 0
diff --git a/test/COFF/guardcf-align.s b/test/COFF/guardcf-align.s
new file mode 100644
index 000000000000..a0caabc92b0d
--- /dev/null
+++ b/test/COFF/guardcf-align.s
@@ -0,0 +1,45 @@
+# RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: yaml2obj < %p/Inputs/guardcf-align-foobar.yaml \
+# RUN: > %T/guardcf-align-foobar.obj
+# RUN: lld-link -out:%T/guardcf-align.exe -entry:main -guard:cf \
+# RUN: %t.obj %T/guardcf-align-foobar.obj
+# RUN: llvm-readobj -coff-load-config %T/guardcf-align.exe | FileCheck %s
+
+# Check that the gfids table contains at least one entry that ends in 0
+# and no entries that end in something other than 0.
+# CHECK: GuardFidTable [
+# CHECK-NOT: 0x{{[0-9A-Fa-f]+[^0]$}}
+# CHECK: 0x{{[0-9A-Fa-f]+0$}}
+# CHECK-NOT: 0x{{[0-9A-Fa-f]+[^0]$}}
+# CHECK: ]
+
+# @feat.00 and _load_config_used to indicate we have gfids.
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 0x801
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
+
+# Functions that are called indirectly.
+ .section .gfids$y,"dr"
+ .symidx foo
+
+
+ .section .text,"rx"
+ .global main
+main:
+ movq foo, %rcx
+ xorq %rax, %rax
+ callq bar
+ retq
diff --git a/test/COFF/guardcf-lto.ll b/test/COFF/guardcf-lto.ll
new file mode 100644
index 000000000000..8ab3e1e04f83
--- /dev/null
+++ b/test/COFF/guardcf-lto.ll
@@ -0,0 +1,40 @@
+; REQUIRES: x86
+; Set up an import library for a DLL that will do the indirect call.
+; RUN: echo -e 'LIBRARY library\nEXPORTS\n do_indirect_call\n' > %t.def
+; RUN: lld-link -lib -def:%t.def -out:%t.lib -machine:x64
+
+; Generate an object that will have the load configuration normally provided by
+; the CRT.
+; RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj
+
+; RUN: llvm-as %s -o %t.bc
+; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t.dll
+; RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s
+
+; There must be *two* entries in the table: DLL entry point, and my_handler.
+
+; CHECK: LoadConfig [
+; CHECK: GuardCFFunctionTable: 0x{{[^0].*}}
+; CHECK-NEXT: GuardCFFunctionCount: 2
+; CHECK-NEXT: GuardFlags: 0x10500
+; CHECK: ]
+; CHECK: GuardFidTable [
+; CHECK-NEXT: 0x180{{.*}}
+; CHECK-NEXT: 0x180{{.*}}
+; CHECK-NEXT: ]
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.12.25835"
+
+declare dllimport void @do_indirect_call(void ()*)
+
+define dso_local i32 @main() local_unnamed_addr {
+entry:
+ tail call void @do_indirect_call(void ()* nonnull @my_handler)
+ ret i32 0
+}
+
+define dso_local void @my_handler() {
+entry:
+ ret void
+}
diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test
index 2399193da6a1..87c58797a901 100644
--- a/test/COFF/hello32.test
+++ b/test/COFF/hello32.test
@@ -11,7 +11,7 @@ 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: TimeDateStamp:
HEADER-NEXT: PointerToSymbolTable: 0x0
HEADER-NEXT: SymbolCount: 0
HEADER-NEXT: OptionalHeaderSize: 224
@@ -27,8 +27,8 @@ 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: AddressOfEntryPoint: 0x1000
+HEADER-NEXT: BaseOfCode: 0x1000
HEADER-NEXT: BaseOfData: 0x0
HEADER-NEXT: ImageBase: 0x400000
HEADER-NEXT: SectionAlignment: 4096
@@ -40,7 +40,7 @@ HEADER-NEXT: MinorImageVersion: 0
HEADER-NEXT: MajorSubsystemVersion: 6
HEADER-NEXT: MinorSubsystemVersion: 0
HEADER-NEXT: SizeOfImage: 20480
-HEADER-NEXT: SizeOfHeaders: 512
+HEADER-NEXT: SizeOfHeaders: 1024
HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
HEADER-NEXT: Characteristics [ (0x9540)
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000)
@@ -57,7 +57,7 @@ HEADER-NEXT: NumberOfRvaAndSize: 16
HEADER-NEXT: DataDirectory {
HEADER-NEXT: ExportTableRVA: 0x0
HEADER-NEXT: ExportTableSize: 0x0
-HEADER-NEXT: ImportTableRVA: 0x3000
+HEADER-NEXT: ImportTableRVA: 0x2000
HEADER-NEXT: ImportTableSize: 0x28
HEADER-NEXT: ResourceTableRVA: 0x0
HEADER-NEXT: ResourceTableSize: 0x0
@@ -79,7 +79,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0
HEADER-NEXT: LoadConfigTableSize: 0x0
HEADER-NEXT: BoundImportRVA: 0x0
HEADER-NEXT: BoundImportSize: 0x0
-HEADER-NEXT: IATRVA: 0x3034
+HEADER-NEXT: IATRVA: 0x2034
HEADER-NEXT: IATSize: 0xC
HEADER-NEXT: DelayImportDescriptorRVA: 0x0
HEADER-NEXT: DelayImportDescriptorSize: 0x0
@@ -91,10 +91,10 @@ HEADER-NEXT: }
HEADER-NEXT: }
HEADER-NEXT: DOSHeader {
HEADER-NEXT: Magic: MZ
-HEADER-NEXT: UsedBytesInTheLastPage: 0
-HEADER-NEXT: FileSizeInPages: 0
+HEADER-NEXT: UsedBytesInTheLastPage: 120
+HEADER-NEXT: FileSizeInPages: 1
HEADER-NEXT: NumberOfRelocationItems: 0
-HEADER-NEXT: HeaderSizeInParagraphs: 0
+HEADER-NEXT: HeaderSizeInParagraphs: 4
HEADER-NEXT: MinimumExtraParagraphs: 0
HEADER-NEXT: MaximumExtraParagraphs: 0
HEADER-NEXT: InitialRelativeSS: 0
@@ -106,7 +106,7 @@ HEADER-NEXT: AddressOfRelocationTable: 64
HEADER-NEXT: OverlayNumber: 0
HEADER-NEXT: OEMid: 0
HEADER-NEXT: OEMinfo: 0
-HEADER-NEXT: AddressOfNewExeHeader: 64
+HEADER-NEXT: AddressOfNewExeHeader: 120
HEADER-NEXT: }
IMPORTS: Format: COFF-i386
@@ -114,8 +114,8 @@ IMPORTS: Arch: i386
IMPORTS: AddressSize: 32bit
IMPORTS: Import {
IMPORTS: Name: std32.dll
-IMPORTS: ImportLookupTableRVA: 0x3028
-IMPORTS: ImportAddressTableRVA: 0x3034
+IMPORTS: ImportLookupTableRVA: 0x2028
+IMPORTS: ImportAddressTableRVA: 0x2034
IMPORTS: Symbol: ExitProcess (0)
IMPORTS: Symbol: MessageBoxA (1)
IMPORTS: }
@@ -123,10 +123,10 @@ IMPORTS: }
BASEREL: BaseReloc [
BASEREL: Entry {
BASEREL: Type: HIGHLOW
-BASEREL: Address: 0x2005
+BASEREL: Address: 0x1005
BASEREL: }
BASEREL: Entry {
BASEREL: Type: HIGHLOW
-BASEREL: Address: 0x200C
+BASEREL: Address: 0x100C
BASEREL: }
BASEREL: ]
diff --git a/test/COFF/icf-different-align.test b/test/COFF/icf-different-align.test
index 3502ed3449a4..0e2fce9f65dc 100644
--- a/test/COFF/icf-different-align.test
+++ b/test/COFF/icf-different-align.test
@@ -2,9 +2,14 @@
# 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
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=OBJDUMP %s
-# CHECK-NOT: Selected foo
-# CHECK-NOT: Removed bar
+# CHECK: Selected foo
+# CHECK: Removed bar
+
+# OBJDUMP: Contents of section .text:
+# OBJDUMP-NEXT: 140001000 00cccccc cccccccc cccccccc cccccccc
+# OBJDUMP-NEXT: 140001010 4883ec28 e8000000 004883c4 28c3
--- !COFF
header:
@@ -19,6 +24,10 @@ sections:
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 4883EC28E8000000004883C428C3
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 00
symbols:
- Name: '.text$mn'
Value: 0
diff --git a/test/COFF/icf-executable.s b/test/COFF/icf-executable.s
index 7f923d25ca45..461439d72c1f 100644
--- a/test/COFF/icf-executable.s
+++ b/test/COFF/icf-executable.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link -entry:main %t.obj -out:%t.exe -verbose 2>&1 | FileCheck %s
diff --git a/test/COFF/icf-pdata.s b/test/COFF/icf-pdata.s
new file mode 100644
index 000000000000..8f5b3baece7d
--- /dev/null
+++ b/test/COFF/icf-pdata.s
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata
+# RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s
+
+# CHECK: Name: .pdata
+# CHECK-NEXT: VirtualSize: 0x18
+# CHECK: Name: .xdata
+# CHECK-NEXT: VirtualSize: 0x10
+
+# CHECK: Name: xdata1
+# CHECK-NEXT: RVA: 0x1010
+# CHECK: Name: xdata1a
+# CHECK-NEXT: RVA: 0x1010
+# CHECK: Name: xdata1b
+# CHECK-NEXT: RVA: 0x1030
+
+ .text
+callee:
+ ret
+
+ .def xdata1;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1
+ .globl xdata1 # -- Begin function xdata1
+ .p2align 4, 0x90
+xdata1: # @xdata1
+.seh_proc xdata1
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 40
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1
+ .seh_endproc
+ # -- End function
+
+# xdata1a is identical to xdata1, so it should be ICFd, and so should its pdata.
+# It also has associative debug and CFG sections which should be ignored by ICF.
+ .def xdata1a;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1a
+ .globl xdata1a # -- Begin function xdata1a
+ .p2align 4, 0x90
+xdata1a: # @xdata1a
+.seh_proc xdata1a
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 40
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1a
+ .seh_endproc
+
+ .section .debug$S,"r",associative,xdata1a
+ .section .gfids$y,"r",associative,xdata1a
+ .section .gljmp$y,"r",associative,xdata1a
+
+# xdata1b's text is identical to xdata1, but its xdata specifies a different
+# stack size, so it cannot be ICFd with xdata1.
+ .def xdata1b;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1b
+ .globl xdata1b # -- Begin function xdata1b
+ .p2align 4, 0x90
+xdata1b: # @xdata1b
+.seh_proc xdata1b
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 48
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1b
+ .seh_endproc
+ # -- End function
+
+ .section .drectve,"yn"
+ .ascii " -export:xdata1"
+ .ascii " -export:xdata1a"
+ .ascii " -export:xdata1b"
diff --git a/test/COFF/icf-simple.test b/test/COFF/icf-simple.test
index ead7e7679ce6..19f13c6065fa 100644
--- a/test/COFF/icf-simple.test
+++ b/test/COFF/icf-simple.test
@@ -23,6 +23,11 @@
# RUN: /include:bar /verbose %t.obj > %t.log 2>&1
# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+# /profile disables ICF.
+# RUN: lld-link /profile /entry:foo /out:%t.exe /subsystem:console \
+# RUN: /include:bar /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+
# /opt:noref disables ICF.
# RUN: lld-link /opt:noref /entry:foo /out:%t.exe /subsystem:console \
# RUN: /include:bar /verbose %t.obj > %t.log 2>&1
diff --git a/test/COFF/icf-vtables.s b/test/COFF/icf-vtables.s
new file mode 100644
index 000000000000..650024763610
--- /dev/null
+++ b/test/COFF/icf-vtables.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+.globl main
+main:
+# CHECK-NEXT: 140001000 00200040 01000000 01200040 01000000
+.8byte "??_"
+.8byte "??_7"
+# CHECK-NEXT: 140001010 01200040 01000000
+.8byte "??_7a"
+
+.section .rdata,"dr",discard,"??_"
+.globl "??_"
+"??_":
+.byte 42
+
+.section .rdata,"dr",discard,"??_7"
+.globl "??_7"
+"??_7":
+.byte 42
+
+.section .rdata,"dr",discard,"??_7a"
+.globl "??_7a"
+"??_7a":
+.byte 42
diff --git a/test/COFF/icf-xdata.s b/test/COFF/icf-xdata.s
index 8fb4bad057bd..f2b6c3df6c61 100644
--- a/test/COFF/icf-xdata.s
+++ b/test/COFF/icf-xdata.s
@@ -1,13 +1,26 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata 2>&1 \
+# RUN: | FileCheck %s --check-prefix=WARN
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=XDATA
# RUN: lld-link %t.obj -dll -noentry -out:%t.dll
-# RUN: llvm-readobj -sections %t.dll | FileCheck %s
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=RDATA
# There shouldn't be much xdata, because all three .pdata entries (12 bytes
# each) should use the same .xdata unwind info.
-# CHECK: Name: .pdata
-# CHECK-NEXT: VirtualSize: 0x24
-# CHECK: Name: .xdata
-# CHECK-NEXT: VirtualSize: 0x8
+# XDATA: Name: .rdata
+# XDATA-NEXT: VirtualSize: 0x73
+# XDATA: Name: .pdata
+# XDATA-NEXT: VirtualSize: 0x24
+# XDATA: Name: .xdata
+# XDATA-NEXT: VirtualSize: 0x8
+#
+# WARN: warning: .xdata=.rdata: already merged into .xdata
+#
+# RDATA: Name: .rdata
+# RDATA-NEXT: VirtualSize: 0x7C
+# RDATA: Name: .pdata
+# RDATA-NEXT: VirtualSize: 0x24
.text
callee:
diff --git a/test/COFF/implib-name.test b/test/COFF/implib-name.test
index 81b5b258483f..4a875ab24b74 100644
--- a/test/COFF/implib-name.test
+++ b/test/COFF/implib-name.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: mkdir -p %T
# RUN: llvm-mc -triple x86_64-unknown-windows-msvc -filetype obj -o %T/object.obj %S/Inputs/object.s
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
index 326bfbebbb05..64f3900a1c2f 100644
--- a/test/COFF/imports.test
+++ b/test/COFF/imports.test
@@ -15,8 +15,8 @@ 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: leaq 8180(%rip), %rdx
+TEXT-NEXT: leaq 8167(%rip), %r8
TEXT-NEXT: movl $0, %r9d
TEXT-NEXT: callq 60
TEXT-NEXT: movl $0, %ecx
@@ -28,8 +28,8 @@ TEXT: jmpq *4082(%rip)
IMPORT: Import {
IMPORT-NEXT: Name: std64.dll
-IMPORT-NEXT: ImportLookupTableRVA: 0x3028
-IMPORT-NEXT: ImportAddressTableRVA: 0x3048
+IMPORT-NEXT: ImportLookupTableRVA: 0x2028
+IMPORT-NEXT: ImportAddressTableRVA: 0x2048
IMPORT-NEXT: Symbol: ExitProcess (0)
IMPORT-NEXT: Symbol: (50)
IMPORT-NEXT: Symbol: MessageBoxA (1)
diff --git a/test/COFF/incremental.test b/test/COFF/incremental.test
new file mode 100644
index 000000000000..01f27487da3c
--- /dev/null
+++ b/test/COFF/incremental.test
@@ -0,0 +1,100 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+
+# RUN: lld-link -out:%t.dll -dll %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -incremental %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=WARN-REF %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -debug %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -debug %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,icf %t.obj 2>&1 \
+# RUN: | FileCheck -check-prefix=WARN-ICF %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,icf %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj 2>&1 \
+# RUN: | FileCheck -check-prefix=WARN-REF %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: touch %t.order
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj \
+# RUN: -order:@%t.order 2>&1 | FileCheck -check-prefix=WARN-ORDER %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf -order:@%t.order %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf %t.obj \
+# RUN: -order:@%t.order 2>&1 | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf -order:@%t.order %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj \
+# RUN: -profile 2>&1 | FileCheck -check-prefix=WARN-PROFILE %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf -profile %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf %t.obj \
+# RUN: -profile 2>&1 | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf -profile %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: touch -t 198002011200.00 %t.lib
+# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj
+# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s
+
+# NOWARN-NOT: ignoring '/incremental'
+# WARN-ICF: ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to disable
+# WARN-REF: ignoring '/incremental' because REF is enabled; use '/opt:noref' to disable
+# WARN-ORDER: ignoring '/incremental' due to '/order' specification
+# WARN-PROFILE: ignoring '/incremental' due to '/profile' specification
+# KEEP: {{Feb 1 1980|1980-02-01}}
+# NOKEEP-NOT: {{Feb 1 1980|1980-02-01}}
diff --git a/test/COFF/invalid-section-number.test b/test/COFF/invalid-section-number.test
new file mode 100644
index 000000000000..bada902d7bc0
--- /dev/null
+++ b/test/COFF/invalid-section-number.test
@@ -0,0 +1,34 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: not lld-link %t.obj 2>&1 | FileCheck %s
+
+# CHECK: foo should not refer to special section -10
+
+--- !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: foo
+ Value: 0
+ SectionNumber: -10
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/largeaddressaware.test b/test/COFF/largeaddressaware.test
index d035e7ce9993..76aadee6a946 100644
--- a/test/COFF/largeaddressaware.test
+++ b/test/COFF/largeaddressaware.test
@@ -9,7 +9,7 @@ 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: TimeDateStamp:
HEADER-NEXT: PointerToSymbolTable: 0x0
HEADER-NEXT: SymbolCount: 0
HEADER-NEXT: OptionalHeaderSize: 224
diff --git a/test/COFF/loadcfg.ll b/test/COFF/loadcfg.ll
index c49ae2f6ebd5..6c1cf69e8728 100644
--- a/test/COFF/loadcfg.ll
+++ b/test/COFF/loadcfg.ll
@@ -1,8 +1,9 @@
+; REQUIRES: x86
; 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: LoadConfigTableRVA: 0x2000
; CHECK: LoadConfigTableSize: 0x70
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/COFF/loadcfg.test b/test/COFF/loadcfg.test
index 072ee6b1edb8..2e226f439415 100644
--- a/test/COFF/loadcfg.test
+++ b/test/COFF/loadcfg.test
@@ -2,7 +2,7 @@
# 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: LoadConfigTableRVA: 0x2000
# CHECK: LoadConfigTableSize: 0x70
--- !COFF
diff --git a/test/COFF/loadcfg32.test b/test/COFF/loadcfg32.test
index 03a066c1e552..9485aa08820d 100644
--- a/test/COFF/loadcfg32.test
+++ b/test/COFF/loadcfg32.test
@@ -2,7 +2,7 @@
# 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: LoadConfigTableRVA: 0x2000
# CHECK: LoadConfigTableSize: 0x40
--- !COFF
diff --git a/test/COFF/lto-chkstk.ll b/test/COFF/lto-chkstk.ll
index 43b0bff164e3..cf831615ec52 100644
--- a/test/COFF/lto-chkstk.ll
+++ b/test/COFF/lto-chkstk.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; 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
diff --git a/test/COFF/lto-comdat.ll b/test/COFF/lto-comdat.ll
index b255f69d1ab5..c5c1d7ba0a4f 100644
--- a/test/COFF/lto-comdat.ll
+++ b/test/COFF/lto-comdat.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; 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
@@ -45,25 +46,24 @@
; TEXT-11-NEXT: xorl %eax, %eax
; TEXT-11-NEXT: retq
-; HEADERS-01: AddressOfEntryPoint: 0x2000
+; HEADERS-01: AddressOfEntryPoint: 0x1000
; 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 23
+; TEXT-01-NEXT: callq 18
; TEXT-01-NEXT: callq 13
; TEXT-01-NEXT: xorl %eax, %eax
; TEXT-01-NEXT: addq $40, %rsp
; TEXT-01: retq
; TEXT-01-NOT: callq
; TEXT-01: retq
-; TEXT-01-NOT: callq
-; TEXT-01: retq
-; TEXT-01-NOT: callq
-; TEXT-01: retq
+; TEXT-01: int3
+; TEXT-01: int3
+; TEXT-01: int3
; TEXT-01-NOT: {{.}}
-; HEADERS-10: AddressOfEntryPoint: 0x2020
+; HEADERS-10: AddressOfEntryPoint: 0x1020
; TEXT-10: Disassembly of section .text:
; TEXT-10-NEXT: .text:
; TEXT-10-NEXT: subq $40, %rsp
diff --git a/test/COFF/lto-icf.ll b/test/COFF/lto-icf.ll
new file mode 100644
index 000000000000..b36b572eb889
--- /dev/null
+++ b/test/COFF/lto-icf.ll
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+; Test that ICF works after LTO, i.e. both functions have the same address.
+; Previously, when we didn't enable function sections, ICF didn't work.
+
+; RUN: llvm-as %s -o %t.bc
+; RUN: lld-link -opt:icf -dll -noentry %t.bc -out:%t.dll
+; RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s
+
+; CHECK: Export {
+; CHECK: Export {
+; CHECK: RVA: 0x[[RVA:.*]]
+; CHECK: Export {
+; CHECK: RVA: 0x[[RVA]]
+; CHECK-NOT: Export
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.12.25835"
+
+define dllexport i8* @icf_ptr() {
+entry:
+ ret i8* null
+}
+
+define dllexport i64 @icf_int() {
+entry:
+ ret i64 0
+}
diff --git a/test/COFF/lto-lazy-reference.ll b/test/COFF/lto-lazy-reference.ll
index 22f953975682..1e92873776c1 100644
--- a/test/COFF/lto-lazy-reference.ll
+++ b/test/COFF/lto-lazy-reference.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; RUN: llc -mtriple=i686-pc-windows-msvc -filetype=obj -o %T/lto-lazy-reference-quadruple.obj %S/Inputs/lto-lazy-reference-quadruple.ll
; RUN: llvm-as -o %T/lto-lazy-reference-dummy.bc %S/Inputs/lto-lazy-reference-dummy.ll
; RUN: rm -f %t.lib
diff --git a/test/COFF/lto-linker-opts.ll b/test/COFF/lto-linker-opts.ll
index 1d788754a773..1fc4f5eb0484 100644
--- a/test/COFF/lto-linker-opts.ll
+++ b/test/COFF/lto-linker-opts.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; 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
diff --git a/test/COFF/lto-new-symbol.ll b/test/COFF/lto-new-symbol.ll
index d9e14eb93264..5223f73f07fa 100644
--- a/test/COFF/lto-new-symbol.ll
+++ b/test/COFF/lto-new-symbol.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; RUN: llvm-as -o %t.obj %s
; RUN: lld-link /out:%t.exe /entry:foo /subsystem:console %t.obj
diff --git a/test/COFF/lto-opt-level.ll b/test/COFF/lto-opt-level.ll
index cacd0637731a..92f88ea9e98d 100644
--- a/test/COFF/lto-opt-level.ll
+++ b/test/COFF/lto-opt-level.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; RUN: llvm-as -o %t.obj %s
; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /lldmap:%t0.map %t.obj
; RUN: FileCheck --check-prefix=CHECK-O0 %s < %t0.map
diff --git a/test/COFF/lto-parallel.ll b/test/COFF/lto-parallel.ll
index 449e3a01a853..7a38a39d77d9 100644
--- a/test/COFF/lto-parallel.ll
+++ b/test/COFF/lto-parallel.ll
@@ -1,11 +1,13 @@
+; REQUIRES: x86
; RUN: llvm-as -o %t.obj %s
-; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj
+; RUN: lld-link -opt:noicf /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=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.tmp
+; CHECK: lto.tmp
; CHECK-NEXT: foo
define void @foo() {
call void @bar()
@@ -13,6 +15,7 @@ define void @foo() {
}
; CHECK: lto.tmp
+; CHECK: lto.tmp
; CHECK: bar
define void @bar() {
call void @foo()
diff --git a/test/COFF/lto-reloc-model.ll b/test/COFF/lto-reloc-model.ll
index bea19e9ce3e9..9ac32ae3677f 100644
--- a/test/COFF/lto-reloc-model.ll
+++ b/test/COFF/lto-reloc-model.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; RUN: llvm-as -o %t %s
; RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t
; RUN: llvm-objdump -d %t.exe | FileCheck %s
diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll
index 587ca5ddcf13..c83a151f115b 100644
--- a/test/COFF/lto.ll
+++ b/test/COFF/lto.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86
; 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
@@ -52,7 +53,7 @@
; TEXT-11-NEXT: movl $2, %eax
; TEXT-11-NEXT: retq
-; HEADERS-01: AddressOfEntryPoint: 0x2000
+; HEADERS-01: AddressOfEntryPoint: 0x1000
; TEXT-01: Disassembly of section .text:
; TEXT-01-NEXT: .text:
; TEXT-01-NEXT: subq $40, %rsp
@@ -78,7 +79,7 @@
; TEXT-01-NEXT: int3
; TEXT-01-NEXT: retq
-; HEADERS-10: AddressOfEntryPoint: 0x2020
+; HEADERS-10: AddressOfEntryPoint: 0x1020
; TEXT-10: Disassembly of section .text:
; TEXT-10-NEXT: .text:
; TEXT-10-NEXT: retq
diff --git a/test/COFF/manifestinput-error.test b/test/COFF/manifestinput-error.test
index eca7d0d03927..22ddc6719104 100644
--- a/test/COFF/manifestinput-error.test
+++ b/test/COFF/manifestinput-error.test
@@ -7,4 +7,4 @@
# RUN: /manifestuac:"level='requireAdministrator'" \
# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj 2>&1 | FileCheck %s
-# CHECK: error: unable to find mt.exe in PATH: No such file or directory
+# CHECK: error: unable to find mt.exe in PATH: {{[Nn]}}o such file or directory
diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test
index 51c189098261..33f14d8434ba 100644
--- a/test/COFF/manifestinput.test
+++ b/test/COFF/manifestinput.test
@@ -8,8 +8,8 @@
# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \
# RUN: -check-prefix TEST_EMBED
-TEST_EMBED: ResourceTableRVA: 0x1000
-TEST_EMBED-NEXT: ResourceTableSize: 0x298
+TEST_EMBED: ResourceTableRVA: 0x2000
+TEST_EMBED-NEXT: ResourceTableSize: 0x2A0
TEST_EMBED-DAG: Resources [
TEST_EMBED-NEXT: Total Number of Resources: 1
TEST_EMBED-DAG: Number of String Entries: 0
diff --git a/test/COFF/merge.test b/test/COFF/merge.test
index 4b5c1007f9fb..10a567243106 100644
--- a/test/COFF/merge.test
+++ b/test/COFF/merge.test
@@ -3,9 +3,35 @@
# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.bar /merge:.bar=.abc %t.obj /debug
+# RUN: llvm-readobj -sections %t.exe | FileCheck --check-prefix=CHECK2 %s
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo2 /merge:.foo2=.foo1 %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
+
# CHECK: Name: .def
# CHECK: Name: .abc
+# CHECK2-NOT: Name: .bar
+# CHECK2: Name: .abc
+# CHECK2-NOT: Name: .bar
+
+# NO-RSRC: /merge: cannot merge '.rsrc' with any section
+# NO-RELOC: /merge: cannot merge '.reloc' with any section
+
+# NO-CYCLE: /merge: cycle found for section '.foo'
+
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
diff --git a/test/COFF/nodefaultlib.test b/test/COFF/nodefaultlib.test
index c0f8d50fc7ed..8f4da3a21efe 100644
--- a/test/COFF/nodefaultlib.test
+++ b/test/COFF/nodefaultlib.test
@@ -21,7 +21,8 @@
CHECK1: error: could not open hello64.obj: {{[Nn]}}o such file or directory
CHECK2: error: could not open hello64: {{[Nn]}}o such file or directory
-CHECK3: error: {{.*}}hello64.obj: undefined symbol: MessageBoxA
+CHECK3: error: undefined symbol: MessageBoxA
+CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main)
# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib
diff --git a/test/COFF/opt.test b/test/COFF/opt.test
index a8b0e2eb97ba..ed43b6048085 100644
--- a/test/COFF/opt.test
+++ b/test/COFF/opt.test
@@ -1,18 +1,24 @@
# 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: /verbose 2>&1 | FileCheck -check-prefix=REF %s
+
+# /debug disables the /opt:ref default...
+# RUN: lld-link /out:%t.exe /debug /entry:main %t.obj \
+# RUN: /verbose 2>&1 | FileCheck -check-prefix=NOREF %s
+
+# ...unless /profile is passed as well.
+# RUN: lld-link /out:%t.exe /profile /debug /entry:main %t.obj \
+# RUN: /verbose 2>&1 | FileCheck -check-prefix=REF %s
+
+# RUN: lld-link /out:%t.exe /opt:ref /debug /entry:main %t.obj \
+# RUN: /verbose 2>&1 | FileCheck -check-prefix=REF %s
# 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
+# RUN: /verbose /opt:noref /profile 2>&1 | FileCheck -check-prefix=NOREF %s
-# CHECK1: Discarded unused
-# CHECK2-NOT: Discarded unused
+# REF: Discarded unused
+# NOREF-NOT: Discarded unused
--- !COFF
header:
diff --git a/test/COFF/options.test b/test/COFF/options.test
index 39f944beddbc..6b9f2ca06fab 100644
--- a/test/COFF/options.test
+++ b/test/COFF/options.test
@@ -30,6 +30,16 @@ ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
# 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 /integritycheck %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=INT %s
+INT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s
+# RUN: lld-link /out:%t.exe /integritycheck:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s
+NOINT-NOT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
+
# 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
@@ -48,4 +58,8 @@ 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
+# RUN: lld-link /dll /out:%t.dll /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s
+# RUN: lld-link /tsaware /dll /out:%t.dll /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s
NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
diff --git a/test/COFF/order-i386.test b/test/COFF/order-i386.test
new file mode 100644
index 000000000000..4cde5fa813f7
--- /dev/null
+++ b/test/COFF/order-i386.test
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: echo fn1 > %t.order
+# RUN: echo fn2 >> %t.order
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \
+# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s
+# CHECK: fn1
+# CHECK: fn2
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \
+# RUN: -lldmap:- -out:%t.exe | FileCheck -check-prefix=DEFAULT %s
+# DEFAULT: fn2
+# DEFAULT: fn1
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+symbols:
+ - Name: '.text'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: '.text'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: _fn2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _fn1
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
+
diff --git a/test/COFF/order.test b/test/COFF/order.test
index bb0a6e5740c0..0006550e56ae 100644
--- a/test/COFF/order.test
+++ b/test/COFF/order.test
@@ -1,15 +1,121 @@
-# 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.tmp2.lib
-CHECK: order.test.tmp3.obj
-CHECK: order.test.tmp3.lib
-CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %p/Inputs/order.yaml > %t2.obj
+
+# RUN: echo fn1 > %t.order
+# RUN: echo fn2 >> %t.order
+# RUN: echo fn3 >> %t.order
+# RUN: echo fn4 >> %t.order
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \
+# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s
+# CHECK: fn1
+# CHECK: fn2
+# CHECK: fn3
+# CHECK: fn4
+# CHECK: unrelated1
+# CHECK: unrelated2
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \
+# RUN: -lldmap:- -ignore:4037 -out:%t.exe | FileCheck -check-prefix=DEFAULT %s
+# DEFAULT: fn2
+# DEFAULT: fn3
+# DEFAULT: unrelated1
+# DEFAULT: unrelated2
+# DEFAULT: fn4
+# DEFAULT: fn1
+
+# RUN: echo fn1 > %t2.order
+# RUN: echo fn2 >> %t2.order
+# RUN: echo fn3 >> %t2.order
+# RUN: echo fn4 >> %t2.order
+# RUN: echo foo >> %t2.order
+# RUN: lld-link -entry:fn1 -subsystem:console -debug %t1.obj %t2.obj \
+# RUN: -out:%t.exe -order:@%t2.order 2>&1 | FileCheck -check-prefix=WARN %s
+# WARN: warning: /order:{{.*}} missing symbol: foo
+# WARN-NOT: f2
+# WARN-NOT: f3
+# WARN-NOT: f4
+# RUN: lld-link -entry:fn1 -subsystem:console -debug %t1.obj %t2.obj \
+# RUN: -out:%t.exe -order:@%t2.order -ignore:4037 2>&1 | \
+# RUN: FileCheck -allow-empty -check-prefix=NOWARN %s
+# NOWARN-NOT: warning: /order:{{.*}} missing symbol: foo
+# NOWARN-NOT: f2
+# NOWARN-NOT: f3
+# NOWARN-NOT: f4
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn3
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: unrelated1
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/output-chars.test b/test/COFF/output-chars.test
new file mode 100644
index 000000000000..2ccb084364ce
--- /dev/null
+++ b/test/COFF/output-chars.test
@@ -0,0 +1,109 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /section:.foo,rwe
+# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=SECTION %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck --check-prefix=MERGE %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar /section:.foo,rwe
+# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=MERGE-SECTION %s
+
+# CHECK: Name: .foo
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: ]
+
+# CHECK: Name: .foo
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: IMAGE_SCN_MEM_WRITE
+# CHECK-NEXT: ]
+
+# SECTION: Name: .foo
+# SECTION: Characteristics [
+# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# SECTION-NEXT: IMAGE_SCN_MEM_READ
+# SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# SECTION-NEXT: ]
+
+# SECTION: Name: .foo
+# SECTION: Characteristics [
+# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# SECTION-NEXT: IMAGE_SCN_MEM_READ
+# SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# SECTION-NEXT: ]
+
+# MERGE: Name: .bar
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 0301
+
+# MERGE: Name: .bar
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 04
+
+# MERGE: Name: .foo
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 02
+
+# MERGE-SECTION: Name: .bar
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: ]
+
+# MERGE-SECTION: Name: .bar
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-SECTION-NEXT: ]
+
+# MERGE-SECTION: Name: .foo
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-SECTION-NEXT: ]
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 02
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 03
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 04
+symbols:
+...
diff --git a/test/COFF/pdata-arm64.yaml b/test/COFF/pdata-arm64.yaml
index f21749b9253f..4f5210c4da81 100644
--- a/test/COFF/pdata-arm64.yaml
+++ b/test/COFF/pdata-arm64.yaml
@@ -3,7 +3,7 @@
# RUN: lld-link /out:%t.exe /entry:func1 /subsystem:console %t.obj
# RUN: llvm-objdump -s -section=.pdata %t.exe | FileCheck -check-prefix=PDATA %s
-# PDATA: 00200000 2500a100 24200000 31002201
+# PDATA: 00100000 2500a100 24100000 31002201
--- !COFF
header:
diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test
index 655f215e0199..2c402739162d 100644
--- a/test/COFF/pdb-comdat.test
+++ b/test/COFF/pdb-comdat.test
@@ -43,10 +43,10 @@ CHECK-NEXT: ============================================================
CHECK-NEXT: Records
CHECK-NEXT: 84 | S_PROCREF [size = 20] `main`
CHECK-NEXT: module = 1, sum name = 0, offset = 120
-CHECK-NEXT: 128 | S_PROCREF [size = 20] `foo`
-CHECK-NEXT: module = 1, sum name = 0, offset = 208
CHECK-NEXT: 148 | S_PROCREF [size = 20] `bar`
CHECK-NEXT: module = 2, sum name = 0, offset = 120
+CHECK-NEXT: 128 | S_PROCREF [size = 20] `foo`
+CHECK-NEXT: module = 1, sum name = 0, offset = 208
CHECK-NEXT: 104 | S_GDATA32 [size = 24] `global`
CHECK-NEXT: type = 0x0074 (int), addr = 0000:0000
CHECK-NEXT: 168 | S_GDATA32 [size = 24] `global`
@@ -61,7 +61,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler,
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 120 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 24
CHECK: debug start = 4, debug end = 19, flags = none
CHECK: 164 | S_FRAMEPROC [size = 32]
CHECK: size = 40, padding size = 0, offset to padding = 0
@@ -70,7 +70,7 @@ CHECK: flags = has async eh | opt speed
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `0x100A`
CHECK: 208 | S_GPROC32 [size = 44] `foo`
-CHECK: parent = 0, end = 284, addr = 0002:0032, code size = 15
+CHECK: parent = 0, end = 284, addr = 0001:0032, code size = 15
CHECK: debug start = 0, debug end = 14, flags = none
CHECK: 252 | S_FRAMEPROC [size = 32]
CHECK: size = 0, padding size = 0, offset to padding = 0
@@ -84,7 +84,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, l
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 120 | S_GPROC32 [size = 44] `bar`
-CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14
+CHECK: parent = 0, end = 196, addr = 0001:0048, code size = 14
CHECK: debug start = 4, debug end = 9, flags = none
CHECK: 164 | S_FRAMEPROC [size = 32]
CHECK: size = 40, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-diff.test b/test/COFF/pdb-diff.test
deleted file mode 100644
index 17d26b60353e..000000000000
--- a/test/COFF/pdb-diff.test
+++ /dev/null
@@ -1,215 +0,0 @@
-This test verifies that we produce PDBs compatible with MSVC in various ways.
-We check in a cl-generated object file, PDB, and original source which serve
-as the "baseline" for us to measure against. Then we link the same object
-file with LLD and compare the two PDBs. Since the baseline object file and
-PDB are already checked in, we just run LLD on the object file.
-
-RUN: rm -f %T/pdb-diff-lld.pdb %T/pdb-diff-lld.exe
-RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /out:%T/pdb-diff-lld.exe /nodefaultlib \
-RUN: /entry:main %S/Inputs/pdb-diff.obj
-RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ \
-RUN: %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s
-
-CHECK: ----------------------
-CHECK-NEXT: | MSF Super Block |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: | File | |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: | Block Size | I |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: | Block Count |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: | Unknown 1 | I |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: | Directory Size |
-CHECK-NEXT: |----------------+---|
-CHECK-NEXT: ------------------------------------
-CHECK-NEXT: | Stream Directory |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | File | |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Stream Count | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Old MSF Directory | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | PDB Stream | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | TPI Stream | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | DBI Stream | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | IPI Stream | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | New FPO Data | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Section Header Data | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Named Stream "/names" | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Named Stream "/LinkInfo" | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Module "* Linker *" | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | TPI Hash | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | IPI Hash | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Public Symbol Hash | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Global Symbol Hash | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Symbol Records | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: ------------------------------------
-CHECK-NEXT: | String Table |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | File | |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Number of Strings | D |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Hash Version | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Byte Size |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Signature | I |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | Empty Strings |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | {{.*}}pdb-diff.cpp | {{[EI]}} |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | $T0 $ebp = $...p $T0 8 + = | D |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: | d:\src\llvm-...er internal) | D |
-CHECK-NEXT: |------------------------------+---|
-CHECK-NEXT: ----------------------------
-CHECK-NEXT: | PDB Stream |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | File | |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Stream Size |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Age | I |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Guid | D |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Signature | D |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Version | I |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Features (set) | I |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Feature | I |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Named Stream Size |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | Named Streams (map) | {{[EI]}} |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | /names | {{[EI]}} |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: | /LinkInfo | {{[EI]}} |
-CHECK-NEXT: |----------------------+---|
-CHECK-NEXT: ----------------------------------------------
-CHECK-NEXT: | DBI Stream |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | File | |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Dbi Version | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Age | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Machine | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Flags | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Build Major | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Build Minor | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Build Number | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | PDB DLL Version | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | PDB DLL RBLD | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (FPO) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (Exception) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (Fixup) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (OmapToSrc) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (OmapFromSrc) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (SectionHdr) | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (TokenRidMap) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (Xdata) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (Pdata) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (NewFPO) | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | DBG (SectionHdrOrig) | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Globals Stream | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Publics Stream | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Symbol Records | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Has CTypes | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Is Incrementally Linked | D |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Is Stripped | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Module Count | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Source File Count | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Module "Inputs\pdb-diff.obj" |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Modi | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Obj File Name | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Debug Stream | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - C11 Byte Size | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - C13 Byte Size | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - # of files | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Pdb File Path Index | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Source File Name Index | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Symbol Byte Size |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | Module "* Linker *" |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Modi | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Obj File Name | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Debug Stream | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - C11 Byte Size | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - C13 Byte Size | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - # of files | I |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Pdb File Path Index | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Source File Name Index | {{[EI]}} |
-CHECK-NEXT: |----------------------------------------+---|
-CHECK-NEXT: | - Symbol Byte Size |
-CHECK-NEXT: |----------------------------------------+---|
-
-
diff --git a/test/COFF/pdb-exe-path-dots.test b/test/COFF/pdb-exe-path-dots.test
new file mode 100644
index 000000000000..131898122545
--- /dev/null
+++ b/test/COFF/pdb-exe-path-dots.test
@@ -0,0 +1,10 @@
+RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+RUN: rm -rf %t
+RUN: mkdir %t
+RUN: mkdir %t/foo
+RUN: lld-link /debug /pdb:%t/foo/./out.pdb /out:%t/out.exe /entry:main /nodefaultlib \
+RUN: %t1.obj %t2.obj
+RUN: llvm-readobj -coff-debug-directory %t/out.exe | FileCheck %s
+
+CHECK: PDBFileName: {{.*}}tmp{{/|\\}}foo{{/|\\}}out.pdb \ No newline at end of file
diff --git a/test/COFF/pdb-file-static.test b/test/COFF/pdb-file-static.test
new file mode 100644
index 000000000000..f08f717b40af
--- /dev/null
+++ b/test/COFF/pdb-file-static.test
@@ -0,0 +1,51 @@
+# RUN: yaml2obj %S/Inputs/pdb-file-statics-a.yaml > %t.a.obj
+# RUN: yaml2obj %S/Inputs/pdb-file-statics-b.yaml > %t.b.obj
+# RUN: lld-link %t.a.obj %t.b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# S_FILESTATIC records are unique in that they refer to the string table, but
+# they do *not* go through the file checksums table. They refer directly to
+# the string table. This makes for special handling in the linker, so it
+# deserves a custom test.
+
+# Clang doesn't currently generate these records, but MSVC does, so we have to
+# be able to correctly link them. These records are only generated when
+# optimizations are turned on.
+
+# // a.cpp
+# // cl.exe /Z7 /O1 /c a.cpp
+# static int x = 0;
+#
+# void b(int);
+#
+# void a(int) {
+# if (x)
+# b(x);
+# }
+#
+# int main(int argc, char **argv) {
+# a(argc);
+# return x;
+# }
+#
+# // b.cpp
+# // cl.exe /Z7 /O1 /c a.cpp
+# void a(int);
+#
+# static int y = 0;
+#
+# void b(int) {
+# if (y)
+# a(y);
+# }
+
+# CHECK: Symbols
+# CHECK: ============================================================
+# CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`:
+# CHECK: 232 | S_FILESTATIC [size = 16] `x`
+# CHECK-NEXT: type = 0x0074 (int), file name = 2 (D:\src\llvmbuild\cl\Debug\x64\a.obj), flags = enreg global | enreg static
+# CHECK: Mod 0001 | `{{.*}}b.obj`:
+# CHECK: 232 | S_FILESTATIC [size = 16] `y`
+# CHECK-NEXT: type = 0x0074 (int), file name = 74 (D:\src\llvmbuild\cl\Debug\x64\b.obj), flags = enreg global | enreg static
+# CHECK-LABEL: Mod 0002 | `* Linker *`:
+
diff --git a/test/COFF/pdb-global-gc.yaml b/test/COFF/pdb-global-gc.yaml
index f2c4450809b0..7206196fae2d 100644
--- a/test/COFF/pdb-global-gc.yaml
+++ b/test/COFF/pdb-global-gc.yaml
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: yaml2obj %s -o %t.obj
# RUN: llvm-mc %S/Inputs/pdb-global-gc.s -triple x86_64-windows-msvc -filetype=obj -o %t2.obj
# RUN: lld-link %t.obj %t2.obj -debug -entry:main \
diff --git a/test/COFF/pdb-global-hashes.test b/test/COFF/pdb-global-hashes.test
index b47e43826537..238613cef69c 100644
--- a/test/COFF/pdb-global-hashes.test
+++ b/test/COFF/pdb-global-hashes.test
@@ -83,7 +83,7 @@ CHECK-NEXT: ============================================================
CHECK-NEXT: Showing 6 records
CHECK-NEXT: 0x1000 | LF_FUNC_ID [size = 20]
CHECK-NEXT: name = main, type = 0x1002, parent scope = <no type>
-CHECK-NEXT: 0x1001 | LF_STRING_ID [size = 48] ID: <no type>, String: D:\src\llvmbuild\clang\Debug\x86\obj.h
+CHECK-NEXT: 0x1001 | LF_STRING_ID [size = {{.*}}] ID: <no type>, String: {{.*}}obj.h
CHECK-NEXT: 0x1002 | LF_UDT_SRC_LINE [size = 16]
CHECK-NEXT: udt = 0x1008, file = 4097, line = 2
CHECK-NEXT: 0x1003 | LF_MFUNC_ID [size = 16]
diff --git a/test/COFF/pdb-globals-dia-func-collision3.test b/test/COFF/pdb-globals-dia-func-collision3.test
new file mode 100644
index 000000000000..532bdd47f13d
--- /dev/null
+++ b/test/COFF/pdb-globals-dia-func-collision3.test
@@ -0,0 +1,81 @@
+REQUIRES: diasdk
+
+Input object file reconstruction:
+
+; // foo.cpp
+; void LJPwNRh() {}
+; void HGfxvKdQO() {}
+; void wuN() {}
+; void tEo() {}
+; void VUo() {}
+; void teO() {}
+; void bqSuLGQgWa() {}
+; void SyJYcL() {}
+; void OUV() {}
+; void quH() {}
+; void rbEaPKrlrRwk() {}
+; void oet() {}
+; void tuM() {}
+; void LuU() {}
+; void loxueqJLH() {}
+; void QplRJuDs() {}
+; void rWDokkLG() {}
+; void sEH() {}
+; void pui() {}
+; void xoZvxw() {}
+;
+; int main(int argc, char **argv) {
+; return 0;
+; }
+
+clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-func-collision3.obj
+
+RUN: lld-link /debug /nodefaultlib /incremental:no /entry:main /out:%t.exe %S/Inputs/globals-dia-func-collision3.obj
+RUN: llvm-pdbutil pretty -with-name=LuU -with-name=oet -with-name=OUV -with-name=pui \
+RUN: -with-name=quH -with-name=sEH -with-name=teO -with-name=tEo \
+RUN: -with-name=tuM -with-name=VUo -with-name=wuN -with-name=SyJYcL \
+RUN: -with-name=xoZvxw -with-name=LJPwNRh -with-name=QplRJuDs -with-name=rWDokkLG \
+RUN: -with-name=HGfxvKdQO -with-name=loxueqJLH -with-name=bqSuLGQgWa -with-name=rbEaPKrlrRwk \
+RUN: %t.pdb | FileCheck %s
+
+
+CHECK: [1 occurrences] - LuU
+CHECK-NEXT: func [0x000010d0+ 0 - 0x000010d1- 1 | sizeof= 1] (FPO) void __cdecl LuU()
+CHECK-NEXT: [1 occurrences] - oet
+CHECK-NEXT: func [0x000010b0+ 0 - 0x000010b1- 1 | sizeof= 1] (FPO) void __cdecl oet()
+CHECK-NEXT: [1 occurrences] - OUV
+CHECK-NEXT: func [0x00001080+ 0 - 0x00001081- 1 | sizeof= 1] (FPO) void __cdecl OUV()
+CHECK-NEXT: [1 occurrences] - pui
+CHECK-NEXT: func [0x00001120+ 0 - 0x00001121- 1 | sizeof= 1] (FPO) void __cdecl pui()
+CHECK-NEXT: [1 occurrences] - quH
+CHECK-NEXT: func [0x00001090+ 0 - 0x00001091- 1 | sizeof= 1] (FPO) void __cdecl quH()
+CHECK-NEXT: [1 occurrences] - sEH
+CHECK-NEXT: func [0x00001110+ 0 - 0x00001111- 1 | sizeof= 1] (FPO) void __cdecl sEH()
+CHECK-NEXT: [1 occurrences] - teO
+CHECK-NEXT: func [0x00001050+ 0 - 0x00001051- 1 | sizeof= 1] (FPO) void __cdecl teO()
+CHECK-NEXT: [1 occurrences] - tEo
+CHECK-NEXT: func [0x00001030+ 0 - 0x00001031- 1 | sizeof= 1] (FPO) void __cdecl tEo()
+CHECK-NEXT: [1 occurrences] - tuM
+CHECK-NEXT: func [0x000010c0+ 0 - 0x000010c1- 1 | sizeof= 1] (FPO) void __cdecl tuM()
+CHECK-NEXT: [1 occurrences] - VUo
+CHECK-NEXT: func [0x00001040+ 0 - 0x00001041- 1 | sizeof= 1] (FPO) void __cdecl VUo()
+CHECK-NEXT: [1 occurrences] - wuN
+CHECK-NEXT: func [0x00001020+ 0 - 0x00001021- 1 | sizeof= 1] (FPO) void __cdecl wuN()
+CHECK-NEXT: [1 occurrences] - SyJYcL
+CHECK-NEXT: func [0x00001070+ 0 - 0x00001071- 1 | sizeof= 1] (FPO) void __cdecl SyJYcL()
+CHECK-NEXT: [1 occurrences] - xoZvxw
+CHECK-NEXT: func [0x00001130+ 0 - 0x00001131- 1 | sizeof= 1] (FPO) void __cdecl xoZvxw()
+CHECK-NEXT: [1 occurrences] - LJPwNRh
+CHECK-NEXT: func [0x00001000+ 0 - 0x00001001- 1 | sizeof= 1] (FPO) void __cdecl LJPwNRh()
+CHECK-NEXT: [1 occurrences] - QplRJuDs
+CHECK-NEXT: func [0x000010f0+ 0 - 0x000010f1- 1 | sizeof= 1] (FPO) void __cdecl QplRJuDs()
+CHECK-NEXT: [1 occurrences] - rWDokkLG
+CHECK-NEXT: func [0x00001100+ 0 - 0x00001101- 1 | sizeof= 1] (FPO) void __cdecl rWDokkLG()
+CHECK-NEXT: [1 occurrences] - HGfxvKdQO
+CHECK-NEXT: func [0x00001010+ 0 - 0x00001011- 1 | sizeof= 1] (FPO) void __cdecl HGfxvKdQO()
+CHECK-NEXT: [1 occurrences] - loxueqJLH
+CHECK-NEXT: func [0x000010e0+ 0 - 0x000010e1- 1 | sizeof= 1] (FPO) void __cdecl loxueqJLH()
+CHECK-NEXT: [1 occurrences] - bqSuLGQgWa
+CHECK-NEXT: func [0x00001060+ 0 - 0x00001061- 1 | sizeof= 1] (FPO) void __cdecl bqSuLGQgWa()
+CHECK-NEXT: [1 occurrences] - rbEaPKrlrRwk
+CHECK-NEXT: func [0x000010a0+ 0 - 0x000010a1- 1 | sizeof= 1] (FPO) void __cdecl rbEaPKrlrRwk()
diff --git a/test/COFF/pdb-globals-dia-vfunc-collision.test b/test/COFF/pdb-globals-dia-vfunc-collision.test
new file mode 100644
index 000000000000..964901882703
--- /dev/null
+++ b/test/COFF/pdb-globals-dia-vfunc-collision.test
@@ -0,0 +1,42 @@
+REQUIRES: diasdk
+
+Input object file reconstruction:
+
+; // main.cpp
+; struct S {
+; // Function names are chosen specifically to generate hash collisions in the
+; // GSI hash table.
+; virtual int A307() { return 102; }
+; virtual int A400() { return 12; }
+; virtual int A206() { return 201; }
+; virtual int A105() { return 300; }
+; };
+;
+; struct T : public S {
+; int A105() override { return 300; }
+; int A307() override { return 102; }
+; int A206() override { return 201; }
+; int A400() override { return 12; }
+; };
+;
+; int main(int argc, char **argv) {
+; T s;
+; return s.A105() + s.A206() + s.A307() + s.A400();
+; }
+
+clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-collision.obj
+
+RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-collision.obj
+RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s
+
+CHECK: struct T
+CHECK: func [0x000010c0+ 0 - 0x000010dd-29 | sizeof= 29] (FPO) virtual {{.*}}A105()
+CHECK: func [0x00001100+ 0 - 0x0000111b-27 | sizeof= 27] (FPO) virtual {{.*}}A307()
+CHECK: func [0x000010e0+ 0 - 0x000010fd-29 | sizeof= 29] (FPO) virtual {{.*}}A206()
+CHECK: func [0x00001120+ 0 - 0x0000113b-27 | sizeof= 27] (FPO) virtual {{.*}}A400()
+
+CHECK: struct S
+CHECK: func [0x00001160+ 0 - 0x0000116c-12 | sizeof= 12] (FPO) virtual {{.*}}A307()
+CHECK: func [0x00001170+ 0 - 0x0000117c-12 | sizeof= 12] (FPO) virtual {{.*}}A400()
+CHECK: func [0x00001180+ 0 - 0x0000118c-12 | sizeof= 12] (FPO) virtual {{.*}}A206()
+CHECK: func [0x00001190+ 0 - 0x0000119c-12 | sizeof= 12] (FPO) virtual {{.*}}A105()
diff --git a/test/COFF/pdb-globals-dia-vfunc-collision2.test b/test/COFF/pdb-globals-dia-vfunc-collision2.test
new file mode 100644
index 000000000000..cfbc445b37b4
--- /dev/null
+++ b/test/COFF/pdb-globals-dia-vfunc-collision2.test
@@ -0,0 +1,25 @@
+REQUIRES: diasdk
+
+Input object file reconstruction:
+
+; // main.cpp
+; struct S {
+; // Function names are chosen specifically to generate hash collisions in the
+; // GSI hash table.
+; virtual int A132() { return 102; }
+; virtual int A1001() { return 300; }
+; };
+;
+; int main(int argc, char **argv) {
+; S s;
+; return s.A132();
+; }
+
+clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-collision2.obj
+
+RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-collision2.obj
+RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s
+
+CHECK: struct S
+CHECK: func [0x00001060+ 0 - 0x0000106c-12 | sizeof= 12] (FPO) virtual {{.*}}A132()
+CHECK: func [0x00001070+ 0 - 0x0000107c-12 | sizeof= 12] (FPO) virtual {{.*}}A1001()
diff --git a/test/COFF/pdb-globals-dia-vfunc-simple.test b/test/COFF/pdb-globals-dia-vfunc-simple.test
new file mode 100644
index 000000000000..00d95ad7ef00
--- /dev/null
+++ b/test/COFF/pdb-globals-dia-vfunc-simple.test
@@ -0,0 +1,26 @@
+REQUIRES: diasdk
+
+Input object file reconstruction:
+
+; // main.cpp
+; struct Base {
+; virtual int V2() { return 42; }
+; };
+;
+; struct Derived : public Base {
+; int V2() override { return 42; }
+; };
+;
+; int main()
+; {
+; Derived D;
+; return D.V2();
+; }
+
+clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-simple.obj
+
+RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-simple.obj
+RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s
+
+CHECK: func [0x00001070+ 0 - 0x0000107c-12 | sizeof= 12] (FPO) virtual {{.*}}V2()
+CHECK: func [0x000010a0+ 0 - 0x000010ac-12 | sizeof= 12] (FPO) virtual {{.*}}V2()
diff --git a/test/COFF/pdb-globals.test b/test/COFF/pdb-globals.test
index b5e4f49cb458..db0d3f6d7e8d 100644
--- a/test/COFF/pdb-globals.test
+++ b/test/COFF/pdb-globals.test
@@ -15,20 +15,20 @@ RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s
CHECK-LABEL: Global Symbols
CHECK-NEXT: ============================================================
CHECK-NEXT: Records
+CHECK-NEXT: 208 | S_LPROCREF [size = 24] `LocalFunc`
+CHECK-NEXT: module = 1, sum name = 0, offset = 292
CHECK-NEXT: 160 | S_PROCREF [size = 28] `GlobalFunc`
CHECK-NEXT: module = 1, sum name = 0, offset = 52
CHECK-NEXT: 188 | S_PROCREF [size = 20] `main`
CHECK-NEXT: module = 1, sum name = 0, offset = 108
-CHECK-NEXT: 208 | S_LPROCREF [size = 24] `LocalFunc`
-CHECK-NEXT: module = 1, sum name = 0, offset = 292
-CHECK-NEXT: 312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
-CHECK-NEXT: module = 1, sum name = 0, offset = 376
CHECK-NEXT: 232 | S_GDATA32 [size = 28] `__purecall`
-CHECK-NEXT: type = 0x0403 (void*), addr = 0000:0000
+CHECK-NEXT: type = 0x0403 (void*), addr = 0003:0004
CHECK-NEXT: 260 | S_GDATA32 [size = 24] `GlobalVar`
-CHECK-NEXT: type = 0x100B (const int*), addr = 0001:0000
+CHECK-NEXT: type = 0x100B (const int*), addr = 0003:0000
CHECK-NEXT: 284 | S_LDATA32 [size = 28] `ConstantVar`
CHECK-NEXT: type = 0x100A (const int), addr = 0002:0000
+CHECK-NEXT: 312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
+CHECK-NEXT: module = 1, sum name = 0, offset = 376
CHECK-LABEL: Symbols
CHECK-NEXT: ============================================================
diff --git a/test/COFF/pdb-heapsite.yaml b/test/COFF/pdb-heapsite.yaml
index 966ae4284890..bfdd7b4dc555 100644
--- a/test/COFF/pdb-heapsite.yaml
+++ b/test/COFF/pdb-heapsite.yaml
@@ -69,7 +69,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 35
- Register: RSP
+ Register: CVRegRSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s
index 319d4bc0fb80..c970f0ba1980 100644
--- a/test/COFF/pdb-lib.s
+++ b/test/COFF/pdb-lib.s
@@ -13,15 +13,15 @@
# CHECK-NEXT: ============================================================
# CHECK-NEXT: Mod 0000 | `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
# CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
-# CHECK-NEXT: debug stream: 9, # files: 0, has ec info: false
+# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false
# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
# CHECK-NEXT: Mod 0001 | `bar.obj`:
# CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`:
-# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false
+# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false
# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
# CHECK-NEXT: Mod 0002 | `* Linker *`:
# CHECK-NEXT: Obj: ``:
-# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false
+# CHECK-NEXT: debug stream: 12, # files: 0, has ec info: false
# CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 ``
.def _main;
diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test
index 1bb57298f96e..022a447e4d55 100644
--- a/test/COFF/pdb-linker-module.test
+++ b/test/COFF/pdb-linker-module.test
@@ -1,10 +1,11 @@
-RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj
+RUN: echo "/nodefaultlib" > %t.rsp
+RUN: lld-link /debug /pdb:%t.pdb @%t.rsp /entry:main %S/Inputs/pdb-diff.obj
RUN: llvm-pdbutil dump -modules %t.pdb | FileCheck --check-prefix=MODS %s
RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck --check-prefix=SYMS %s
MODS: Mod 0001 | `* Linker *`
MODS-NEXT: Obj: ``:
-MODS-NEXT: debug stream: 10, # files: 0, has ec info: false
+MODS-NEXT: debug stream: 12, # files: 0, has ec info: false
MODS-NEXT: pdb file ni: 1 `{{.*}}pdb-linker-module.test.tmp.pdb`, src file ni: 0 ``
SYMS: Mod 0001 | `* Linker *`
diff --git a/test/COFF/pdb-natvis.test b/test/COFF/pdb-natvis.test
new file mode 100644
index 000000000000..2db68b6bc71a
--- /dev/null
+++ b/test/COFF/pdb-natvis.test
@@ -0,0 +1,26 @@
+REQUIRES: diasdk
+
+RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj
+RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/natvis-1.natvis \
+RUN: /NATVIS:%p/Inputs/natvis-2.natvis /NATVIS:%p/Inputs/natvis-3.natvis /OUT:%t.exe \
+RUN: /PDB:%t.pdb
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN: --check-prefix=CHECK-FIRST %s
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN: --check-prefix=CHECK-SECOND %s
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN: --check-prefix=CHECK-THIRD %s
+
+RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/test2.natvis \
+RUN: /OUT:%t.exe /PDB:%t.pdb 2>&1 | FileCheck --check-prefix=CHECK-MISSING %s
+
+CHECK-FIRST: {{.*}}natvis-1.natvis (16 bytes): obj=<null>, vname={{.*}}natvis-1.natvis, crc=355285096, compression=None
+CHECK-FIRST-NEXT: 1st Natvis Test
+
+CHECK-SECOND: {{.*}}natvis-2.natvis (19 bytes): obj=<null>, vname={{.*}}natvis-2.natvis, crc=4252640062, compression=None
+CHECK-SECOND-NEXT: Second Natvis Test
+
+CHECK-THIRD: {{.*}}natvis-3.natvis (18 bytes): obj=<null>, vname={{.*}}natvis-3.natvis, crc=2069719849, compression=None
+CHECK-THIRD-NEXT: Third Natvis Test
+
+CHECK-MISSING: Cannot open input file: {{.*}}test2.natvis \ No newline at end of file
diff --git a/test/COFF/pdb-procid-remapping.test b/test/COFF/pdb-procid-remapping.test
index cb612400a650..e42616dae47d 100644
--- a/test/COFF/pdb-procid-remapping.test
+++ b/test/COFF/pdb-procid-remapping.test
@@ -9,7 +9,7 @@ CHECK: Symbols
CHECK-NEXT: ============================================================
CHECK-LABEL: Mod 0000 |
CHECK: 92 | S_GPROC32 [size = 44] `main`
-CHECK-NEXT: parent = 0, end = 168, addr = 0002:0000, code size = 14
+CHECK-NEXT: parent = 0, end = 168, addr = 0001:0000, code size = 14
CHECK-NEXT: type = `0x1004 (int (<no type>))`, debug start = 4, debug end = 9, flags = none
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0
@@ -18,7 +18,7 @@ CHECK-NEXT: flags = has async eh | opt speed
CHECK-NEXT: 168 | S_END [size = 4]
CHECK-LABEL: Mod 0001 |
CHECK: 92 | S_GPROC32 [size = 44] `foo`
-CHECK-NEXT: parent = 0, end = 168, addr = 0002:0016, code size = 6
+CHECK-NEXT: parent = 0, end = 168, addr = 0001:0016, code size = 6
CHECK-NEXT: type = `0x1001 (int ())`, debug start = 0, debug end = 5, flags = none
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-publics-import.test b/test/COFF/pdb-publics-import.test
index 1c75e905ed46..a1fe7d00a08c 100644
--- a/test/COFF/pdb-publics-import.test
+++ b/test/COFF/pdb-publics-import.test
@@ -6,7 +6,8 @@ RUN: yaml2obj < %p/Inputs/export.yaml > %t1.obj
RUN: lld-link /out:%t1.dll /dll %t1.obj /implib:%t1.lib \
RUN: /export:exportfn1 /export:exportfn2
RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
-RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /debug /entry:main %t2.obj %t1.lib
+RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /pdbaltpath:test.pdb \
+RUN: /debug /entry:main %t2.obj %t1.lib
RUN: llvm-pdbutil dump %t2.pdb -publics -section-contribs | FileCheck %s
CHECK: Public Symbols
@@ -19,9 +20,9 @@ CHECK-NEXT: flags = function, addr = 0001:0016
CHECK-NEXT: 88 | S_PUB32 [size = 24] `exportfn2`
CHECK-NEXT: flags = function, addr = 0001:0032
CHECK-NEXT: 32 | S_PUB32 [size = 32] `__imp_exportfn2`
-CHECK-NEXT: flags = none, addr = 0003:0072
+CHECK-NEXT: flags = none, addr = 0002:0136
CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1`
-CHECK-NEXT: flags = none, addr = 0003:0064
+CHECK-NEXT: flags = none, addr = 0002:0128
CHECK: Section Contributions
CHECK-NEXT: ============================================================
@@ -38,5 +39,5 @@ CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_S
.rdata debug directory data chunks
CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0000, size = 28, data crc = 0, reloc crc = 0
CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
-CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = {{.*}}, data crc = 0, reloc crc = 0
+CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = 33, data crc = 0, reloc crc = 0
CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
diff --git a/test/COFF/pdb-relative-source-lines.test b/test/COFF/pdb-relative-source-lines.test
new file mode 100644
index 000000000000..8c0894c21801
--- /dev/null
+++ b/test/COFF/pdb-relative-source-lines.test
@@ -0,0 +1,45 @@
+Test the linker line tables on roughly the following example:
+
+==> foo.h <==
+void bar(void);
+inline void foo(void) {
+ bar();
+}
+==> pdb_lines_1.c <==
+#include "foo.h"
+int main(void) {
+ foo();
+ return 42;
+}
+==> pdb_lines_2.c <==
+void bar(void) {
+}
+
+$ clang-cl -Xclang -fdebug-compilation-dir -Xclang . -c -Z7 pdb_lines*.c
+
+RUN: yaml2obj %S/Inputs/pdb_lines_1_relative.yaml -o %t.pdb_lines_1_relative.obj
+RUN: yaml2obj %S/Inputs/pdb_lines_2_relative.yaml -o %t.pdb_lines_2_relative.obj
+RUN: rm -f %t.exe %t.pdb
+RUN: lld-link -debug -pdbsourcepath:c:\\src -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_lines_1_relative.obj %t.pdb_lines_2_relative.obj
+RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s
+
+CHECK-LABEL: - Module: {{.*}}pdb_lines_1_relative.obj
+CHECK-NEXT: ObjFile: {{.*}}pdb_lines_1_relative.obj
+CHECK: SourceFiles:
+CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c'
+CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}foo.h'
+CHECK: Subsections:
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c'
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}foo.h'
+CHECK: - !FileChecksums
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c'
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}foo.h'
+
+CHECK-LABEL: - Module: {{.*}}pdb_lines_2_relative.obj
+CHECK-NEXT: ObjFile: {{.*}}pdb_lines_2_relative.obj
+CHECK: SourceFiles:
+CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
+CHECK: Subsections:
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
+CHECK: - !FileChecksums
+CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
diff --git a/test/COFF/pdb-same-name.test b/test/COFF/pdb-same-name.test
index 76db69fabbd6..352bfc9f9942 100644
--- a/test/COFF/pdb-same-name.test
+++ b/test/COFF/pdb-same-name.test
@@ -15,9 +15,9 @@ RAW: Modules
RAW-NEXT: ============================================================
RAW-NEXT: Mod 0000 | `foo.obj`:
RAW-NEXT: Obj: `{{.*}}1\foo.lib`:
-RAW-NEXT: debug stream: 9, # files: 1, has ec info: false
+RAW-NEXT: debug stream: 11, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
RAW-NEXT: Mod 0001 | `foo.obj`:
RAW-NEXT: Obj: `{{.*}}2\foo.lib`:
-RAW-NEXT: debug stream: 10, # files: 1, has ec info: false
+RAW-NEXT: debug stream: 12, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test
index 2649167e900f..f0381f16e5c0 100644
--- a/test/COFF/pdb-scopes.test
+++ b/test/COFF/pdb-scopes.test
@@ -35,39 +35,39 @@ RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`:
CHECK: 104 | S_GPROC32 [size = 44] `g`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 5
CHECK: debug start = 4, debug end = 4, flags = none
CHECK: 180 | S_REGREL32 [size = 16] `x`
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58
+CHECK: parent = 0, end = 384, addr = 0001:0016, code size = 58
CHECK: debug start = 8, debug end = 53, flags = none
CHECK: 276 | S_REGREL32 [size = 20] `argc`
CHECK: 296 | S_BLOCK32 [size = 24] ``
CHECK: parent = 200, end = 336
-CHECK: code size = 17, addr = 0002:0031
+CHECK: code size = 17, addr = 0001:0031
CHECK: 320 | S_REGREL32 [size = 16] `x`
CHECK: 336 | S_END [size = 4]
CHECK: 340 | S_BLOCK32 [size = 24] ``
CHECK: parent = 200, end = 380
-CHECK: code size = 17, addr = 0002:0050
+CHECK: code size = 17, addr = 0001:0050
CHECK: 364 | S_REGREL32 [size = 16] `y`
CHECK: 380 | S_END [size = 4]
CHECK: 384 | S_END [size = 4]
CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`:
CHECK: 104 | S_GPROC32 [size = 44] `f`
-CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62
+CHECK: parent = 0, end = 284, addr = 0001:0080, code size = 62
CHECK: debug start = 8, debug end = 57, flags = none
CHECK: 180 | S_REGREL32 [size = 16] `x`
CHECK: 196 | S_BLOCK32 [size = 24] ``
CHECK: parent = 104, end = 236
-CHECK: code size = 20, addr = 0002:0095
+CHECK: code size = 20, addr = 0001:0095
CHECK: 220 | S_REGREL32 [size = 16] `y`
CHECK: 236 | S_END [size = 4]
CHECK: 240 | S_BLOCK32 [size = 24] ``
CHECK: parent = 104, end = 280
-CHECK: code size = 20, addr = 0002:0117
+CHECK: code size = 20, addr = 0001:0117
CHECK: 264 | S_REGREL32 [size = 16] `w`
CHECK: 280 | S_END [size = 4]
CHECK: 284 | S_END [size = 4]
diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test
index 389d91f20efb..416cab02fd26 100644
--- a/test/COFF/pdb-source-lines.test
+++ b/test/COFF/pdb-source-lines.test
@@ -26,11 +26,11 @@ RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb |
CHECK-LABEL: DbiStream:
CHECK-NEXT: VerHeader: V70
CHECK-NEXT: Age: 1
-CHECK-NEXT: BuildNumber: 0
+CHECK-NEXT: BuildNumber: 36363
CHECK-NEXT: PdbDllVersion: 0
CHECK-NEXT: PdbDllRbld: 0
CHECK-NEXT: Flags: 0
-CHECK-NEXT: MachineType: x86
+CHECK-NEXT: MachineType: Amd64
CHECK-NEXT: Modules:
CHECK-LABEL: - Module: {{.*}}pdb_lines_1.obj
@@ -43,7 +43,7 @@ CHECK-NEXT: - !Lines
CHECK-NEXT: CodeSize: 19
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 0
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c'
CHECK-NEXT: Lines:
@@ -64,19 +64,11 @@ CHECK-NEXT: LineStart: 5
CHECK-NEXT: IsStatement: true
CHECK-NEXT: EndDelta: 0
CHECK-NEXT: Columns:
-CHECK-NEXT: - !FileChecksums
-CHECK-NEXT: Checksums:
-CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c'
-CHECK-NEXT: Kind: MD5
-CHECK-NEXT: Checksum: 4EB19DCD86C3BA2238A255C718572E7B
-CHECK-NEXT: - FileName: '{{.*}}foo.h'
-CHECK-NEXT: Kind: MD5
-CHECK-NEXT: Checksum: 061EB73ABB642532857A4F1D9CBAC323
CHECK-NEXT: - !Lines
CHECK-NEXT: CodeSize: 14
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 32
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}foo.h'
CHECK-NEXT: Lines:
@@ -93,6 +85,14 @@ CHECK-NEXT: LineStart: 4
CHECK-NEXT: IsStatement: true
CHECK-NEXT: EndDelta: 0
CHECK-NEXT: Columns:
+CHECK-NEXT: - !FileChecksums
+CHECK-NEXT: Checksums:
+CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c'
+CHECK-NEXT: Kind: MD5
+CHECK-NEXT: Checksum: 4EB19DCD86C3BA2238A255C718572E7B
+CHECK-NEXT: - FileName: '{{.*}}foo.h'
+CHECK-NEXT: Kind: MD5
+CHECK-NEXT: Checksum: 061EB73ABB642532857A4F1D9CBAC323
CHECK-LABEL: - Module: {{.*}}pdb_lines_2.obj
CHECK-NEXT: ObjFile: {{.*}}pdb_lines_2.obj
@@ -103,7 +103,7 @@ CHECK-NEXT: - !Lines
CHECK-NEXT: CodeSize: 1
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 48
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}pdb_lines_2.c'
CHECK-NEXT: Lines:
diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml
index 9dad72d3cc2f..0ed1215ec8ee 100644
--- a/test/COFF/pdb-symbol-types.yaml
+++ b/test/COFF/pdb-symbol-types.yaml
@@ -19,7 +19,7 @@
# CHECK-NEXT: 48 | S_PROCREF [size = 20] `main`
# CHECK-NEXT: module = 1, sum name = 0, offset = 116
# CHECK-NEXT: 68 | S_GDATA32 [size = 28] `global_foo`
-# CHECK-NEXT: type = 0x1004 (Foo), addr = 0001:0000
+# CHECK-NEXT: type = 0x1004 (Foo), addr = 0003:0000
# CHECK: Symbols
# CHECK: ============================================================
@@ -30,7 +30,7 @@
# CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
# CHECK: flags = security checks | hot patchable
# CHECK: 116 | S_GPROC32 [size = 44] `main`
-# CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7
+# CHECK: parent = 0, end = 192, addr = 0001:0000, code size = 7
# CHECK: debug start = 0, debug end = 6, flags = none
# CHECK: 160 | S_FRAMEPROC [size = 32]
# CHECK: size = 0, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-thunk.yaml b/test/COFF/pdb-thunk.yaml
index 6435a17e8f62..444800ff9e57 100644
--- a/test/COFF/pdb-thunk.yaml
+++ b/test/COFF/pdb-thunk.yaml
@@ -84,7 +84,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -124,7 +124,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4121
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -164,7 +164,7 @@ sections:
RegRelativeSym:
Offset: 48
Type: 4143
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -208,7 +208,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4143
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2176,7 +2176,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2222,7 +2222,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4121
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-type-server-missing.yaml b/test/COFF/pdb-type-server-missing.yaml
index 91bb04f5622f..fbbb46f6b4fd 100644
--- a/test/COFF/pdb-type-server-missing.yaml
+++ b/test/COFF/pdb-type-server-missing.yaml
@@ -1,13 +1,10 @@
# This is an object compiled with /Zi (see the LF_TYPESERVER2 record) without an
# adjacent type server PDB. Test that LLD fails gracefully on it.
-# FIXME: Ideally we'd do what MSVC does, which is to warn and drop all debug
-# info in the object with the missing PDB.
-
# RUN: yaml2obj %s -o %t.obj
-# RUN: not lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
+# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
-# CHECK: error: Type server PDB was not found
+# CHECK: warning: Type server PDB for {{.*}}.obj is invalid, ignoring debug info.
--- !COFF
header:
diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test
index 898c5d4aa130..51a92db8df7a 100644
--- a/test/COFF/pdb-type-server-simple.test
+++ b/test/COFF/pdb-type-server-simple.test
@@ -72,7 +72,7 @@ CHECK: ============================================================
CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`:
CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj`
CHECK: 104 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 27
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 27
CHECK: type = {{.*}}, debug start = 4, debug end = 22, flags = none
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[A_BUILD]]`
CHECK-LABEL: Mod 0001 | `{{.*}}b.obj`:
@@ -82,14 +82,14 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compil
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 104 | S_GPROC32 [size = 44] `g`
-CHECK: parent = 0, end = 196, addr = 0002:0032, code size = 13
+CHECK: parent = 0, end = 196, addr = 0001:0032, code size = 13
CHECK: type = {{.*}}, debug start = 5, debug end = 12, flags = none
CHECK: 148 | S_FRAMEPROC [size = 32]
CHECK: size = 0, padding size = 0, offset to padding = 0
CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000
CHECK: flags = has async eh | opt speed
CHECK: 180 | S_REGREL32 [size = 16] `p`
-CHECK: type = [[FOO_PTR]] (Foo*), register = RSP, offset = 8
+CHECK: type = [[FOO_PTR]] (Foo*), register = CVRegRSP, offset = 8
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]`
CHECK-LABEL: Mod 0002 | `* Linker *`:
diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test
index dad6de25db58..a7b2a215ec6b 100644
--- a/test/COFF/pdb.test
+++ b/test/COFF/pdb.test
@@ -1,8 +1,8 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
-# RUN: %t1.obj %t2.obj
+# RUN: lld-link /debug /pdb:%t.pdb /pdbaltpath:test.pdb /dll /out:%t.dll \
+# RUN: /entry:main /nodefaultlib %t1.obj %t2.obj
# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \
# RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
@@ -14,7 +14,7 @@
# CHECK: MSF:
# CHECK-NEXT: SuperBlock:
# CHECK-NEXT: BlockSize: 4096
-# CHECK-NEXT: FreeBlockMap: 1
+# CHECK-NEXT: FreeBlockMap: 2
# CHECK-NEXT: NumBlocks:
# CHECK-NEXT: NumDirectoryBytes:
# CHECK-NEXT: Unknown1: 0
@@ -34,11 +34,11 @@
# CHECK-NEXT: DbiStream:
# CHECK-NEXT: VerHeader: V70
# CHECK-NEXT: Age: 1
-# CHECK-NEXT: BuildNumber: 0
+# CHECK-NEXT: BuildNumber: 36363
# CHECK-NEXT: PdbDllVersion: 0
# CHECK-NEXT: PdbDllRbld: 0
# CHECK-NEXT: Flags: 0
-# CHECK-NEXT: MachineType: x86
+# CHECK-NEXT: MachineType: Amd64
# CHECK-NEXT: TpiStream:
# CHECK-NEXT: Version: VC80
# CHECK-NEXT: Records:
@@ -120,16 +120,24 @@
RAW: Modules
RAW-NEXT: ============================================================
RAW-NEXT: Mod 0000 | `{{.*}}pdb.test.tmp1.obj`:
+RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`:
-RAW-NEXT: debug stream: 9, # files: 1, has ec info: false
+RAW-NEXT: debug stream: 11, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
RAW-NEXT: Mod 0001 | `{{.*}}pdb.test.tmp2.obj`:
+RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`:
-RAW-NEXT: debug stream: 10, # files: 1, has ec info: false
+RAW-NEXT: debug stream: 12, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
RAW-NEXT: Mod 0002 | `* Linker *`:
+RAW-NEXT: SC[???] | mod = 2, 0000:0000, size = 0, data crc = 0, reloc crc = 0
+RAW-NEXT: none
RAW-NEXT: Obj: ``:
-RAW-NEXT: debug stream: 11, # files: 0, has ec info: false
+RAW-NEXT: debug stream: 13, # files: 0, has ec info: false
RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 ``
RAW: Types (TPI Stream)
RAW-NEXT: ============================================================
@@ -181,10 +189,29 @@ RAW-NEXT: GSI Header
RAW-NEXT: sig = 0xFFFFFFFF, hdr = 0xF12F091A, hr size = 16, num buckets = 524
RAW-NEXT: Records
RAW-NEXT: 20 | S_PUB32 [size = 20] `main`
-RAW-NEXT: flags = function, addr = 0002:0000
+RAW-NEXT: flags = function, addr = 0001:0000
RAW-NEXT: 0 | S_PUB32 [size = 20] `foo`
-RAW-NEXT: flags = function, addr = 0002:0016
+RAW-NEXT: flags = function, addr = 0001:0016
RAW-NOT: S_PUB32
+RAW-NEXT: Hash Bitmap (
+RAW-NEXT: 0000: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0020: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0040: 00000000 20000000 00000000 00000000 00000000 00000000 00000000 00000000 |.... ...........................|
+RAW-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0080: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 00A0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 00C0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 00E0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0100: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0120: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0140: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0160: 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0180: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 01A0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 01C0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 01E0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
+RAW-NEXT: 0200: 00000000 |....|
+RAW-NEXT: )
RAW-NEXT: Hash Entries
RAW-NEXT: off = 21, refcnt = 1
RAW-NEXT: off = 1, refcnt = 1
@@ -196,93 +223,80 @@ RAW-NEXT: off = 20
RAW-NEXT: off = 0
RAW: Section Headers
RAW-NEXT: ============================================================
+
RAW: SECTION HEADER #1
-RAW-NEXT: .pdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 1000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 400 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .text name
+RAW-NEXT: 16 virtual size
+RAW-NEXT: 1000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 400 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 60000020 flags
+RAW-NEXT: IMAGE_SCN_CNT_CODE
+RAW-NEXT: IMAGE_SCN_MEM_EXECUTE
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: SECTION HEADER #2
-RAW-NEXT: .text name
-RAW-NEXT: virtual size
-RAW-NEXT: 2000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 600 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 60000020 flags
-RAW-NEXT: IMAGE_SCN_CNT_CODE
-RAW-NEXT: IMAGE_SCN_MEM_EXECUTE
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .rdata name
+RAW-NEXT: virtual size
+RAW-NEXT: 2000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 600 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 40000040 flags
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: SECTION HEADER #3
-RAW-NEXT: .xdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 3000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 800 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW: SECTION HEADER #4
-RAW-NEXT: .rdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 4000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: A00 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .pdata name
+RAW-NEXT: C virtual size
+RAW-NEXT: 3000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 800 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 40000040 flags
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: Original Section Headers
RAW-NEXT: ============================================================
RAW-NEXT: PDB does not contain the requested image section header type
RAW: Section Contributions
RAW-NEXT: ============================================================
-RAW-NEXT: SC[.pdata] | mod = 0, 0001:0000, size = 12, data crc = 361370162, reloc crc = 0
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.text] | mod = 0, 0002:0000, size = 14, data crc = 1682752513, reloc crc = 0
+
+RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.text] | mod = 1, 0002:0016, size = 6, data crc = 2139436471, reloc crc = 0
+RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.xdata] | mod = 0, 0003:0000, size = 8, data crc = 264583633, reloc crc = 0
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[???] | mod = 2, 0004:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
+RAW-NEXT: SC[.rdata] | mod = 2, 0002:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[???] | mod = 2, 0004:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
+RAW-NEXT: SC[.rdata] | mod = 2, 0002:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+RAW-NEXT: SC[.rdata] | mod = 0, 0002:0064, size = {{[0-9]+}}, data crc = 264583633, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
+RAW-NEXT: SC[.pdata] | mod = 0, 0003:0000, size = 12, data crc = 361370162, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
RAW-NOT: SC[
RAW: Section Map
RAW-NEXT: ============================================================
+
RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 1, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | 32 bit addr | selector
+RAW-NEXT: flags = read | execute | 32 bit addr | selector
RAW-NEXT: Section 0001 | ovl = 0, group = 0, frame = 2, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | execute | 32 bit addr | selector
+RAW-NEXT: flags = read | 32 bit addr | selector
RAW-NEXT: Section 0002 | ovl = 0, group = 0, frame = 3, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
RAW-NEXT: flags = read | 32 bit addr | selector
RAW-NEXT: Section 0003 | ovl = 0, group = 0, frame = 4, name = 65535
-RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | 32 bit addr | selector
-RAW-NEXT: Section 0004 | ovl = 0, group = 0, frame = 5, name = 65535
-RAW-NEXT: class = 65535, offset = 0, size =
+RAW-NEXT: class = 65535, offset = 0, size = 4294967295
RAW-NEXT: flags = 32 bit addr | absolute addr
diff --git a/test/COFF/pending-comdat.s b/test/COFF/pending-comdat.s
new file mode 100644
index 000000000000..b10dce1f1ea4
--- /dev/null
+++ b/test/COFF/pending-comdat.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+
+# RUN: not lld-link -lldmingw -out:%t.exe -entry:main -subsystem:console %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: other
+
+# Check that the comdat section without a symbol isn't left pending once we iterate symbols
+# to print source of the undefined symbol.
+
+ .text
+ .globl main
+main:
+ call other
+ ret
+
+ .section .data$pending,"w"
+ .linkonce discard
+.Llocal:
+ .byte 0
diff --git a/test/COFF/reloc-arm.test b/test/COFF/reloc-arm.test
index 872e6d53c8aa..87d93ed76bf2 100644
--- a/test/COFF/reloc-arm.test
+++ b/test/COFF/reloc-arm.test
@@ -3,14 +3,14 @@
# RUN: llvm-objdump -s %t.exe | FileCheck %s
# CHECK: .text:
-# CHECK: 402000 01104000 00000000 00000000 00000000
-# CHECK: 402010 01100000 00000000 00000000 00000000
-# CHECK: 402020 41f20009 c0f24009 00000000 00000000
-# CHECK: 402030 fe07e62f 00000000 00000000 00000000
-# CHECK: 402040 3e04de2f 00000000 00000000 00000000
-# CHECK: 402050 fe07d62f 00000000 00000000 00000000
-# CHECK: 402060 fef0cef7 00000000 00000000 00000000
-# CHECK: 402070 00005000 00000000 00000000 00000000
+# CHECK: 401000 01204000 00000000 00000000 00000000
+# CHECK: 401010 01200000 00000000 00000000 00000000
+# CHECK: 401020 42f20009 c0f24009 00000000 00000000
+# CHECK: 401030 0000e62f 00000000 00000000 00000000
+# CHECK: 401040 0000de07 00000000 00000000 00000000
+# CHECK: 401050 0000d62f 00000000 00000000 00000000
+# CHECK: 401060 00f1cef7 00000000 00000000 00000000
+# CHECK: 401070 00005000 00000000 00000000 00000000
--- !COFF
header:
diff --git a/test/COFF/reloc-discarded-dwarf.s b/test/COFF/reloc-discarded-dwarf.s
index 14dc5948b32a..960f3b308a97 100644
--- a/test/COFF/reloc-discarded-dwarf.s
+++ b/test/COFF/reloc-discarded-dwarf.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t1.obj %s
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %s
diff --git a/test/COFF/reloc-discarded-early.s b/test/COFF/reloc-discarded-early.s
index 6d1043dbfa74..181859db9e64 100644
--- a/test/COFF/reloc-discarded-early.s
+++ b/test/COFF/reloc-discarded-early.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
# RUN: lld-link -entry:__ImageBase -subsystem:console -debug %t.obj
diff --git a/test/COFF/reloc-discarded-early2.s b/test/COFF/reloc-discarded-early2.s
index 18e200008721..c5589dc89935 100644
--- a/test/COFF/reloc-discarded-early2.s
+++ b/test/COFF/reloc-discarded-early2.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
# RUN: not lld-link -entry:__ImageBase -subsystem:console %t.obj 2>&1 | FileCheck %s
diff --git a/test/COFF/reloc-discarded.s b/test/COFF/reloc-discarded.s
index 0be4e110b4db..aa8fb3c3447a 100644
--- a/test/COFF/reloc-discarded.s
+++ b/test/COFF/reloc-discarded.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: echo -e '.section .bss,"bw",discard,main_global\n.global main_global\n main_global:\n .long 0' | \
# RUN: llvm-mc - -filetype=obj -o %t1.obj -triple x86_64-windows-msvc
# RUN: llvm-mc %s -filetype=obj -o %t2.obj -triple x86_64-windows-msvc
diff --git a/test/COFF/reloc-x64.test b/test/COFF/reloc-x64.test
index 7af8fb24bd38..21d78428ffeb 100644
--- a/test/COFF/reloc-x64.test
+++ b/test/COFF/reloc-x64.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-objdump -d %t.exe | FileCheck %s
diff --git a/test/COFF/reloc-x86.test b/test/COFF/reloc-x86.test
index 5e1406913756..bd500be164a7 100644
--- a/test/COFF/reloc-x86.test
+++ b/test/COFF/reloc-x86.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/COFF/resource.test b/test/COFF/resource.test
index 53242cdcb63a..4108957f6f68 100644
--- a/test/COFF/resource.test
+++ b/test/COFF/resource.test
@@ -10,11 +10,11 @@ EXE: {{H.e.l.l.o}}
# RUN: llvm-readobj -file-headers -coff-resources -section-data %t.exe | \
# RUN: FileCheck --check-prefix=RESOURCE_INFO %s
-RESOURCE_INFO: ResourceTableRVA: 0x1000
-RESOURCE_INFO-NEXT: ResourceTableSize: 0x88
+RESOURCE_INFO: ResourceTableRVA: 0x2000
+RESOURCE_INFO-NEXT: ResourceTableSize: 0x90
RESOURCE_INFO-DAG: Resources [
RESOURCE_INFO-NEXT: Total Number of Resources: 1
-RESOURCE_INFO-NEXT: Base Table Address: 0x400
+RESOURCE_INFO-NEXT: Base Table Address: 0x600
RESOURCE_INFO-DAG: Number of String Entries: 0
RESOURCE_INFO-NEXT: Number of ID Entries: 1
RESOURCE_INFO-NEXT: Type: kRT_STRING (ID 6) [
@@ -36,9 +36,9 @@ RESOURCE_INFO-NEXT: 0000: 00000000 00000000 00000000 00000100 |................
RESOURCE_INFO-NEXT: 0010: 06000000 18000080 00000000 00000000 |................|
RESOURCE_INFO-NEXT: 0020: 00000000 00000100 01000000 30000080 |............0...|
RESOURCE_INFO-NEXT: 0030: 00000000 00000000 00000000 00000100 |................|
-RESOURCE_INFO-NEXT: 0040: 09040000 48000000 58100000 2A000000 |....H...X...*...|
-RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000500 48006500 |............H.e.|
-RESOURCE_INFO-NEXT: 0060: 6C006C00 6F000000 00000000 00000000 |l.l.o...........|
+RESOURCE_INFO-NEXT: 0040: 09040000 48000000 60200000 2A000000 |....H...` ..*...|
+RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000000 00000000 |................|
+RESOURCE_INFO-NEXT: 0060: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...|
RESOURCE_INFO-NEXT: 0070: 00000000 00000000 00000000 00000000 |................|
-RESOURCE_INFO-NEXT: 0080: 00000000 00000000 |........|
+RESOURCE_INFO-NEXT: 0080: 00000000 00000000 00000000 00000000 |................|
RESOURCE_INFO-NEXT: )
diff --git a/test/COFF/rsds.test b/test/COFF/rsds.test
index 176597786848..6ce92a9c5b03 100644
--- a/test/COFF/rsds.test
+++ b/test/COFF/rsds.test
@@ -1,16 +1,16 @@
# RUN: yaml2obj %s > %t.obj
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test1.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt
-# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test2.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.2.txt
# RUN: cat %t.1.txt %t.2.txt | FileCheck %s
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdb:%t1.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdb:%t2.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt
# RUN: cat %t.3.txt %t.4.txt | FileCheck %s
@@ -18,7 +18,7 @@
# CHECK: DebugDirectory [
# CHECK: DebugEntry {
# CHECK: Characteristics: 0x0
-# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+# CHECK: TimeDateStamp:
# CHECK: MajorVersion: 0x0
# CHECK: MinorVersion: 0x0
# CHECK: Type: CodeView (0x2)
@@ -29,7 +29,7 @@
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
# CHECK: PDBAge: 1
-# CHECK: PDBFileName: {{.*}}.pdb
+# CHECK: PDBFileName: {{.*}}1.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
@@ -37,7 +37,7 @@
# CHECK: DebugDirectory [
# CHECK: DebugEntry {
# CHECK: Characteristics: 0x0
-# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+# CHECK: TimeDateStamp:
# CHECK: MajorVersion: 0x0
# CHECK: MinorVersion: 0x0
# CHECK: Type: CodeView (0x2)
@@ -48,7 +48,7 @@
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID]]
# CHECK: PDBAge: 2
-# CHECK: PDBFileName: {{.*}}.pdb
+# CHECK: PDBFileName: {{.*}}2.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
diff --git a/test/COFF/safeseh-md.s b/test/COFF/safeseh-md.s
index ae731b5211df..b762457a9bb9 100644
--- a/test/COFF/safeseh-md.s
+++ b/test/COFF/safeseh-md.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link %t.obj %S/Inputs/except_handler3.lib -safeseh -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s
diff --git a/test/COFF/safeseh-notable.s b/test/COFF/safeseh-notable.s
new file mode 100644
index 000000000000..8a9d4296dad6
--- /dev/null
+++ b/test/COFF/safeseh-notable.s
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -entry:main
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# This object lacks a _load_config_used global, so we set
+# IMAGE_DLL_CHARACTERISTICS_NO_SEH even though there is an exception handler.
+# This is a more secure default. If someone wants to use a CRT without a load
+# config and they want to use 32-bit SEH, they will need to provide a
+# safeseh-compatible load config.
+
+# CHECK-LABEL: Characteristics [
+# CHECK: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# CHECK: ]
+
+# CHECK-LABEL: DataDirectory {
+# CHECK: LoadConfigTableRVA: 0x0
+# CHECK: LoadConfigTableSize: 0x0
+# CHECK: }
+
+# CHECK-NOT: LoadConfig
+# CHECK-NOT: SEHTable
+
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 1
+
+ .text
+ .def _main; .scl 2; .type 32; .endef
+ .globl _main
+_main:
+ pushl $_my_handler
+ movl $42, %eax
+ popl %ecx
+ ret
+
+ .def _my_handler; .scl 3; .type 32; .endef
+_my_handler:
+ ret
+
+.safeseh _my_handler
diff --git a/test/COFF/safeseh.s b/test/COFF/safeseh.s
index 35f54c590d13..ee6a60d0df21 100644
--- a/test/COFF/safeseh.s
+++ b/test/COFF/safeseh.s
@@ -1,27 +1,36 @@
+# REQUIRES: x86
# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main -debug:dwarf
+# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main
# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-GC
# __safe_se_handler_table needs to be relocated against ImageBase.
# check that the relocation is present.
+#
# CHECK-NOGC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH
# CHECK-NOGC: BaseReloc [
# CHECK-NOGC: Entry {
# CHECK-NOGC: Type: HIGHLOW
# CHECK-NOGC: LoadConfig [
# CHECK-NOGC: Size: 0x48
-# CHECK-NOGC: SEHandlerTable: 0x401048
+# CHECK-NOGC: SEHandlerTable: 0x
# CHECK-NOGC: SEHandlerCount: 1
# CHECK-NOGC: ]
# CHECK-NOGC: SEHTable [
-# CHECK-NOGC-NEXT: 0x402006
+# CHECK-NOGC-NEXT: 0x401006
# CHECK-NOGC-NEXT: ]
-# Without the SEH table, the address is absolute, so check that we do
-# not have a relocation for it.
-# CHECK-GC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# If we enable GC, the exception handler should be removed, and we should add
+# the DLL characteristic flag that indicates that there are no exception
+# handlers in this DLL. The exception handler table in the load config should
+# be empty and there should be no relocations for it.
+#
+# CHECK-GC: Characteristics [
+# CHECK-GC: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# CHECK-GC: ]
# CHECK-GC: BaseReloc [
# CHECK-GC-NEXT: ]
# CHECK-GC: LoadConfig [
diff --git a/test/COFF/secidx-absolute.s b/test/COFF/secidx-absolute.s
index bfe7136b31d2..0b467bbb09bf 100644
--- a/test/COFF/secidx-absolute.s
+++ b/test/COFF/secidx-absolute.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe
# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s
@@ -16,17 +17,17 @@ ret
# CHECK: Sections [
# CHECK: Section {
# CHECK: Number: 1
-# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
+# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
+# CHECK: VirtualSize: 0x1
# CHECK: SectionData (
-# CHECK: 0000: 0300 |..|
+# CHECK: 0000: C3 |.|
# CHECK: )
# CHECK: }
# CHECK: Section {
# CHECK: Number: 2
-# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
-# CHECK: VirtualSize: 0x1
+# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
# CHECK: SectionData (
-# CHECK: 0000: C3 |.|
+# CHECK: 0000: 0300 |..|
# CHECK: )
# CHECK: }
# CHECK-NOT: Section
diff --git a/test/COFF/secrel-absolute.s b/test/COFF/secrel-absolute.s
index bc61fb94b6b0..630af6e72276 100644
--- a/test/COFF/secrel-absolute.s
+++ b/test/COFF/secrel-absolute.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
# RUN: not lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe 2>&1 | FileCheck %s
diff --git a/test/COFF/secrel-common.s b/test/COFF/secrel-common.s
index 0188f6cb9674..0d3aafcad001 100644
--- a/test/COFF/secrel-common.s
+++ b/test/COFF/secrel-common.s
@@ -1,29 +1,31 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe
# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s
-# Section relocations against common symbols resolve to .bss.
+# Section relocations against common symbols resolve to .bss (merged into .data).
# CHECK: Sections [
# CHECK: Section {
# CHECK: Number: 1
-# CHECK: Name: .bss (2E 62 73 73 00 00 00 00)
-# CHECK: VirtualSize: 0x4
+# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
+# CHECK: VirtualSize: 0x1
+# CHECK: SectionData (
+# CHECK: 0000: C3 |.|
+# CHECK: )
# CHECK: }
# CHECK: Section {
# CHECK: Number: 2
# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
# CHECK: SectionData (
-# CHECK: 0000: 00000000 01000000 |........|
+# CHECK: 0000: 00020000 03000000 |........|
# CHECK: )
# CHECK: }
# CHECK: Section {
# CHECK: Number: 3
-# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
-# CHECK: VirtualSize: 0x1
-# CHECK: SectionData (
-# CHECK: 0000: C3 |.|
-# CHECK: )
+# CHECK: Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK: VirtualSize: 0x204
+# CHECK: RawDataSize: 512
# CHECK: }
# CHECK-NOT: Section
# CHECK: ]
@@ -39,3 +41,6 @@ ret
.secrel32 common_global
.secidx common_global
.short 0
+
+.section .data,"drw"
+.zero 512
diff --git a/test/COFF/section-order.test b/test/COFF/section-order.test
new file mode 100644
index 000000000000..2e0279285b78
--- /dev/null
+++ b/test/COFF/section-order.test
@@ -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: section-order.test.tmp1.obj
+CHECK: section-order.test.tmp2.lib
+CHECK: section-order.test.tmp3.obj
+CHECK: section-order.test.tmp3.lib
+CHECK: section-order.test.tmp2.lib(section-order.test.tmp2.obj) for foo
diff --git a/test/COFF/section-size.s b/test/COFF/section-size.s
index 28f3f4acbc9d..d971b6efa5e8 100644
--- a/test/COFF/section-size.s
+++ b/test/COFF/section-size.s
@@ -7,7 +7,7 @@
# Run: lld-link -entry:main %tmain.obj %t3.obj -out:%t.exe
# RUN: not lld-link -entry:main %tmain.obj %t1.obj %t2.obj -out:%t.exe 2>&1 | FileCheck %s
-# CHECK: error: section larger than 4 GiB: .bss
+# CHECK: error: section larger than 4 GiB: .data
.globl main
main:
diff --git a/test/COFF/section.test b/test/COFF/section.test
index 591c04dde73f..5e1162e8f358 100644
--- a/test/COFF/section.test
+++ b/test/COFF/section.test
@@ -16,18 +16,22 @@
# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s
# R: Characteristics [
+# R-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# R-NEXT: IMAGE_SCN_MEM_READ
# R-NEXT: ]
# W: Characteristics [
+# W-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# W-NEXT: IMAGE_SCN_MEM_WRITE
# W-NEXT: ]
# E: Characteristics [
+# E-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# E-NEXT: IMAGE_SCN_MEM_EXECUTE
# E-NEXT: ]
# S: Characteristics [
+# S-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# S-NEXT: IMAGE_SCN_MEM_SHARED
# S-NEXT: ]
diff --git a/test/COFF/sort-debug.test b/test/COFF/sort-debug.test
index 3bad013a309a..5e2701b6610d 100644
--- a/test/COFF/sort-debug.test
+++ b/test/COFF/sort-debug.test
@@ -1,15 +1,28 @@
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+# RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s
+# RUN: lld-link /debug:symtab /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s
# CHECK: Name: .text
+# CHECK: Name: .reloc
# CHECK: Name: .debug_abbrev
# CHECK: Name: .debug_info
# CHECK: Name: .debug_line
# CHECK: Name: .debug_pubnames
# CHECK: Name: .debug_pubtypes
-# CHECK: Name: .reloc
+# NODEBUG: Name: .text
+# NODEBUG: Name: .reloc
+# NODEBUG-NOT: Name: .debug_abbrev
+# NODEBUG-NOT: Name: .debug_info
+# NODEBUG-NOT: Name: .debug_line
+# NODEBUG-NOT: Name: .debug_pubnames
+# NODEBUG-NOT: Name: .debug_pubtypes
--- !COFF
header:
diff --git a/test/COFF/string-tail-merge.s b/test/COFF/string-tail-merge.s
new file mode 100644
index 000000000000..2e3b735dbf90
--- /dev/null
+++ b/test/COFF/string-tail-merge.s
@@ -0,0 +1,106 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf /opt:lldtailmerge
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:nolldtailmerge
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s
+
+# CHECK: Contents of section .text:
+# NOSTM: Contents of section .text:
+.globl main
+main:
+# CHECK-NEXT: 140001000 11200040 01000000 17200040 01000000
+# NOSTM-NEXT: 140001000 00200040 01000000 0c200040 01000000
+.8byte "??_C@_0M@LACCCNMM@hello?5world?$AA@"
+.8byte "??_C@_05MCBCHHEJ@world?$AA@"
+# CHECK-NEXT: 140001010 2a200040 01000000 36200040 01000000
+# NOSTM-NEXT: 140001010 12200040 01000000 2a200040 01000000
+.8byte "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.8byte "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+# CHECK-NEXT: 140001020 00200040 01000000 0c200040 01000000
+# NOSTM-NEXT: 140001020 36200040 01000000 42200040 01000000
+.8byte "??_D@not_a_string_literal"
+.8byte "??_C@string_literal_with_relocs"
+# CHECK-NEXT: 140001030 00300040 01000000 1e200040 01000000
+# NOSTM-NEXT: 140001030 00300040 01000000 48200040 01000000
+.8byte "??_C@string_literal_in_wrong_section"
+.8byte "??_C@overaligned_string_literal"
+
+# CHECK: Contents of section .rdata:
+# CHECK-NEXT: 140002000 68656c6c 6f20776f 726c6400 6f826ca4 hello world.o.l.
+# CHECK-NEXT: 140002010 0068656c 6c6f2077 6f726c64 00006865 .hello world..he
+# CHECK-NEXT: 140002020 6c6c6f20 776f726c 64006800 65006c00 llo world.h.e.l.
+# CHECK-NEXT: 140002030 6c006f00 20007700 6f007200 6c006400 l.o. .w.o.r.l.d.
+# CHECK-NEXT: 140002040 0000 ..
+
+# NOSTM: Contents of section .rdata:
+# NOSTM-NEXT: 140002000 68656c6c 6f20776f 726c6400 776f726c hello world.worl
+# NOSTM-NEXT: 140002010 64006800 65006c00 6c006f00 20007700 d.h.e.l.l.o. .w.
+# NOSTM-NEXT: 140002020 6f007200 6c006400 00007700 6f007200 o.r.l.d...w.o.r.
+# NOSTM-NEXT: 140002030 6c006400 00006865 6c6c6f20 776f726c l.d...hello worl
+# NOSTM-NEXT: 140002040 64006f82 6ca40000 68656c6c 6f20776f d.o.l...hello wo
+# NOSTM-NEXT: 140002050 726c6400 rld.
+
+.section .rdata,"dr",discard,"??_C@_0M@LACCCNMM@hello?5world?$AA@"
+.globl "??_C@_0M@LACCCNMM@hello?5world?$AA@"
+"??_C@_0M@LACCCNMM@hello?5world?$AA@":
+.asciz "hello world"
+
+.section .rdata,"dr",discard,"??_C@_05MCBCHHEJ@world?$AA@"
+.globl "??_C@_05MCBCHHEJ@world?$AA@"
+"??_C@_05MCBCHHEJ@world?$AA@":
+.asciz "world"
+
+.section .rdata,"dr",discard,"??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.globl "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.p2align 1
+"??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@":
+.short 104
+.short 101
+.short 108
+.short 108
+.short 111
+.short 32
+.short 119
+.short 111
+.short 114
+.short 108
+.short 100
+.short 0
+
+.section .rdata,"dr",discard,"??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.globl "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.p2align 1
+"??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@":
+.short 119
+.short 111
+.short 114
+.short 108
+.short 100
+.short 0
+
+.section .data,"drw",discard,"??_C@string_literal_in_wrong_section"
+.globl "??_C@string_literal_in_wrong_section"
+"??_C@string_literal_in_wrong_section":
+.asciz "hello world"
+
+.section .rdata,"dr",discard,"??_D@not_a_string_literal"
+.globl "??_D@not_a_string_literal"
+"??_D@not_a_string_literal":
+.asciz "hello world"
+
+.section .rdata,"dr",discard,"??_C@string_literal_with_relocs"
+.globl "??_C@string_literal_with_relocs"
+"??_C@string_literal_with_relocs":
+.4byte main + 111 + (114 << 8) + (108 << 16) + (100 << 24) # main + "orld"
+.byte 0
+
+.section .rdata,"dr",discard,"??_C@overaligned_string_literal"
+.globl "??_C@overaligned_string_literal"
+.p2align 1
+"??_C@overaligned_string_literal":
+.asciz "hello world"
diff --git a/test/COFF/symtab-gc.s b/test/COFF/symtab-gc.s
new file mode 100644
index 000000000000..5552639908be
--- /dev/null
+++ b/test/COFF/symtab-gc.s
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %tobject.obj %S/Inputs/object.s
+# RUN: lld-link -dll -entry:f -out:%t.dll -implib:%t.lib %tobject.obj
+# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %tmain.obj %s
+# RUN: lld-link -entry:main -out:%t.exe -opt:ref -debug:dwarf %tmain.obj %t.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+# CHECK-NOT: Symbol: f
+
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ retq
+
+ .def stripped;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,stripped
+stripped:
+ callq __imp_f
+ retq
diff --git a/test/COFF/symtab.test b/test/COFF/symtab.test
index 4e46e3383a4a..bedcd2f601a2 100644
--- a/test/COFF/symtab.test
+++ b/test/COFF/symtab.test
@@ -3,6 +3,8 @@
# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
# RUN: lld-link /debug:dwarf /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:symtab /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 /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s
@@ -11,7 +13,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -20,7 +22,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text2
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -29,7 +31,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .data
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .data (1)
+# CHECK-NEXT: Section: .data (3)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -38,7 +40,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: MessageBoxA
# CHECK-NEXT: Value: 80
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -47,7 +49,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: ExitProcess
# CHECK-NEXT: Value: 64
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -56,7 +58,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: message
# CHECK-NEXT: Value: 6
-# CHECK-NEXT: Section: .text2 (3)
+# CHECK-NEXT: Section: .text2
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -65,7 +67,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: main
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -74,7 +76,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: caption
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text2 (3)
+# CHECK-NEXT: Section: .text2
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
diff --git a/test/COFF/thunk-replace.s b/test/COFF/thunk-replace.s
new file mode 100644
index 000000000000..2d47fcc64837
--- /dev/null
+++ b/test/COFF/thunk-replace.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-win32 %s -filetype=obj -o %t.main.obj
+# RUN: llvm-mc -triple=x86_64-win32 %p/Inputs/otherFunc.s -filetype=obj -o %t.other.obj
+# RUN: llvm-ar rcs %t.other.lib %t.other.obj
+# RUN: not lld-link -out:%t.exe -entry:main %t.main.obj %p/Inputs/std64.lib %t.other.lib -opt:noref 2>&1 | FileCheck %s
+# CHECK: MessageBoxA was replaced
+
+.global main
+.text
+main:
+ callq MessageBoxA
+ callq ExitProcess
+ callq otherFunc
+ ret
diff --git a/test/COFF/timestamp.test b/test/COFF/timestamp.test
new file mode 100644
index 000000000000..7e5f79fde53b
--- /dev/null
+++ b/test/COFF/timestamp.test
@@ -0,0 +1,18 @@
+rm %t.*.exe
+RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj
+RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.1.exe
+RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.2.exe
+RUN: lld-link %t.obj /debug /timestamp:0 /entry:main /nodefaultlib /out:%t.3.exe
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO
+
+HASH: ImageFileHeader {
+HASH: TimeDateStamp: [[STAMP:.*]]
+HASH: DebugDirectory [
+HASH: TimeDateStamp: [[STAMP]]
+
+ZERO: ImageFileHeader {
+ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+ZERO: DebugDirectory [
+ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
diff --git a/test/COFF/undefined-symbol-cv.s b/test/COFF/undefined-symbol-cv.s
new file mode 100644
index 000000000000..31a44c384c75
--- /dev/null
+++ b/test/COFF/undefined-symbol-cv.s
@@ -0,0 +1,62 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: ?foo@@YAHXZ
+# CHECK-NEXT: >>> referenced by file1.cpp:1
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by file1.cpp:2
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+
+# CHECK: error: undefined symbol: ?bar@@YAHXZ
+# CHECK-NEXT: >>> referenced by file2.cpp:3
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by file1.cpp:4
+# CHECK-NEXT: >>> {{.*}}.obj:(f1)
+
+# CHECK: error: undefined symbol: ?baz@@YAHXZ
+# CHECK-NEXT: >>> referenced by file1.cpp:5
+# CHECK-NEXT: >>> {{.*}}.obj:(f2)
+
+ .cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1
+ .cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1
+
+ .section .text,"xr",one_only,main
+.globl main
+main:
+ .cv_func_id 0
+ .cv_loc 0 1 1 0 is_stmt 0
+ call "?foo@@YAHXZ"
+ .cv_loc 0 1 2 0
+ call "?foo@@YAHXZ"
+ .cv_loc 0 2 3 0
+ call "?bar@@YAHXZ"
+.Lfunc_end0:
+
+f1:
+ .cv_func_id 1
+ .cv_loc 1 1 4 0 is_stmt 0
+ call "?bar@@YAHXZ"
+.Lfunc_end1:
+
+ .section .text,"xr",one_only,f2
+.globl f2
+f2:
+ .cv_func_id 2
+ .cv_loc 2 1 5 0 is_stmt 0
+ call "?baz@@YAHXZ"
+.Lfunc_end2:
+
+ .section .debug$S,"dr",associative,main
+ .long 4
+ .cv_linetable 0, main, .Lfunc_end0
+ .cv_linetable 1, f1, .Lfunc_end1
+
+ .section .debug$S,"dr",associative,f2
+ .long 4
+ .cv_linetable 2, f2, .Lfunc_end2
+
+ .section .debug$S,"dr"
+ .long 4
+ .cv_filechecksums
+ .cv_stringtable
diff --git a/test/COFF/undefined-symbol.s b/test/COFF/undefined-symbol.s
new file mode 100644
index 000000000000..5d002d82d23c
--- /dev/null
+++ b/test/COFF/undefined-symbol.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: ?foo@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+
+# CHECK: error: undefined symbol: ?bar@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1)
+
+# CHECK: error: undefined symbol: ?baz@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f2)
+
+ .section .text,"xr",one_only,main
+.globl main
+main:
+ call "?foo@@YAHXZ"
+ call "?foo@@YAHXZ"
+ call "?bar@@YAHXZ"
+
+f1:
+ call "?bar@@YAHXZ"
+.Lfunc_end1:
+
+ .section .text,"xr",one_only,f2
+.globl f2
+f2:
+ call "?baz@@YAHXZ"
diff --git a/test/COFF/unwind.test b/test/COFF/unwind.test
index 2415b0542ca5..5b74aa7c1bba 100644
--- a/test/COFF/unwind.test
+++ b/test/COFF/unwind.test
@@ -4,12 +4,24 @@
# 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
+# RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s
+#
+# HEADER: ExceptionTableRVA: 0x3000
+#
+# FIXME: llvm-readobj currently does not understand files with .pdata merged
+# into .rdata. But we can at least check that the section headers look correct.
+#
+# HEADER-MERGE: ExceptionTableRVA: 0x2004
+# HEADER-MERGE-NEXT: ExceptionTableSize: 0x30
+# HEADER-MERGE: Name: .rdata
+# HEADER-MERGE-NEXT: VirtualSize: 0x78
+# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
#
# UNWIND: Function Table:
-# UNWIND: Start Address: 0x2000
-# UNWIND: End Address: 0x201b
-# UNWIND: Unwind Info Address: 0x3000
+# UNWIND: Start Address: 0x1000
+# UNWIND: End Address: 0x101b
+# UNWIND: Unwind Info Address: 0x2004
# UNWIND: Version: 1
# UNWIND: Flags: 1 UNW_ExceptionHandler
# UNWIND: Size of prolog: 18
@@ -24,27 +36,27 @@
# 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: Start Address: 0x1012
+# UNWIND: End Address: 0x1012
+# UNWIND: Unwind Info Address: 0x2020
# 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: Start Address: 0x101b
+# UNWIND: End Address: 0x101c
+# UNWIND: Unwind Info Address: 0x2030
# 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: Start Address: 0x101c
+# UNWIND: End Address: 0x1039
+# UNWIND: Unwind Info Address: 0x2038
# UNWIND: Version: 1
# UNWIND: Flags: 0
# UNWIND: Size of prolog: 14
@@ -122,6 +134,10 @@ sections:
- VirtualAddress: 44
SymbolName: .xdata
Type: IMAGE_REL_AMD64_ADDR32NB
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 00000000
symbols:
- Name: .text
Value: 0
diff --git a/test/COFF/weak-external.test b/test/COFF/weak-external.test
index 7bdadd9b1c94..352b14f08381 100644
--- a/test/COFF/weak-external.test
+++ b/test/COFF/weak-external.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
@@ -5,6 +6,7 @@
# RUN: FileCheck %s < %t2.map
# CHECK: lto.tmp
+# CHECK-NEXT: lto.tmp
# CHECK-NEXT: 0 g
--- !COFF
diff --git a/test/COFF/weak-external2.test b/test/COFF/weak-external2.test
index 30101d73096b..dd9662045676 100644
--- a/test/COFF/weak-external2.test
+++ b/test/COFF/weak-external2.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/COFF/weak-external3.test b/test/COFF/weak-external3.test
index a06ce48a61a6..480b09b2eb0f 100644
--- a/test/COFF/weak-external3.test
+++ b/test/COFF/weak-external3.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
@@ -6,6 +7,7 @@
# RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map
# CHECK1: lto.tmp
+# CHECK1: lto.tmp
# CHECK1-NEXT: 0 g
# CHECK2: weak-external3.test.tmp.obj
diff --git a/test/COFF/wholearchive.s b/test/COFF/wholearchive.s
index da9976382b0d..6a601eba6b0d 100644
--- a/test/COFF/wholearchive.s
+++ b/test/COFF/wholearchive.s
@@ -1,4 +1,4 @@
-# REQEUIRES: x86
+# REQUIRES: x86
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.archive.obj
# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj
@@ -10,6 +10,14 @@
# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj -wholearchive %t.archive.lib -implib:%t.lib
# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB
+# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj %t.archive.lib -wholearchive:%t.archive.lib -implib:%t.lib
+# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB
+
+# RUN: mkdir -p %t.dir
+# RUN: cp %t.archive.lib %t.dir/foo.lib
+# RUN: lld-link -dll -out:%t.dll -entry:main -libpath:%t.dir %t.main.obj %t.dir/./foo.lib -wholearchive:foo.lib -implib:%t.lib
+# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB
+
# CHECK-IMPLIB: Symbol: __imp_exportfn3
# CHECK-IMPLIB: Symbol: exportfn3
diff --git a/test/ELF/Inputs/amdgpu-kernel-2.o b/test/ELF/Inputs/amdgpu-kernel-2.o
deleted file mode 100644
index fa76151f8976..000000000000
--- a/test/ELF/Inputs/amdgpu-kernel-2.o
+++ /dev/null
Binary files differ
diff --git a/test/ELF/Inputs/arm-long-thunk-converge.lds b/test/ELF/Inputs/arm-long-thunk-converge.lds
new file mode 100644
index 000000000000..592d400c8dc6
--- /dev/null
+++ b/test/ELF/Inputs/arm-long-thunk-converge.lds
@@ -0,0 +1,4 @@
+SECTIONS {
+ .foo : { *(.foo) }
+ .bar 0x2000000 : { *(.bar) }
+}
diff --git a/test/ELF/Inputs/as-needed-lazy.s b/test/ELF/Inputs/as-needed-lazy.s
new file mode 100644
index 000000000000..7f9c360dda20
--- /dev/null
+++ b/test/ELF/Inputs/as-needed-lazy.s
@@ -0,0 +1,3 @@
+.global foo
+foo:
+ nop
diff --git a/test/ELF/Inputs/comdat-discarded-reloc.s b/test/ELF/Inputs/comdat-discarded-reloc.s
new file mode 100644
index 000000000000..9526f5ac95c0
--- /dev/null
+++ b/test/ELF/Inputs/comdat-discarded-reloc.s
@@ -0,0 +1,6 @@
+.section .text.bar1,"aG",@progbits,group,comdat
+
+.section .text.bar2
+.global bar
+bar:
+ .quad .text.bar1
diff --git a/test/ELF/Inputs/compress-debug.s b/test/ELF/Inputs/compress-debug.s
new file mode 100644
index 000000000000..5fd9d39a98a0
--- /dev/null
+++ b/test/ELF/Inputs/compress-debug.s
@@ -0,0 +1,5 @@
+.text
+.fill 0x44
+
+.section .debug_info,"",@progbits
+.fill 0x43
diff --git a/test/ELF/Inputs/conflict-debug.s b/test/ELF/Inputs/conflict-debug.s
index 03fb01331815..c38771efc20a 100644
--- a/test/ELF/Inputs/conflict-debug.s
+++ b/test/ELF/Inputs/conflict-debug.s
@@ -3,3 +3,24 @@
.loc 1 4
zed:
nop
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+ .long .debug_line # DW_AT_stmt_list
+.Lend0:
+ .section .debug_line,"",@progbits
diff --git a/test/ELF/Inputs/copy-rel-version.s b/test/ELF/Inputs/copy-rel-version.s
new file mode 100644
index 000000000000..36bb1ba54c9f
--- /dev/null
+++ b/test/ELF/Inputs/copy-rel-version.s
@@ -0,0 +1,11 @@
+.data
+.global foo@v1
+.type foo@v1, @object
+.size foo@v1, 4
+.global foo@@v2
+.type foo@@v2, @object
+.size foo@@v2, 8
+foo@v1:
+foo@@v2:
+.int 0
+.int 0
diff --git a/test/ELF/Inputs/copy-relocation-zero-abs-addr.s b/test/ELF/Inputs/copy-relocation-zero-abs-addr.s
new file mode 100644
index 000000000000..da81e0372d8b
--- /dev/null
+++ b/test/ELF/Inputs/copy-relocation-zero-abs-addr.s
@@ -0,0 +1,7 @@
+.globl ver1
+.globl ver2
+ ver1 = 0x0
+ ver2 = 0x0
+
+.type foo,@object
+.comm foo,16,16
diff --git a/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s
new file mode 100644
index 000000000000..26ac7bed195b
--- /dev/null
+++ b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s
@@ -0,0 +1,7 @@
+.balign 1024
+.type foo,@object
+.globl foo
+goo:
+foo:
+ .long 0
+ .size foo,4
diff --git a/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script
new file mode 100644
index 000000000000..a5807231acd6
--- /dev/null
+++ b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script
@@ -0,0 +1,3 @@
+SECTIONS {
+ goo = 0;
+};
diff --git a/test/ELF/Inputs/eh-frame-pcrel-overflow.s b/test/ELF/Inputs/eh-frame-pcrel-overflow.s
new file mode 100644
index 000000000000..7b3cff88b466
--- /dev/null
+++ b/test/ELF/Inputs/eh-frame-pcrel-overflow.s
@@ -0,0 +1,25 @@
+.text
+.global foo
+foo:
+ ret
+
+.section .eh_frame, "a"
+ .long 12 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x52 # Augmentation string: 'R','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x00 # DW_EH_PE_absptr
+
+ .byte 0xFF
+
+ .long 12 # Size
+ .long 0x14 # ID
+ .quad foo + 0x90000000
diff --git a/test/ELF/Inputs/exclude-libs.ll b/test/ELF/Inputs/exclude-libs.ll
new file mode 100644
index 000000000000..8bd947085f31
--- /dev/null
+++ b/test/ELF/Inputs/exclude-libs.ll
@@ -0,0 +1,3 @@
+@fn2 = global void()* null;
+
+target triple = "x86_64-unknown-linux"
diff --git a/test/ELF/Inputs/exclude-libs.s b/test/ELF/Inputs/exclude-libs.s
index 6d05c5e3aa91..eeacae6bccf2 100644
--- a/test/ELF/Inputs/exclude-libs.s
+++ b/test/ELF/Inputs/exclude-libs.s
@@ -1,3 +1,5 @@
.globl fn
fn:
nop
+
+.globl foo
diff --git a/test/ELF/Inputs/far-long-arm-abs.s b/test/ELF/Inputs/far-long-arm-abs.s
new file mode 100644
index 000000000000..10d9d0292eab
--- /dev/null
+++ b/test/ELF/Inputs/far-long-arm-abs.s
@@ -0,0 +1,13 @@
+.global far
+.type far,%function
+far = 0x201001c
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x2020014
+.global too_far2
+.type too_far2,%function
+too_far2 = 0x2020020
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x202002c
diff --git a/test/ELF/Inputs/gdb-index.s b/test/ELF/Inputs/gdb-index.s
index 907a66d350b0..794995c150f9 100644
--- a/test/ELF/Inputs/gdb-index.s
+++ b/test/ELF/Inputs/gdb-index.s
@@ -1,8 +1,8 @@
.text
.Ltext0:
-.globl main2
-.type main2, @function
-main2:
+.globl aaaaaaaaaaaaaaaa
+.type aaaaaaaaaaaaaaaa, @function
+aaaaaaaaaaaaaaaa:
nop
nop
.Letext0:
@@ -59,7 +59,7 @@ main2:
.long 0x33
.long 0x18
.byte 0x30
-.string "main2"
+.string "aaaaaaaaaaaaaaaa"
.long 0
.section .debug_gnu_pubtypes,"",@progbits
diff --git a/test/ELF/Inputs/hexagon.s b/test/ELF/Inputs/hexagon.s
new file mode 100644
index 000000000000..921a0c409b57
--- /dev/null
+++ b/test/ELF/Inputs/hexagon.s
@@ -0,0 +1,6 @@
+.global _start
+_start:
+ nop
+.global foo
+foo:
+ jumpr lr
diff --git a/test/ELF/Inputs/hidden-shared-err.s b/test/ELF/Inputs/hidden-shared-err.s
new file mode 100644
index 000000000000..ade79556db7b
--- /dev/null
+++ b/test/ELF/Inputs/hidden-shared-err.s
@@ -0,0 +1,2 @@
+.global foo
+foo:
diff --git a/test/ELF/Inputs/hidden-shared-err2.s b/test/ELF/Inputs/hidden-shared-err2.s
new file mode 100644
index 000000000000..aedd19d396fb
--- /dev/null
+++ b/test/ELF/Inputs/hidden-shared-err2.s
@@ -0,0 +1 @@
+.quad foo
diff --git a/test/ELF/Inputs/i386-pic-plt.s b/test/ELF/Inputs/i386-pic-plt.s
new file mode 100644
index 000000000000..a7a812194fa3
--- /dev/null
+++ b/test/ELF/Inputs/i386-pic-plt.s
@@ -0,0 +1,4 @@
+ .global foo
+ .type foo, @function
+foo:
+ nop
diff --git a/test/ELF/Inputs/icf-safe.s b/test/ELF/Inputs/icf-safe.s
new file mode 100644
index 000000000000..02393f3bbda5
--- /dev/null
+++ b/test/ELF/Inputs/icf-safe.s
@@ -0,0 +1,9 @@
+.section .text.non_addrsig1,"ax",@progbits
+.globl non_addrsig1
+non_addrsig1:
+ret
+
+.section .text.non_addrsig2,"ax",@progbits
+.globl non_addrsig2
+non_addrsig2:
+ret
diff --git a/test/ELF/Inputs/map-file2.s b/test/ELF/Inputs/map-file2.s
index d46b06f7345a..b830bbc41d2e 100644
--- a/test/ELF/Inputs/map-file2.s
+++ b/test/ELF/Inputs/map-file2.s
@@ -1,5 +1,7 @@
foo:
+.cfi_startproc
nop
+.cfi_endproc
.global bar
bar:
nop
diff --git a/test/ELF/Inputs/mips-64-got-load.s b/test/ELF/Inputs/mips-64-got-load.s
new file mode 100644
index 000000000000..dffc6fb335c9
--- /dev/null
+++ b/test/ELF/Inputs/mips-64-got-load.s
@@ -0,0 +1,8 @@
+ .text
+ .global foo1
+foo1:
+ ld $2, %got_disp(local1)($gp)
+
+ .bss
+local1:
+ .word 0
diff --git a/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s
new file mode 100644
index 000000000000..42bd32a1e73a
--- /dev/null
+++ b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s
@@ -0,0 +1,14 @@
+# Source file for mips-gp-dips-corrupt-ver.so
+#
+# % cat gpdisp.ver
+# LLD_1.0.0 { global: foo; };
+#
+# % as mips-gp-dips-corrupt-ver.s -o mips-gp-dips-corrupt-ver.o
+# % ld -shared -o mips-gp-dips-corrupt-ver.so \
+# --version-script gpdisp.ver mips-gp-dips-corrupt-ver.o
+
+ .global foo
+ .text
+foo:
+ lui $t0, %hi(_gp_disp)
+ addi $t0, $t0, %lo(_gp_disp)
diff --git a/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so
new file mode 100755
index 000000000000..289ffa538f0c
--- /dev/null
+++ b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so
Binary files differ
diff --git a/test/ELF/Inputs/mips-mgot-1.s b/test/ELF/Inputs/mips-mgot-1.s
new file mode 100644
index 000000000000..def6e5821154
--- /dev/null
+++ b/test/ELF/Inputs/mips-mgot-1.s
@@ -0,0 +1,10 @@
+ .text
+ .global foo1
+foo1:
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+ addiu $2, $2, %gottprel(tls1) # tls got entry
+
+ .section .tdata,"awT",%progbits
+ .global tls1
+tls1:
+ .word 0
diff --git a/test/ELF/Inputs/mips-mgot-2.s b/test/ELF/Inputs/mips-mgot-2.s
new file mode 100644
index 000000000000..4f6a92d36ffd
--- /dev/null
+++ b/test/ELF/Inputs/mips-mgot-2.s
@@ -0,0 +1,17 @@
+ .text
+ .global foo2
+foo2:
+ lw $2, %got(.data)($gp) # page entry
+ addi $2, $2, %lo(.data)
+ lw $2, %call16(foo0)($gp) # global entry
+ lw $2, %call16(foo2)($gp) # global entry
+ addiu $2, $2, %tlsgd(tls0) # tls gd entry
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+
+ .data
+ .space 0x20000
+
+ .section .tdata,"awT",%progbits
+ .global tls2
+tls2:
+ .word 0
diff --git a/test/ELF/Inputs/mips-micro-gp0-non-zero.o b/test/ELF/Inputs/mips-micro-gp0-non-zero.o
new file mode 100644
index 000000000000..abd67bcd262a
--- /dev/null
+++ b/test/ELF/Inputs/mips-micro-gp0-non-zero.o
Binary files differ
diff --git a/test/ELF/Inputs/mips-n32-rels.o b/test/ELF/Inputs/mips-n32-rels.o
deleted file mode 100644
index 88cbce699e6d..000000000000
--- a/test/ELF/Inputs/mips-n32-rels.o
+++ /dev/null
Binary files differ
diff --git a/test/ELF/Inputs/mips-n64-gp0-non-zero.o b/test/ELF/Inputs/mips-n64-gp0-non-zero.o
new file mode 100644
index 000000000000..43b930b9d9fd
--- /dev/null
+++ b/test/ELF/Inputs/mips-n64-gp0-non-zero.o
Binary files differ
diff --git a/test/ELF/Inputs/multiple-cu.s b/test/ELF/Inputs/multiple-cu.s
new file mode 100644
index 000000000000..ff29d36a7e0a
--- /dev/null
+++ b/test/ELF/Inputs/multiple-cu.s
@@ -0,0 +1,24 @@
+ .file 1 "test2.c"
+ .loc 1 2 0
+ jmp bar
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+ .long .debug_line # DW_AT_stmt_list
+.Lend0:
+ .section .debug_line,"",@progbits
diff --git a/test/ELF/Inputs/ppc64-func-global-entry.s b/test/ELF/Inputs/ppc64-func-global-entry.s
new file mode 100644
index 000000000000..5987db6b5c53
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func-global-entry.s
@@ -0,0 +1,35 @@
+ .text
+ .abiversion 2
+ .globl foo_external_diff # -- Begin function foo_external_diff
+ .p2align 4
+ .type foo_external_diff,@function
+foo_external_diff: # @foo_external_diff
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry foo_external_diff, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ addis 5, 2, .LC0@toc@ha
+ add 3, 4, 3
+ ld 5, .LC0@toc@l(5)
+ lwz 5, 0(5)
+ add 3, 3, 5
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_external_diff, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob2[TC],glob2
+ .type glob2,@object # @glob2
+ .data
+ .globl glob2
+ .p2align 2
+glob2:
+ .long 10 # 0xa
+ .size glob2, 4
diff --git a/test/ELF/Inputs/ppc64-func-local-entry.s b/test/ELF/Inputs/ppc64-func-local-entry.s
new file mode 100644
index 000000000000..fc0a72df762d
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func-local-entry.s
@@ -0,0 +1,16 @@
+ .text
+ .abiversion 2
+ .globl foo_external_same # -- Begin function foo_external_same
+ .p2align 4
+ .type foo_external_same,@function
+foo_external_same: # @foo_external_same
+.Lfunc_begin0:
+# %bb.0: # %entry
+ add 3, 4, 3
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_external_same, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
diff --git a/test/ELF/Inputs/ppc64-func.s b/test/ELF/Inputs/ppc64-func.s
new file mode 100644
index 000000000000..745faf870e6b
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func.s
@@ -0,0 +1,14 @@
+ .text
+ .abiversion 2
+ .globl foo_not_shared
+ .p2align 4
+ .type foo_not_shared,@function
+
+foo_not_shared:
+.Lfunc_begin0:
+ li 3, 55
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_not_shared, .Lfunc_end0-.Lfunc_begin0
diff --git a/test/ELF/Inputs/ppc64-tls.s b/test/ELF/Inputs/ppc64-tls.s
new file mode 100644
index 000000000000..11d1d1240962
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-tls.s
@@ -0,0 +1,20 @@
+ .text
+ .abiversion 2
+ .type a,@object # @a
+ .type b,@object # @a
+ .type c,@object # @a
+ .section .tdata,"awT",@progbits
+ .globl a
+a:
+ .long 10 # 0xa
+ .size a, 4
+
+ .globl b
+b:
+ .long 10 # 0xa
+ .size b, 4
+
+ .globl c
+c:
+ .long 10 # 0xa
+ .size c, 4
diff --git a/test/ELF/Inputs/print-icf.s b/test/ELF/Inputs/print-icf.s
new file mode 100644
index 000000000000..df9bcbc0989d
--- /dev/null
+++ b/test/ELF/Inputs/print-icf.s
@@ -0,0 +1,9 @@
+.section .text.f6, "ax"
+f6:
+ mov $60, %rax
+ mov $42, %rdi
+ syscall
+
+ .section .text.f7, "ax"
+f7:
+ mov $0, %rax
diff --git a/test/ELF/Inputs/protected-data-access.s b/test/ELF/Inputs/protected-data-access.s
new file mode 100644
index 000000000000..50a1c461fd84
--- /dev/null
+++ b/test/ELF/Inputs/protected-data-access.s
@@ -0,0 +1,7 @@
+ .section .rodata,"a"
+ .global foo
+ .protected foo
+ .type foo, @object
+ .size foo, 8
+foo:
+ .quad 42
diff --git a/test/ELF/Inputs/protected-function-access.s b/test/ELF/Inputs/protected-function-access.s
new file mode 100644
index 000000000000..4dfffe512956
--- /dev/null
+++ b/test/ELF/Inputs/protected-function-access.s
@@ -0,0 +1,5 @@
+ .global foo
+ .protected foo
+ .type foo, @function
+foo:
+ ret
diff --git a/test/ELF/Inputs/shared-ppc64.s b/test/ELF/Inputs/shared-ppc64.s
index b0117ac42963..0e1ecf7ce849 100644
--- a/test/ELF/Inputs/shared-ppc64.s
+++ b/test/ELF/Inputs/shared-ppc64.s
@@ -1,9 +1,14 @@
-.section ".opd","aw"
-.global bar
-bar:
-.quad .Lbar,.TOC.@tocbase,0
-.quad .Lbar,0,0
+ .text
+ .abiversion 2
+ .globl foo
+ .p2align 4
+ .type foo,@function
-.text
-.Lbar:
- blr
+foo:
+.Lfunc_begin0:
+ li 3, 55
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-.Lfunc_begin0
diff --git a/test/ELF/Inputs/shlib-undefined-ref.s b/test/ELF/Inputs/shlib-undefined-ref.s
new file mode 100644
index 000000000000..cfb7c60ebc01
--- /dev/null
+++ b/test/ELF/Inputs/shlib-undefined-ref.s
@@ -0,0 +1,4 @@
+.globl f
+f:
+ call should_not_be_exported@PLT
+ ret
diff --git a/test/ELF/Inputs/symbol-ordering-file-warnings1.s b/test/ELF/Inputs/symbol-ordering-file-warnings1.s
new file mode 100644
index 000000000000..9250a6d42705
--- /dev/null
+++ b/test/ELF/Inputs/symbol-ordering-file-warnings1.s
@@ -0,0 +1,19 @@
+# This is a "bad" (absolute) instance of the symbol
+multi = 1234
+
+.text
+.global shared
+.type shared, @function
+shared:
+ movq %rax, multi
+ ret
+
+.section .text.comdat,"axG",@progbits,comdat,comdat
+.weak comdat
+comdat:
+ ret
+
+.section .text.glob_or_wk,"ax",@progbits
+.global glob_or_wk
+glob_or_wk:
+ ret
diff --git a/test/ELF/Inputs/symbol-ordering-file-warnings2.s b/test/ELF/Inputs/symbol-ordering-file-warnings2.s
new file mode 100644
index 000000000000..4d914b240f17
--- /dev/null
+++ b/test/ELF/Inputs/symbol-ordering-file-warnings2.s
@@ -0,0 +1,6 @@
+.text
+.global missing
+missing:
+ callq undefined
+ # This is a "bad" (undefined) instance of the symbol
+ callq multi
diff --git a/test/ELF/Inputs/undef-bad-debug.s b/test/ELF/Inputs/undef-bad-debug.s
new file mode 100644
index 000000000000..e3e9f5edb9db
--- /dev/null
+++ b/test/ELF/Inputs/undef-bad-debug.s
@@ -0,0 +1,134 @@
+.section .text,"ax"
+sym:
+ .quad zed6
+sym2:
+ .quad zed7
+
+.section .debug_line,"",@progbits
+.Lunit:
+ .long .Lunit_end - .Lunit_start # unit length
+.Lunit_start:
+ .short 4 # version
+ .long .Lprologue_end - .Lprologue_start # prologue length
+.Lprologue_start:
+ .byte 1 # minimum instruction length
+ .byte 1 # maximum operatiosn per instruction
+ .byte 1 # default is_stmt
+ .byte -5 # line base
+ .byte 14 # line range
+ .byte 13 # opcode base
+ .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths
+ .asciz "dir" # include directories
+ .byte 0
+ .asciz "undef-bad-debug.s" # file names
+ .byte 1, 0, 0
+ .byte 0
+ .byte 0 # extraneous byte
+.Lprologue_end:
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad sym
+ .byte 3 # DW_LNS_advance_line
+ .byte 10
+ .byte 1 # DW_LNS_copy
+ .byte 2 # DW_LNS_advance_pc
+ .byte 8
+ .byte 0, 1, 1 # DW_LNE_end_sequence
+.Lunit_end:
+
+.Lunit2:
+ .long .Lunit2_end - .Lunit2_start # unit length
+.Lunit2_start:
+ .short 4 # version
+ .long .Lprologue2_end - .Lprologue2_start # prologue length
+.Lprologue2_start:
+ .byte 1 # minimum instruction length
+ .byte 1 # maximum operatiosn per instruction
+ .byte 1 # default is_stmt
+ .byte -5 # line base
+ .byte 14 # line range
+ .byte 13 # opcode base
+ .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths
+ .asciz "dir2" # include directories
+ .byte 0
+ .asciz "undef-bad-debug2.s" # file names
+ .byte 1, 0, 0
+ .byte 0
+.Lprologue2_end:
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad sym2
+ .byte 3 # DW_LNS_advance_line
+ .byte 10
+ .byte 1 # DW_LNS_copy
+ .byte 2 # DW_LNS_advance_pc
+ .byte 8
+ .byte 0, 1, 1 # DW_LNE_end_sequence
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad 0x0badbeef
+ .byte 3 # DW_LNS_advance_line
+ .byte 99
+ .byte 1 # DW_LNS_copy
+ .byte 99 # DW_LNS_advance_pc
+ .byte 119
+ # Missing end of sequence.
+.Lunit2_end:
+
+.section .debug_info,"",@progbits
+ .long .Lcu_end - .Lcu_start # Length of Unit
+.Lcu_start:
+ .short 4 # DWARF version number
+ .long .Lsection_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit
+ .long .Lunit # DW_AT_stmt_list
+ .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable
+ .long .Linfo_string # DW_AT_name
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # End Of Children Mark
+.Lcu_end:
+
+ .long .Lcu2_end - .Lcu2_start # Length of Unit
+.Lcu2_start:
+ .short 4 # DWARF version number
+ .long .Lsection_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit
+ .long .Lunit2 # DW_AT_stmt_list
+ .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable
+ .long .Linfo2_string # DW_AT_name
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # End Of Children Mark
+.Lcu2_end:
+
+.section .debug_abbrev,"",@progbits
+.Lsection_abbrev:
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string:
+ .asciz "sym"
+.Linfo2_string:
+ .asciz "sym2"
diff --git a/test/ELF/Inputs/undef-debug.s b/test/ELF/Inputs/undef-debug.s
index db8aaf16e6bd..46c1c92d2b1f 100644
--- a/test/ELF/Inputs/undef-debug.s
+++ b/test/ELF/Inputs/undef-debug.s
@@ -9,3 +9,24 @@
.section .text.2,"ax"
.loc 1 11
.quad zed5
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+ .long .debug_line # DW_AT_stmt_list
+.Lend0:
+ .section .debug_line,"",@progbits
diff --git a/test/ELF/Inputs/undef-shared2.s b/test/ELF/Inputs/undef-shared2.s
new file mode 100644
index 000000000000..8742073726e5
--- /dev/null
+++ b/test/ELF/Inputs/undef-shared2.s
@@ -0,0 +1,2 @@
+.data
+.quad foo
diff --git a/test/ELF/Inputs/versiondef.s b/test/ELF/Inputs/versiondef.s
new file mode 100644
index 000000000000..911cc146706f
--- /dev/null
+++ b/test/ELF/Inputs/versiondef.s
@@ -0,0 +1,9 @@
+.text
+.globl func_impl
+func_impl:
+ ret
+.globl func_impl2
+func_impl2:
+ ret
+.symver func_impl, func@@VER2
+.symver func_impl2, func@VER
diff --git a/test/ELF/Inputs/weak-and-strong-undef.s b/test/ELF/Inputs/weak-and-strong-undef.s
deleted file mode 100644
index a5e476d43160..000000000000
--- a/test/ELF/Inputs/weak-and-strong-undef.s
+++ /dev/null
@@ -1 +0,0 @@
- .weak foo
diff --git a/test/ELF/Inputs/x86-64-split-stack-main.s b/test/ELF/Inputs/x86-64-split-stack-main.s
new file mode 100644
index 000000000000..3be9facf51e9
--- /dev/null
+++ b/test/ELF/Inputs/x86-64-split-stack-main.s
@@ -0,0 +1,16 @@
+ .text
+
+ .global non_split
+ .type non_split,@function
+non_split:
+ retq
+ .size non_split,. - non_split
+
+ .global non_function_text_symbol
+non_function_text_symbol:
+ .byte 0x01
+ .type non_function_text_symbol,@STT_OBJECT
+ .size non_function_text_symbol, 1
+
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/test/ELF/Inputs/ztext-text-notext.s b/test/ELF/Inputs/ztext.s
index f66b3ee1e29b..f66b3ee1e29b 100644
--- a/test/ELF/Inputs/ztext-text-notext.s
+++ b/test/ELF/Inputs/ztext.s
diff --git a/test/ELF/aarch64-call26-thunk.s b/test/ELF/aarch64-call26-thunk.s
index 0fe99cec974d..067f6dbc2f7e 100644
--- a/test/ELF/aarch64-call26-thunk.s
+++ b/test/ELF/aarch64-call26-thunk.s
@@ -1,8 +1,8 @@
+// REQUIRES: aarch64
// 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: ld.lld %t %tabs -o %t2 2>&1
// RUN: llvm-objdump -d -triple=aarch64-pc-freebsd %t2 | FileCheck %s
-// REQUIRES: aarch64
.text
.globl _start
diff --git a/test/ELF/aarch64-condb-reloc.s b/test/ELF/aarch64-condb-reloc.s
index 23c16c2db898..8a7581480544 100644
--- a/test/ELF/aarch64-condb-reloc.s
+++ b/test/ELF/aarch64-condb-reloc.s
@@ -1,3 +1,4 @@
+# REQUIRES: aarch64
# 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
@@ -5,7 +6,6 @@
# 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
diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s
index ffecf2f8a283..32e1c76df771 100644
--- a/test/ELF/aarch64-copy.s
+++ b/test/ELF/aarch64-copy.s
@@ -1,7 +1,7 @@
// 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 -shared %t2.o -soname fixed-length-string.so -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
@@ -90,4 +90,4 @@ _start:
// RODATA: Contents of section .rodata:
// S(z) = 0x40014
-// RODATA-NEXT: 101c8 14000400
+// RODATA-NEXT: 102e0 14000400
diff --git a/test/ELF/aarch64-cortex-a53-843419-address.s b/test/ELF/aarch64-cortex-a53-843419-address.s
index e9f6ff4c38db..6c1f04d49fa1 100644
--- a/test/ELF/aarch64-cortex-a53-843419-address.s
+++ b/test/ELF/aarch64-cortex-a53-843419-address.s
@@ -4,7 +4,8 @@
// RUN: .text : { *(.text) *(.text.*) *(.newisd) } \
// RUN: .text2 : { *.(newos) } \
// RUN: .data : { *(.data) } }" > %t.script
-// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PRINT %s
// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s
// Test cases for Cortex-A53 Erratum 843419 that involve interactions
diff --git a/test/ELF/aarch64-cortex-a53-843419-cli.s b/test/ELF/aarch64-cortex-a53-843419-cli.s
index 30abc8f06d20..9c1d4858b3a7 100644
--- a/test/ELF/aarch64-cortex-a53-843419-cli.s
+++ b/test/ELF/aarch64-cortex-a53-843419-cli.s
@@ -1,6 +1,6 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-// RUN: not ld.lld %t -fix-cortex-a53-843419 -o %t2 2>&1 | FileCheck %s
+// RUN: not ld.lld %t -fix-cortex-a53-843419 -o /dev/null 2>&1 | FileCheck %s
// CHECK: --fix-cortex-a53-843419 is only supported on AArch64 targets.
.globl entry
diff --git a/test/ELF/aarch64-cortex-a53-843419-nopatch.s b/test/ELF/aarch64-cortex-a53-843419-nopatch.s
index 389bf4505735..4f34ea26da7f 100644
--- a/test/ELF/aarch64-cortex-a53-843419-nopatch.s
+++ b/test/ELF/aarch64-cortex-a53-843419-nopatch.s
@@ -1,6 +1,6 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
-// RUN: ld.lld -fix-cortex-a53-843419 -verbose -t %t.o -o %t2 | FileCheck %s
+// RUN: ld.lld -fix-cortex-a53-843419 -verbose -t %t.o -o /dev/null | FileCheck %s
// Test cases for Cortex-A53 Erratum 843419 that we don't expect to recognize
// as needing a patch as one or more of the conditions isn't satisfied.
// See ARM-EPM-048406 Cortex_A53_MPCore_Software_Developers_Errata_Notice.pdf
diff --git a/test/ELF/aarch64-cortex-a53-843419-recognize.s b/test/ELF/aarch64-cortex-a53-843419-recognize.s
index 3674dd2744da..174f18164bce 100644
--- a/test/ELF/aarch64-cortex-a53-843419-recognize.s
+++ b/test/ELF/aarch64-cortex-a53-843419-recognize.s
@@ -1,8 +1,8 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
-// RUN: ld.lld -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix CHECK-PRINT %s
+// RUN: ld.lld -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 | FileCheck -check-prefix CHECK-PRINT %s
// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s -check-prefixes=CHECK,CHECK-FIX
-// RUN: ld.lld -verbose %t.o -o %t3
+// RUN: ld.lld %t.o -o %t3
// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t3 | FileCheck %s -check-prefixes=CHECK,CHECK-NOFIX
// Test cases for Cortex-A53 Erratum 843419
// See ARM-EPM-048406 Cortex_A53_MPCore_Software_Developers_Errata_Notice.pdf
@@ -30,7 +30,7 @@
// CHECK: t3_ff8_ldr:
// CHECK-NEXT: 21ff8: e0 01 00 f0 adrp x0, #258048
// CHECK-NEXT: 21ffc: 21 00 40 f9 ldr x1, [x1]
-// CHECK-FIX: 22000: 03 b8 00 14 b #188428
+// CHECK-FIX: 22000: 03 c8 00 14 b #204812
// CHECK-NOFIX: 22000: 00 00 40 f9 ldr x0, [x0]
// CHECK-NEXT: 22004: c0 03 5f d6 ret
.section .text.01, "ax", %progbits
@@ -48,7 +48,7 @@ t3_ff8_ldr:
// CHECK: t3_ff8_ldrsimd:
// CHECK-NEXT: 23ff8: e0 01 00 b0 adrp x0, #249856
// CHECK-NEXT: 23ffc: 21 00 40 bd ldr s1, [x1]
-// CHECK-FIX: 24000: 05 b0 00 14 b #180244
+// CHECK-FIX: 24000: 05 c0 00 14 b #196628
// CHECK-NOFIX: 24000: 02 04 40 f9 ldr x2, [x0, #8]
// CHECK-NEXT: 24004: c0 03 5f d6 ret
.section .text.02, "ax", %progbits
@@ -66,7 +66,7 @@ t3_ff8_ldrsimd:
// CHECK: t3_ffc_ldrpost:
// CHECK-NEXT: 25ffc: c0 01 00 f0 adrp x0, #241664
// CHECK-NEXT: 26000: 21 84 40 bc ldr s1, [x1], #8
-// CHECK-FIX: 26004: 06 a8 00 14 b #172056
+// CHECK-FIX: 26004: 06 b8 00 14 b #188440
// CHECK-NOFIX: 26004: 03 08 40 f9 ldr x3, [x0, #16]
// CHECK-NEXT: 26008: c0 03 5f d6 ret
.section .text.03, "ax", %progbits
@@ -84,7 +84,7 @@ t3_ffc_ldrpost:
// CHECK: t3_ff8_strpre:
// CHECK-NEXT: 27ff8: c0 01 00 b0 adrp x0, #233472
// CHECK-NEXT: 27ffc: 21 8c 00 bc str s1, [x1, #8]!
-// CHECK-FIX: 28000: 09 a0 00 14 b #163876
+// CHECK-FIX: 28000: 09 b0 00 14 b #180260
// CHECK-NOFIX: 28000: 02 00 40 f9 ldr x2, [x0]
// CHECK-NEXT: 28004: c0 03 5f d6 ret
.section .text.04, "ax", %progbits
@@ -102,7 +102,7 @@ t3_ff8_strpre:
// CHECK: t3_ffc_str:
// CHECK-NEXT: 29ffc: bc 01 00 f0 adrp x28, #225280
// CHECK-NEXT: 2a000: 42 00 00 f9 str x2, [x2]
-// CHECK-FIX: 2a004: 0a 98 00 14 b #155688
+// CHECK-FIX: 2a004: 0a a8 00 14 b #172072
// CHECK-NOFIX: 2a004: 9c 07 00 f9 str x28, [x28, #8]
// CHECK-NEXT: 2a008: c0 03 5f d6 ret
.section .text.05, "ax", %progbits
@@ -120,7 +120,7 @@ t3_ffc_str:
// CHECK: t3_ffc_strsimd:
// CHECK-NEXT: 2bffc: bc 01 00 b0 adrp x28, #217088
// CHECK-NEXT: 2c000: 44 00 00 b9 str w4, [x2]
-// CHECK-FIX: 2c004: 0c 90 00 14 b #147504
+// CHECK-FIX: 2c004: 0c a0 00 14 b #163888
// CHECK-NOFIX: 2c004: 84 0b 00 f9 str x4, [x28, #16]
// CHECK-NEXT: 2c008: c0 03 5f d6 ret
.section .text.06, "ax", %progbits
@@ -138,7 +138,7 @@ t3_ffc_strsimd:
// CHECK: t3_ff8_ldrunpriv:
// CHECK-NEXT: 2dff8: 9d 01 00 f0 adrp x29, #208896
// CHECK-NEXT: 2dffc: 41 08 40 38 ldtrb w1, [x2]
-// CHECK-FIX: 2e000: 0f 88 00 14 b #139324
+// CHECK-FIX: 2e000: 0f 98 00 14 b #155708
// CHECK-NOFIX: 2e000: bd 03 40 f9 ldr x29, [x29]
// CHECK-NEXT: 2e004: c0 03 5f d6 ret
.section .text.07, "ax", %progbits
@@ -156,7 +156,7 @@ t3_ff8_ldrunpriv:
// CHECK: t3_ffc_ldur:
// CHECK-NEXT: 2fffc: 9d 01 00 b0 adrp x29, #200704
// CHECK-NEXT: 30000: 42 40 40 b8 ldur w2, [x2, #4]
-// CHECK-FIX: 30004: 10 80 00 14 b #131136
+// CHECK-FIX: 30004: 10 90 00 14 b #147520
// CHECK-NOFIX: 30004: bd 07 40 f9 ldr x29, [x29, #8]
// CHECK-NEXT: 30008: c0 03 5f d6 ret
.balign 4096
@@ -173,8 +173,8 @@ t3_ffc_ldur:
// CHECK: t3_ffc_sturh:
// CHECK-NEXT: 31ffc: 72 01 00 f0 adrp x18, #192512
// CHECK-NEXT: 32000: 43 40 00 78 sturh w3, [x2, #4]
-// CHECK-FIX: 32004: 12 78 00 14 b #122952
-// CHECK-NOFIX: 32004: 41 0a 40 f9 ldr x1, [x18, #16]
+// CHECK-FIX: 32004: 12 88 00 14 b #139336
+// CHECK-NOFIX: 32004: 41 0a 40 f9 ldr x1, [x18, #16]
// CHECK-NEXT: 32008: c0 03 5f d6 ret
.section .text.09, "ax", %progbits
.balign 4096
@@ -191,7 +191,7 @@ t3_ffc_sturh:
// CHECK: t3_ff8_literal:
// CHECK-NEXT: 33ff8: 72 01 00 b0 adrp x18, #184320
// CHECK-NEXT: 33ffc: e3 ff ff 58 ldr x3, #-4
-// CHECK-FIX: 34000: 15 70 00 14 b #114772
+// CHECK-FIX: 34000: 15 80 00 14 b #131156
// CHECK-NOFIX: 34000: 52 02 40 f9 ldr x18, [x18]
// CHECK-NEXT: 34004: c0 03 5f d6 ret
.section .text.10, "ax", %progbits
@@ -209,7 +209,7 @@ t3_ff8_literal:
// CHECK: t3_ffc_register:
// CHECK-NEXT: 35ffc: 4f 01 00 f0 adrp x15, #176128
// CHECK-NEXT: 36000: 43 68 61 f8 ldr x3, [x2, x1]
-// CHECK-FIX: 36004: 16 68 00 14 b #106584
+// CHECK-FIX: 36004: 16 78 00 14 b #122968
// CHECK-NOFIX: 36004: ea 05 40 f9 ldr x10, [x15, #8]
// CHECK-NEXT: 36008: c0 03 5f d6 ret
.section .text.11, "ax", %progbits
@@ -227,7 +227,7 @@ t3_ffc_register:
// CHECK: t3_ff8_stp:
// CHECK-NEXT: 37ff8: 50 01 00 b0 adrp x16, #167936
// CHECK-NEXT: 37ffc: 61 08 00 a9 stp x1, x2, [x3]
-// CHECK-FIX: 38000: 19 60 00 14 b #98404
+// CHECK-FIX: 38000: 19 70 00 14 b #114788
// CHECK-NOFIX: 38000: 0d 0a 40 f9 ldr x13, [x16, #16]
// CHECK-NEXT: 38004: c0 03 5f d6 ret
.section .text.12, "ax", %progbits
@@ -245,7 +245,7 @@ t3_ff8_stp:
// CHECK: t3_ffc_stnp:
// CHECK-NEXT: 39ffc: 27 01 00 f0 adrp x7, #159744
// CHECK-NEXT: 3a000: 61 08 00 a8 stnp x1, x2, [x3]
-// CHECK-FIX: 3a004: 1a 58 00 14 b #90216
+// CHECK-FIX: 3a004: 1a 68 00 14 b #106600
// CHECK-NOFIX: 3a004: e9 00 40 f9 ldr x9, [x7]
// CHECK-NEXT: 3a008: c0 03 5f d6 ret
.section .text.13, "ax", %progbits
@@ -262,8 +262,8 @@ t3_ffc_stnp:
// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3BFFC in unpatched output.
// CHECK: t3_ffc_st1singlepost:
// CHECK-NEXT: 3bffc: 37 01 00 b0 adrp x23, #151552
-// CHECK-NEXT: 3c000: 20 70 82 4c st1 { v0.16b }, [x1], x2
-// CHECK-FIX: 3c004: 1c 50 00 14 b #82032
+// CHECK-NEXT: 3c000: 20 04 82 0d st1 { v0.b }[1], [x1], x2
+// CHECK-FIX: 3c004: 1c 60 00 14 b #98416
// CHECK-NOFIX: 3c004: f6 06 40 f9 ldr x22, [x23, #8]
// CHECK-NEXT: 3c008: c0 03 5f d6 ret
.section .text.14, "ax", %progbits
@@ -273,7 +273,7 @@ t3_ffc_stnp:
.space 4096 - 4
t3_ffc_st1singlepost:
adrp x23, dat2
- st1 { v0.16b }, [x1], x2
+ st1 { v0.b }[1], [x1], x2
ldr x22, [x23, :lo12:dat2]
ret
@@ -281,7 +281,7 @@ t3_ffc_st1singlepost:
// CHECK: t3_ff8_st1multiple:
// CHECK-NEXT: 3dff8: 17 01 00 f0 adrp x23, #143360
// CHECK-NEXT: 3dffc: 20 a0 00 4c st1 { v0.16b, v1.16b }, [x1]
-// CHECK-FIX: 3e000: 1f 48 00 14 b #73852
+// CHECK-FIX: 3e000: 1f 58 00 14 b #90236
// CHECK-NOFIX: 3e000: f8 0a 40 f9 ldr x24, [x23, #16]
// CHECK-NEXT: 3e004: c0 03 5f d6 ret
.section .text.15, "ax", %progbits
@@ -300,7 +300,7 @@ t3_ff8_st1multiple:
// CHECK-NEXT: 3fff8: 00 01 00 b0 adrp x0, #135168
// CHECK-NEXT: 3fffc: 21 00 40 f9 ldr x1, [x1]
// CHECK-NEXT: 40000: 42 00 00 8b add x2, x2, x0
-// CHECK-FIX: 40004: 20 40 00 14 b #65664
+// CHECK-FIX: 40004: 20 50 00 14 b #82048
// CHECK-NOFIX: 40004: 02 00 40 f9 ldr x2, [x0]
// CHECK-NEXT: 40008: c0 03 5f d6 ret
.section .text.16, "ax", %progbits
@@ -320,7 +320,7 @@ t4_ff8_ldr:
// CHECK-NEXT: 41ffc: fc 00 00 f0 adrp x28, #126976
// CHECK-NEXT: 42000: 42 00 00 f9 str x2, [x2]
// CHECK-NEXT: 42004: 20 00 02 cb sub x0, x1, x2
-// CHECK-FIX: 42008: 21 38 00 14 b #57476
+// CHECK-FIX: 42008: 21 48 00 14 b #73860
// CHECK-NOFIX: 42008: 9b 07 00 f9 str x27, [x28, #8]
// CHECK-NEXT: 4200c: c0 03 5f d6 ret
.section .text.17, "ax", %progbits
@@ -340,7 +340,7 @@ t4_ffc_str:
// CHECK-NEXT: 43ff8: f0 00 00 b0 adrp x16, #118784
// CHECK-NEXT: 43ffc: 61 08 00 a9 stp x1, x2, [x3]
// CHECK-NEXT: 44000: 03 7e 10 9b mul x3, x16, x16
-// CHECK-FIX: 44004: 24 30 00 14 b #49296
+// CHECK-FIX: 44004: 24 40 00 14 b #65680
// CHECK-NOFIX: 44004: 0e 0a 40 f9 ldr x14, [x16, #16]
// CHECK-NEXT: 44008: c0 03 5f d6 ret
.section .text.18, "ax", %progbits
@@ -360,7 +360,7 @@ t4_ff8_stp:
// CHECK-NEXT: 45ff8: d0 00 00 f0 adrp x16, #110592
// CHECK-NEXT: 45ffc: 61 08 81 a9 stp x1, x2, [x3, #16]!
// CHECK-NEXT: 46000: 03 7e 10 9b mul x3, x16, x16
-// CHECK-FIX: 46004: 26 28 00 14 b #41112
+// CHECK-FIX: 46004: 26 38 00 14 b #57496
// CHECK-NOFIX: 46004: 0e 06 40 f9 ldr x14, [x16, #8]
// CHECK-NEXT: 46008: c0 03 5f d6 ret
.section .text.19, "ax", %progbits
@@ -380,7 +380,7 @@ t4_ff8_stppre:
// CHECK-NEXT: 47ff8: d0 00 00 b0 adrp x16, #102400
// CHECK-NEXT: 47ffc: 61 08 81 a8 stp x1, x2, [x3], #16
// CHECK-NEXT: 48000: 03 7e 10 9b mul x3, x16, x16
-// CHECK-FIX: 48004: 28 20 00 14 b #32928
+// CHECK-FIX: 48004: 28 30 00 14 b #49312
// CHECK-NOFIX: 48004: 0e 06 40 f9 ldr x14, [x16, #8]
// CHECK-NEXT: 48008: c0 03 5f d6 ret
.section .text.20, "ax", %progbits
@@ -400,7 +400,7 @@ t4_ff8_stppost:
// CHECK-NEXT: 49ffc: b0 00 00 f0 adrp x16, #94208
// CHECK-NEXT: 4a000: 61 08 00 ad stp q1, q2, [x3]
// CHECK-NEXT: 4a004: 03 7e 10 9b mul x3, x16, x16
-// CHECK-FIX: 4a008: 29 18 00 14 b #24740
+// CHECK-FIX: 4a008: 29 28 00 14 b #41124
// CHECK-NOFIX: 4a008: 0e 06 40 f9 ldr x14, [x16, #8]
// CHECK-NEXT: 4a00c: c0 03 5f d6 ret
.section .text.21, "ax", %progbits
@@ -420,7 +420,7 @@ t4_ffc_stpsimd:
// CHECK-NEXT: 4bffc: a7 00 00 b0 adrp x7, #86016
// CHECK-NEXT: 4c000: 61 08 00 a8 stnp x1, x2, [x3]
// CHECK-NEXT: 4c004: 1f 20 03 d5 nop
-// CHECK-FIX: 4c008: 2b 10 00 14 b #16556
+// CHECK-FIX: 4c008: 2b 20 00 14 b #32940
// CHECK-NOFIX: 4c008: ea 00 40 f9 ldr x10, [x7]
// CHECK-NEXT: 4c00c: c0 03 5f d6 ret
.section .text.22, "ax", %progbits
@@ -438,9 +438,9 @@ t4_ffc_stnp:
// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4DFFC in unpatched output.
// CHECK: t4_ffc_st1:
// CHECK-NEXT: 4dffc: 98 00 00 f0 adrp x24, #77824
-// CHECK-NEXT: 4e000: 20 70 00 4c st1 { v0.16b }, [x1]
+// CHECK-NEXT: 4e000: 20 80 00 4d st1 { v0.s }[2], [x1]
// CHECK-NEXT: 4e004: f6 06 40 f9 ldr x22, [x23, #8]
-// CHECK-FIX: 4e008: 2d 08 00 14 b #8372
+// CHECK-FIX: 4e008: 2d 18 00 14 b #24756
// CHECK-NOFIX: 4e008: 18 ff 3f f9 str x24, [x24, #32760]
// CHECK-NEXT: 4e00c: c0 03 5f d6 ret
.section .text.23, "ax", %progbits
@@ -450,7 +450,7 @@ t4_ffc_stnp:
.space 4096 - 4
t4_ffc_st1:
adrp x24, dat2
- st1 { v0.16b }, [x1]
+ st1 { v0.s }[2], [x1]
ldr x22, [x23, :got_lo12:dat2]
str x24, [x24, #32760]
ret
@@ -459,7 +459,7 @@ t4_ffc_st1:
// CHECK: t3_ff8_ldr_once:
// CHECK-NEXT: 4fff8: 80 00 00 b0 adrp x0, #69632
// CHECK-NEXT: 4fffc: 20 70 82 4c st1 { v0.16b }, [x1], x2
-// CHECK-FIX: 50000: 31 00 00 14 b #196
+// CHECK-FIX: 50000: 31 10 00 14 b #16580
// CHECK-NOFIX: 50000: 01 08 40 f9 ldr x1, [x0, #16]
// CHECK-NEXT: 50004: 02 08 40 f9 ldr x2, [x0, #16]
// CHECK-NEXT: 50008: c0 03 5f d6 ret
@@ -475,6 +475,46 @@ t3_ff8_ldr_once:
ldr x2, [x0, #16]
ret
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 51FF8 in unpatched output.
+// CHECK: t3_ff8_ldxr:
+// CHECK-NEXT: 51ff8: 60 00 00 f0 adrp x0, #61440
+// CHECK-NEXT: 51ffc: 03 7c 5f c8 ldxr x3, [x0]
+// CHECK-FIX: 52000: 33 08 00 14 b #8396
+// CHECK-NOFIX: 52000: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK: 52004: 02 08 40 f9 ldr x2, [x0, #16]
+// CHECK-NEXT: 52008: c0 03 5f d6 ret
+ .section .text.25, "ax", %progbits
+ .balign 4096
+ .globl t3_ff8_ldxr
+ .type t3_ff8_ldxr, %function
+ .space 4096 - 8
+t3_ff8_ldxr:
+ adrp x0, dat3
+ ldxr x3, [x0]
+ ldr x1, [x0, #16]
+ ldr x2, [x0, #16]
+ ret
+
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 53FF8 in unpatched output.
+// CHECK: t3_ff8_stxr:
+// CHECK-NEXT: 53ff8: 60 00 00 b0 adrp x0, #53248
+// CHECK-NEXT: 53ffc: 03 7c 04 c8 stxr w4, x3, [x0]
+// CHECK-FIX: 54000: 35 00 00 14 b #212
+// CHECK-NOFIX: 54000: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK: 54004: 02 08 40 f9 ldr x2, [x0, #16]
+// CHECK-NEXT: 54008: c0 03 5f d6 ret
+ .section .text.26, "ax", %progbits
+ .balign 4096
+ .globl t3_ff8_stxr
+ .type t3_ff8_stxr, %function
+ .space 4096 - 8
+t3_ff8_stxr:
+ adrp x0, dat3
+ stxr w4, x3, [x0]
+ ldr x1, [x0, #16]
+ ldr x2, [x0, #16]
+ ret
+
.text
.globl _start
.type _start, %function
@@ -482,78 +522,83 @@ _start:
ret
// CHECK-FIX: __CortexA53843419_22000:
-// CHECK-FIX-NEXT: 5000c: 00 00 40 f9 ldr x0, [x0]
-// CHECK-FIX-NEXT: 50010: fd 47 ff 17 b #-188428
+// CHECK-FIX-NEXT: 5400c: 00 00 40 f9 ldr x0, [x0]
+// CHECK-FIX-NEXT: 54010: fd 37 ff 17 b #-204812
// CHECK-FIX: __CortexA53843419_24000:
-// CHECK-FIX-NEXT: 50014: 02 04 40 f9 ldr x2, [x0, #8]
-// CHECK-FIX-NEXT: 50018: fb 4f ff 17 b #-180244
+// CHECK-FIX-NEXT: 54014: 02 04 40 f9 ldr x2, [x0, #8]
+// CHECK-FIX-NEXT: 54018: fb 3f ff 17 b #-196628
// CHECK-FIX: __CortexA53843419_26004:
-// CHECK-FIX-NEXT: 5001c: 03 08 40 f9 ldr x3, [x0, #16]
-// CHECK-FIX-NEXT: 50020: fa 57 ff 17 b #-172056
+// CHECK-FIX-NEXT: 5401c: 03 08 40 f9 ldr x3, [x0, #16]
+// CHECK-FIX-NEXT: 54020: fa 47 ff 17 b #-188440
// CHECK-FIX: __CortexA53843419_28000:
-// CHECK-FIX-NEXT: 50024: 02 00 40 f9 ldr x2, [x0]
-// CHECK-FIX-NEXT: 50028: f7 5f ff 17 b #-163876
+// CHECK-FIX-NEXT: 54024: 02 00 40 f9 ldr x2, [x0]
+// CHECK-FIX-NEXT: 54028: f7 4f ff 17 b #-180260
// CHECK-FIX: __CortexA53843419_2A004:
-// CHECK-FIX-NEXT: 5002c: 9c 07 00 f9 str x28, [x28, #8]
-// CHECK-FIX-NEXT: 50030: f6 67 ff 17 b #-155688
+// CHECK-FIX-NEXT: 5402c: 9c 07 00 f9 str x28, [x28, #8]
+// CHECK-FIX-NEXT: 54030: f6 57 ff 17 b #-172072
// CHECK-FIX: __CortexA53843419_2C004:
-// CHECK-FIX-NEXT: 50034: 84 0b 00 f9 str x4, [x28, #16]
-// CHECK-FIX-NEXT: 50038: f4 6f ff 17 b #-147504
+// CHECK-FIX-NEXT: 54034: 84 0b 00 f9 str x4, [x28, #16]
+// CHECK-FIX-NEXT: 54038: f4 5f ff 17 b #-163888
// CHECK-FIX: __CortexA53843419_2E000:
-// CHECK-FIX-NEXT: 5003c: bd 03 40 f9 ldr x29, [x29]
-// CHECK-FIX-NEXT: 50040: f1 77 ff 17 b #-139324
+// CHECK-FIX-NEXT: 5403c: bd 03 40 f9 ldr x29, [x29]
+// CHECK-FIX-NEXT: 54040: f1 67 ff 17 b #-155708
// CHECK-FIX: __CortexA53843419_30004:
-// CHECK-FIX-NEXT: 50044: bd 07 40 f9 ldr x29, [x29, #8]
-// CHECK-FIX-NEXT: 50048: f0 7f ff 17 b #-131136
+// CHECK-FIX-NEXT: 54044: bd 07 40 f9 ldr x29, [x29, #8]
+// CHECK-FIX-NEXT: 54048: f0 6f ff 17 b #-147520
// CHECK-FIX: __CortexA53843419_32004:
-// CHECK-FIX-NEXT: 5004c: 41 0a 40 f9 ldr x1, [x18, #16]
-// CHECK-FIX-NEXT: 50050: ee 87 ff 17 b #-122952
+// CHECK-FIX-NEXT: 5404c: 41 0a 40 f9 ldr x1, [x18, #16]
+// CHECK-FIX-NEXT: 54050: ee 77 ff 17 b #-139336
// CHECK-FIX: __CortexA53843419_34000:
-// CHECK-FIX-NEXT: 50054: 52 02 40 f9 ldr x18, [x18]
-// CHECK-FIX-NEXT: 50058: eb 8f ff 17 b #-114772
+// CHECK-FIX-NEXT: 54054: 52 02 40 f9 ldr x18, [x18]
+// CHECK-FIX-NEXT: 54058: eb 7f ff 17 b #-131156
// CHECK-FIX: __CortexA53843419_36004:
-// CHECK-FIX-NEXT: 5005c: ea 05 40 f9 ldr x10, [x15, #8]
-// CHECK-FIX-NEXT: 50060: ea 97 ff 17 b #-106584
+// CHECK-FIX-NEXT: 5405c: ea 05 40 f9 ldr x10, [x15, #8]
+// CHECK-FIX-NEXT: 54060: ea 87 ff 17 b #-122968
// CHECK-FIX: __CortexA53843419_38000:
-// CHECK-FIX-NEXT: 50064: 0d 0a 40 f9 ldr x13, [x16, #16]
-// CHECK-FIX-NEXT: 50068: e7 9f ff 17 b #-98404
+// CHECK-FIX-NEXT: 54064: 0d 0a 40 f9 ldr x13, [x16, #16]
+// CHECK-FIX-NEXT: 54068: e7 8f ff 17 b #-114788
// CHECK-FIX: __CortexA53843419_3A004:
-// CHECK-FIX-NEXT: 5006c: e9 00 40 f9 ldr x9, [x7]
-// CHECK-FIX-NEXT: 50070: e6 a7 ff 17 b #-90216
+// CHECK-FIX-NEXT: 5406c: e9 00 40 f9 ldr x9, [x7]
+// CHECK-FIX-NEXT: 54070: e6 97 ff 17 b #-106600
// CHECK-FIX: __CortexA53843419_3C004:
-// CHECK-FIX-NEXT: 50074: f6 06 40 f9 ldr x22, [x23, #8]
-// CHECK-FIX-NEXT: 50078: e4 af ff 17 b #-82032
+// CHECK-FIX-NEXT: 54074: f6 06 40 f9 ldr x22, [x23, #8]
+// CHECK-FIX-NEXT: 54078: e4 9f ff 17 b #-98416
// CHECK-FIX: __CortexA53843419_3E000:
-// CHECK-FIX-NEXT: 5007c: f8 0a 40 f9 ldr x24, [x23, #16]
-// CHECK-FIX-NEXT: 50080: e1 b7 ff 17 b #-73852
+// CHECK-FIX-NEXT: 5407c: f8 0a 40 f9 ldr x24, [x23, #16]
+// CHECK-FIX-NEXT: 54080: e1 a7 ff 17 b #-90236
// CHECK-FIX: __CortexA53843419_40004:
-// CHECK-FIX-NEXT: 50084: 02 00 40 f9 ldr x2, [x0]
-// CHECK-FIX-NEXT: 50088: e0 bf ff 17 b #-65664
+// CHECK-FIX-NEXT: 54084: 02 00 40 f9 ldr x2, [x0]
+// CHECK-FIX-NEXT: 54088: e0 af ff 17 b #-82048
// CHECK-FIX: __CortexA53843419_42008:
-// CHECK-FIX-NEXT: 5008c: 9b 07 00 f9 str x27, [x28, #8]
-// CHECK-FIX-NEXT: 50090: df c7 ff 17 b #-57476
+// CHECK-FIX-NEXT: 5408c: 9b 07 00 f9 str x27, [x28, #8]
+// CHECK-FIX-NEXT: 54090: df b7 ff 17 b #-73860
// CHECK-FIX: __CortexA53843419_44004:
-// CHECK-FIX-NEXT: 50094: 0e 0a 40 f9 ldr x14, [x16, #16]
-// CHECK-FIX-NEXT: 50098: dc cf ff 17 b #-49296
+// CHECK-FIX-NEXT: 54094: 0e 0a 40 f9 ldr x14, [x16, #16]
+// CHECK-FIX-NEXT: 54098: dc bf ff 17 b #-65680
// CHECK-FIX: __CortexA53843419_46004:
-// CHECK-FIX-NEXT: 5009c: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-FIX-NEXT: 500a0: da d7 ff 17 b #-41112
+// CHECK-FIX-NEXT: 5409c: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 540a0: da c7 ff 17 b #-57496
// CHECK-FIX: __CortexA53843419_48004:
-// CHECK-FIX-NEXT: 500a4: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-FIX-NEXT: 500a8: d8 df ff 17 b #-32928
+// CHECK-FIX-NEXT: 540a4: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 540a8: d8 cf ff 17 b #-49312
// CHECK-FIX: __CortexA53843419_4A008:
-// CHECK-FIX-NEXT: 500ac: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-FIX-NEXT: 500b0: d7 e7 ff 17 b #-24740
+// CHECK-FIX-NEXT: 540ac: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 540b0: d7 d7 ff 17 b #-41124
// CHECK-FIX: __CortexA53843419_4C008:
-// CHECK-FIX-NEXT: 500b4: ea 00 40 f9 ldr x10, [x7]
-// CHECK-FIX-NEXT: 500b8: d5 ef ff 17 b #-16556
+// CHECK-FIX-NEXT: 540b4: ea 00 40 f9 ldr x10, [x7]
+// CHECK-FIX-NEXT: 540b8: d5 df ff 17 b #-32940
// CHECK-FIX: __CortexA53843419_4E008:
-// CHECK-FIX-NEXT: 500bc: 18 ff 3f f9 str x24, [x24, #32760]
-// CHECK-FIX-NEXT: 500c0: d3 f7 ff 17 b #-8372
+// CHECK-FIX-NEXT: 540bc: 18 ff 3f f9 str x24, [x24, #32760]
+// CHECK-FIX-NEXT: 540c0: d3 e7 ff 17 b #-24756
// CHECK-FIX: __CortexA53843419_50000:
-// CHECK-FIX-NEXT: 500c4: 01 08 40 f9 ldr x1, [x0, #16]
-// CHECK-FIX-NEXT: 500c8: cf ff ff 17 b #-196
-
+// CHECK-FIX-NEXT: 540c4: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 540c8: cf ef ff 17 b #-16580
+// CHECK-FIX: __CortexA53843419_52000:
+// CHECK-FIX-NEXT: 540cc: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 540d0: cd f7 ff 17 b #-8396
+// CHECK-FIX: __CortexA53843419_54000:
+// CHECK-FIX-NEXT: 540d4: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 540d8: cb ff ff 17 b #-212
.data
.globl dat
.globl dat2
diff --git a/test/ELF/aarch64-cortex-a53-843419-thunk.s b/test/ELF/aarch64-cortex-a53-843419-thunk.s
index 4568095a2fa7..c802f3f605f1 100644
--- a/test/ELF/aarch64-cortex-a53-843419-thunk.s
+++ b/test/ELF/aarch64-cortex-a53-843419-thunk.s
@@ -3,7 +3,8 @@
// RUN: echo "SECTIONS { \
// RUN: .text1 0x10000 : { *(.text.01) *(.text.02) *(.text.03) } \
// RUN: .text2 0x8010000 : { *(.text.04) } } " > %t.script
-// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PRINT %s
// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s
// %t2 is 128 Megabytes, so delete it early.
diff --git a/test/ELF/aarch64-data-relocs.s b/test/ELF/aarch64-data-relocs.s
index 19e11bc3925c..d32871543bf6 100644
--- a/test/ELF/aarch64-data-relocs.s
+++ b/test/ELF/aarch64-data-relocs.s
@@ -1,8 +1,8 @@
+// REQUIRES: aarch64
// 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:
diff --git a/test/ELF/aarch64-fpic-abs16.s b/test/ELF/aarch64-fpic-abs16.s
index 2b14b11c75db..c180939b7cac 100644
--- a/test/ELF/aarch64-fpic-abs16.s
+++ b/test/ELF/aarch64-fpic-abs16.s
@@ -1,7 +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
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_ABS16 cannot be used against symbol foo; recompile with -fPIC
// CHECK-NEXT: >>> defined in {{.*}}.o
// CHECK-NEXT: >>> referenced by {{.*}}.o:(.data+0x0)
diff --git a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s
index 9e13fd18af46..fc58e06b3db3 100644
--- a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s
+++ b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-adr_prel_lo21.s b/test/ELF/aarch64-fpic-adr_prel_lo21.s
index c1e6bc6359bd..4b6f43f1f226 100644
--- a/test/ELF/aarch64-fpic-adr_prel_lo21.s
+++ b/test/ELF/aarch64-fpic-adr_prel_lo21.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_ADR_PREL_LO21 against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_ADR_PREL_LO21 cannot be used against symbol dat; recompile with -fPIC
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s
index e27867b85242..651a32e56868 100644
--- a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s
+++ b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol dat; recompile with -fPIC
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s
index 02b75a5bfcde..b68b9f23e4ca 100644
--- a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s
+++ b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s
index 45e4f2032c19..1d5b9439f0f4 100644
--- a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s
+++ b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s
index 16e7df1bc4a1..a3f8243a080c 100644
--- a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s
+++ b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s
@@ -1,7 +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: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against symbol: dat
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/aarch64-fpic-prel16.s b/test/ELF/aarch64-fpic-prel16.s
index 1faef9f866e0..1de7f6f63370 100644
--- a/test/ELF/aarch64-fpic-prel16.s
+++ b/test/ELF/aarch64-fpic-prel16.s
@@ -1,7 +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: R_AARCH64_PREL16 cannot be used against shared object; recompile with -fPIC
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: R_AARCH64_PREL16 cannot be used against symbol foo; recompile with -fPIC
// CHECK: >>> defined in {{.*}}
// CHECK: >>> referenced by {{.*}}:(.data+0x0)
diff --git a/test/ELF/aarch64-fpic-prel32.s b/test/ELF/aarch64-fpic-prel32.s
index b797dca2f2c4..0988b26a2b91 100644
--- a/test/ELF/aarch64-fpic-prel32.s
+++ b/test/ELF/aarch64-fpic-prel32.s
@@ -1,7 +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
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL32 cannot be used against symbol foo; recompile with -fPIC
// CHECK: >>> defined in {{.*}}
// CHECK: >>> referenced by {{.*}}:(.data+0x0)
diff --git a/test/ELF/aarch64-fpic-prel64.s b/test/ELF/aarch64-fpic-prel64.s
index 4c67837eac78..653f54220334 100644
--- a/test/ELF/aarch64-fpic-prel64.s
+++ b/test/ELF/aarch64-fpic-prel64.s
@@ -1,7 +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
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL64 cannot be used against symbol foo; recompile with -fPIC
// CHECK: >>> defined in {{.*}}
// CHECK: >>> referenced by {{.*}}:(.data+0x0)
diff --git a/test/ELF/aarch64-gnu-ifunc-nosym.s b/test/ELF/aarch64-gnu-ifunc-nosym.s
index bb3a0b8b5116..aa0124aa3fa2 100644
--- a/test/ELF/aarch64-gnu-ifunc-nosym.s
+++ b/test/ELF/aarch64-gnu-ifunc-nosym.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// 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.
diff --git a/test/ELF/aarch64-gnu-ifunc-plt.s b/test/ELF/aarch64-gnu-ifunc-plt.s
index 5138675676d3..ca30316c7afe 100644
--- a/test/ELF/aarch64-gnu-ifunc-plt.s
+++ b/test/ELF/aarch64-gnu-ifunc-plt.s
@@ -1,3 +1,4 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %S/Inputs/shared2.s -o %t1.o
// RUN: ld.lld %t1.o --shared -o %t.so
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
@@ -5,7 +6,6 @@
// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
-// REQUIRES: aarch64
// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
// CHECK: Relocations [
diff --git a/test/ELF/aarch64-gnu-ifunc.s b/test/ELF/aarch64-gnu-ifunc.s
index 4e0dc328025d..b3c1571b7604 100644
--- a/test/ELF/aarch64-gnu-ifunc.s
+++ b/test/ELF/aarch64-gnu-ifunc.s
@@ -1,8 +1,8 @@
+// REQUIRES: aarch64
// 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 {
diff --git a/test/ELF/aarch64-hi21-error.s b/test/ELF/aarch64-hi21-error.s
index 9e2b283ea118..07f9e04953b0 100644
--- a/test/ELF/aarch64-hi21-error.s
+++ b/test/ELF/aarch64-hi21-error.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// 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
+// RUN: not ld.lld %tabs %t -o /dev/null 2>&1 | FileCheck %s
.globl _start
_start:
diff --git a/test/ELF/aarch64-jump26-thunk.s b/test/ELF/aarch64-jump26-thunk.s
index 088ab3a9e1a5..13c084a0c78e 100644
--- a/test/ELF/aarch64-jump26-thunk.s
+++ b/test/ELF/aarch64-jump26-thunk.s
@@ -1,8 +1,8 @@
+// REQUIRES: aarch64
// 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: ld.lld %t %tabs -o %t2 2>&1
// RUN: llvm-objdump -d -triple=aarch64-pc-freebsd %t2 | FileCheck %s
-// REQUIRES: aarch64
.text
.globl _start
diff --git a/test/ELF/aarch64-ldprel-lo19-invalid.s b/test/ELF/aarch64-ldprel-lo19-invalid.s
index 04df32e05904..cf38b2c84fd0 100644
--- a/test/ELF/aarch64-ldprel-lo19-invalid.s
+++ b/test/ELF/aarch64-ldprel-lo19-invalid.s
@@ -1,7 +1,7 @@
# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
-# RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: relocation R_AARCH64_LD_PREL_LO19 out of range: 2065536 is not in [-1048576, 1048575]
diff --git a/test/ELF/aarch64-lo12-alignment.s b/test/ELF/aarch64-lo12-alignment.s
index 2b30022658e6..7edecd4494f5 100644
--- a/test/ELF/aarch64-lo12-alignment.s
+++ b/test/ELF/aarch64-lo12-alignment.s
@@ -1,6 +1,6 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t
-// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
// Test derived from a typical ODR violation where a global is declared
// extern int but defined as a half or byte sized type.
diff --git a/test/ELF/aarch64-lo21-error.s b/test/ELF/aarch64-lo21-error.s
index 055f8948f6a3..c1fb8a6fa2c2 100644
--- a/test/ELF/aarch64-lo21-error.s
+++ b/test/ELF/aarch64-lo21-error.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// 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
+// RUN: not ld.lld %tabs %t -o /dev/null 2>&1 | FileCheck %s
.globl _start
_start:
diff --git a/test/ELF/aarch64-load-alignment.s b/test/ELF/aarch64-load-alignment.s
index 7b1129b7afa5..175f1e6dad74 100644
--- a/test/ELF/aarch64-load-alignment.s
+++ b/test/ELF/aarch64-load-alignment.s
@@ -1,7 +1,7 @@
# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
-# RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: improper alignment for relocation R_AARCH64_LD_PREL_LO19: 0x10005 is not aligned to 4 bytes
diff --git a/test/ELF/aarch64-relocs.s b/test/ELF/aarch64-relocs.s
index 9d02bd599b25..79caabcb6bb5 100644
--- a/test/ELF/aarch64-relocs.s
+++ b/test/ELF/aarch64-relocs.s
@@ -1,8 +1,8 @@
+# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/uabs_label.s -o %t2.o
# RUN: ld.lld %t %t2.o -o %t2
# RUN: llvm-objdump -d %t2 | FileCheck %s
-# REQUIRES: aarch64
.section .R_AARCH64_ADR_PREL_LO21,"ax",@progbits
.globl _start
diff --git a/test/ELF/aarch64-thunk-pi.s b/test/ELF/aarch64-thunk-pi.s
index 91e2b7f0f3cd..d5d956c669b5 100644
--- a/test/ELF/aarch64-thunk-pi.s
+++ b/test/ELF/aarch64-thunk-pi.s
@@ -1,3 +1,4 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
// RUN: echo "SECTIONS { \
// RUN: .text_low : { *(.text_low) } \
@@ -5,7 +6,6 @@
// RUN: } " > %t.script
// RUN: ld.lld --script %t.script --shared %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=aarch64-linux-gnu %t2 | FileCheck %s
-// REQUIRES: aarch64
// Check that Position Independent thunks are generated for shared libraries.
.section .text_low, "ax", %progbits
@@ -16,8 +16,8 @@ low_target:
bl high_target
ret
// CHECK: low_target:
-// CHECK-NEXT: 0: 04 00 00 94 bl #16
-// CHECK-NEXT: 4: c0 03 5f d6 ret
+// CHECK-NEXT: 8: 04 00 00 94 bl #16
+// CHECK-NEXT: c: c0 03 5f d6 ret
.hidden low_target2
.globl low_target2
@@ -27,19 +27,19 @@ low_target2:
bl high_target2
ret
// CHECK: low_target2:
-// CHECK-NEXT: 8: 05 00 00 94 bl #20
-// CHECK-NEXT: c: c0 03 5f d6 ret
+// CHECK-NEXT: 0: 05 00 00 94 bl #20
+// CHECK-NEXT: 4: c0 03 5f d6 ret
// Expect range extension thunks for .text_low
// adrp calculation is (PC + signed immediate) & (!0xfff)
// CHECK: __AArch64ADRPThunk_high_target:
-// CHECK-NEXT: 10: 10 00 08 90 adrp x16, #268435456
-// CHECK-NEXT: 14: 10 82 04 91 add x16, x16, #288
-// CHECK-NEXT: 18: 00 02 1f d6 br x16
+// CHECK-NEXT: e8: 10 00 08 90 adrp x16, #268435456
+// CHECK-NEXT: ec: 10 02 01 91 add x16, x16, #64
+// CHECK-NEXT: f0: 00 02 1f d6 br x16
// CHECK: __AArch64ADRPThunk_high_target2:
-// CHECK-NEXT: 1c: 10 00 08 90 adrp x16, #268435456
-// CHECK-NEXT: 20: 10 22 00 91 add x16, x16, #8
-// CHECK-NEXT: 24: 00 02 1f d6 br x16
+// CHECK-NEXT: f4: 10 00 08 90 adrp x16, #268435456
+// CHECK-NEXT: f8: 10 22 00 91 add x16, x16, #8
+// CHECK-NEXT: fc: 00 02 1f d6 br x16
.section .text_high, "ax", %progbits
@@ -50,7 +50,7 @@ high_target:
bl low_target
ret
// CHECK: high_target:
-// CHECK-NEXT: 10000000: 4c 00 00 94 bl #304
+// CHECK-NEXT: 10000000: 14 00 00 94 bl #80
// CHECK-NEXT: 10000004: c0 03 5f d6 ret
.hidden high_target2
@@ -68,24 +68,24 @@ high_target2:
// CHECK: __AArch64ADRPThunk_low_target2:
// CHECK-NEXT: 10000010: 10 00 f8 90 adrp x16, #-268435456
-// CHECK-NEXT: 10000014: 10 22 00 91 add x16, x16, #8
+// CHECK-NEXT: 10000014: 10 82 03 91 add x16, x16, #224
// CHECK-NEXT: 10000018: 00 02 1f d6 br x16
// CHECK: Disassembly of section .plt:
// CHECK-NEXT: .plt:
-// CHECK-NEXT: 10000100: f0 7b bf a9 stp x16, x30, [sp, #-16]!
-// CHECK-NEXT: 10000104: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000108: 11 aa 40 f9 ldr x17, [x16, #336]
-// CHECK-NEXT: 1000010c: 10 42 05 91 add x16, x16, #336
-// CHECK-NEXT: 10000110: 20 02 1f d6 br x17
-// CHECK-NEXT: 10000114: 1f 20 03 d5 nop
-// CHECK-NEXT: 10000118: 1f 20 03 d5 nop
-// CHECK-NEXT: 1000011c: 1f 20 03 d5 nop
-// CHECK-NEXT: 10000120: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000124: 11 ae 40 f9 ldr x17, [x16, #344]
-// CHECK-NEXT: 10000128: 10 62 05 91 add x16, x16, #344
-// CHECK-NEXT: 1000012c: 20 02 1f d6 br x17
-// CHECK-NEXT: 10000130: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000134: 11 b2 40 f9 ldr x17, [x16, #352]
-// CHECK-NEXT: 10000138: 10 82 05 91 add x16, x16, #352
-// CHECK-NEXT: 1000013c: 20 02 1f d6 br x17
+// CHECK-NEXT: 10000020: f0 7b bf a9 stp x16, x30, [sp, #-16]!
+// CHECK-NEXT: 10000024: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 10000028: 11 3a 40 f9 ldr x17, [x16, #112]
+// CHECK-NEXT: 1000002c: 10 c2 01 91 add x16, x16, #112
+// CHECK-NEXT: 10000030: 20 02 1f d6 br x17
+// CHECK-NEXT: 10000034: 1f 20 03 d5 nop
+// CHECK-NEXT: 10000038: 1f 20 03 d5 nop
+// CHECK-NEXT: 1000003c: 1f 20 03 d5 nop
+// CHECK-NEXT: 10000040: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 10000044: 11 3e 40 f9 ldr x17, [x16, #120]
+// CHECK-NEXT: 10000048: 10 e2 01 91 add x16, x16, #120
+// CHECK-NEXT: 1000004c: 20 02 1f d6 br x17
+// CHECK-NEXT: 10000050: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 10000054: 11 42 40 f9 ldr x17, [x16, #128]
+// CHECK-NEXT: 10000058: 10 02 02 91 add x16, x16, #128
+// CHECK-NEXT: 1000005c: 20 02 1f d6 br x17
diff --git a/test/ELF/aarch64-thunk-script.s b/test/ELF/aarch64-thunk-script.s
index ebfaf72de5f4..1dfdcbc7a562 100644
--- a/test/ELF/aarch64-thunk-script.s
+++ b/test/ELF/aarch64-thunk-script.s
@@ -1,3 +1,4 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
// RUN: echo "SECTIONS { \
// RUN: .text_low 0x2000: { *(.text_low) } \
@@ -5,7 +6,6 @@
// RUN: } " > %t.script
// RUN: ld.lld --script %t.script %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=aarch64-linux-gnu %t2 | FileCheck %s
-// REQUIRES: aarch64
// Check that we have the out of branch range calculation right. The immediate
// field is signed so we have a slightly higher negative displacement.
diff --git a/test/ELF/aarch64-thunk-section-location.s b/test/ELF/aarch64-thunk-section-location.s
index bf70b7c365ba..606c6941579e 100644
--- a/test/ELF/aarch64-thunk-section-location.s
+++ b/test/ELF/aarch64-thunk-section-location.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d -start-address=134086664 -stop-address=134086676 -triple=aarch64-linux-gnu %t2 | FileCheck %s
-// REQUIRES: aarch64
// Check that the range extension thunks are dumped close to the aarch64 branch
// range of 128 MiB
.section .text.1, "ax", %progbits
diff --git a/test/ELF/aarch64-tls-gdle.s b/test/ELF/aarch64-tls-gdle.s
index a111cacefd29..6763c50838da 100644
--- a/test/ELF/aarch64-tls-gdle.s
+++ b/test/ELF/aarch64-tls-gdle.s
@@ -1,9 +1,9 @@
+# REQUIRES: aarch64
# 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 [
diff --git a/test/ELF/aarch64-tls-ie.s b/test/ELF/aarch64-tls-ie.s
index 8b7431093a26..fba7cd8af51f 100644
--- a/test/ELF/aarch64-tls-ie.s
+++ b/test/ELF/aarch64-tls-ie.s
@@ -1,11 +1,11 @@
// REQUIRES: aarch64
+# 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 --hash-style=sysv %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:
diff --git a/test/ELF/aarch64-tls-iele.s b/test/ELF/aarch64-tls-iele.s
index 208b5cdd5446..c97a578f8dc2 100644
--- a/test/ELF/aarch64-tls-iele.s
+++ b/test/ELF/aarch64-tls-iele.s
@@ -1,9 +1,9 @@
+# REQUIRES: aarch64
# 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 [
diff --git a/test/ELF/aarch64-tls-le.s b/test/ELF/aarch64-tls-le.s
index df943f7f091a..e5b1c208a185 100644
--- a/test/ELF/aarch64-tls-le.s
+++ b/test/ELF/aarch64-tls-le.s
@@ -1,8 +1,8 @@
+# REQUIRES: aarch64
# 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 [
diff --git a/test/ELF/aarch64-tlsld-ldst.s b/test/ELF/aarch64-tlsld-ldst.s
new file mode 100644
index 000000000000..9de3a38044d9
--- /dev/null
+++ b/test/ELF/aarch64-tlsld-ldst.s
@@ -0,0 +1,85 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-readelf --symbols %t | FileCheck -check-prefix CHECK-SYMS %s
+
+ .text
+ .globl _start
+ .type _start, %function
+_start: mrs x8, TPIDR_EL0
+
+ add x8, x8, :tprel_hi12:var0
+ ldr q20, [x8, :tprel_lo12_nc:var0]
+
+ add x8, x8, :tprel_hi12:var1
+ ldr x0, [x8, :tprel_lo12_nc:var1]
+
+ add x8, x8, :tprel_hi12:var2
+ ldr w0, [x8, :tprel_lo12_nc:var2]
+
+ add x8, x8, :tprel_hi12:var3
+ ldrh w0, [x8, :tprel_lo12_nc:var3]
+
+ add x8, x8, :tprel_hi12:var4
+ ldrb w0, [x8, :tprel_lo12_nc:var4]
+
+// CHECK: _start:
+// CHECK-NEXT: 20000: 48 d0 3b d5 mrs x8, TPIDR_EL0
+// 0x0 + c10 = 0xc10 = tcb (16-bytes) + var0
+// CHECK-NEXT: 20004: 08 01 40 91 add x8, x8, #0, lsl #12
+// CHECK-NEXT: 20008: 14 05 c3 3d ldr q20, [x8, #3088]
+// 0x1000 + 0x820 = 0x1820 = tcb + var1
+// CHECK-NEXT: 2000c: 08 05 40 91 add x8, x8, #1, lsl #12
+// CHECK-NEXT: 20010: 00 11 44 f9 ldr x0, [x8, #2080]
+// 0x2000 + 0x428 = 0x2428 = tcb + var2
+// CHECK-NEXT: 20014: 08 09 40 91 add x8, x8, #2, lsl #12
+// CHECK-NEXT: 20018: 00 29 44 b9 ldr w0, [x8, #1064]
+// 0x3000 + 0x2c = 0x302c = tcb + var3
+// CHECK-NEXT: 2001c: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 20020: 00 59 40 79 ldrh w0, [x8, #44]
+// 0x3000 + 0xc2e = 0x32ce = tcb + var4
+// CHECK-NEXT: 20024: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 20028: 00 b9 70 39 ldrb w0, [x8, #3118]
+
+// CHECK-SYMS: 0000000000000c00 0 TLS GLOBAL DEFAULT 2 var0
+// CHECK-SYMS-NEXT: 0000000000001810 4 TLS GLOBAL DEFAULT 2 var1
+// CHECK-SYMS-NEXT: 0000000000002418 2 TLS GLOBAL DEFAULT 2 var2
+// CHECK-SYMS-NEXT: 000000000000301c 1 TLS GLOBAL DEFAULT 2 var3
+// CHECK-SYMS-NEXT: 0000000000003c1e 0 TLS GLOBAL DEFAULT 2 var4
+
+ .globl var0
+ .globl var1
+ .globl var2
+ .globl var3
+ .globl var4
+ .type var0,@object
+ .type var1,@object
+ .type var2,@object
+ .type var3,@object
+
+.section .tbss,"awT",@nobits
+ .balign 16
+ .space 1024 * 3
+var0:
+ .quad 0
+ .quad 0
+ .size var1, 16
+ .space 1024 * 3
+var1:
+ .quad 0
+ .size var1, 8
+ .space 1024 * 3
+var2:
+ .word 0
+ .size var1, 4
+
+ .space 1024 * 3
+var3:
+ .hword 0
+ .size var2, 2
+ .space 1024 * 3
+var4:
+ .byte 0
+ .size var3, 1
+ .space 1024 * 3
diff --git a/test/ELF/aarch64-tstbr14-reloc.s b/test/ELF/aarch64-tstbr14-reloc.s
index c0a0a543a6c5..779ca6b808a8 100644
--- a/test/ELF/aarch64-tstbr14-reloc.s
+++ b/test/ELF/aarch64-tstbr14-reloc.s
@@ -1,3 +1,4 @@
+# REQUIRES: aarch64
# 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
@@ -5,7 +6,6 @@
# 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 = 0x20000
# 0x11020 - 16 = 0x20010
diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s
index 35f50417497e..e2316acf36a0 100644
--- a/test/ELF/aarch64-undefined-weak.s
+++ b/test/ELF/aarch64-undefined-weak.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -triple=aarch64-none-linux -d %t2 | FileCheck %s
-// REQUIRES: aarch64
// Check that the ARM 64-bit ABI rules for undefined weak symbols are applied.
// Branch instructions are resolved to the next instruction. Undefined
diff --git a/test/ELF/abs-conflict.s b/test/ELF/abs-conflict.s
index 4662c48a4e40..ea435cc956c0 100644
--- a/test/ELF/abs-conflict.s
+++ b/test/ELF/abs-conflict.s
@@ -15,4 +15,4 @@ foo = 0x123
// DUP: duplicate symbol: foo
// DUP-NEXT: >>> defined in {{.*}}.o
-// DUP-NEXT: >>> defined in <internal>
+// DUP-NEXT: >>> defined in {{.*}}2.o
diff --git a/test/ELF/allow-multiple-definition.s b/test/ELF/allow-multiple-definition.s
index c54438d9f1e0..06684f47e616 100644
--- a/test/ELF/allow-multiple-definition.s
+++ b/test/ELF/allow-multiple-definition.s
@@ -3,13 +3,14 @@
# 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: not ld.lld --allow-multiple-definition --no-allow-multiple-definition %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition --fatal-warnings %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition --fatal-warnings %t2 %t1 -o %t4
# RUN: llvm-objdump -d %t3 | FileCheck %s
# RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s
-# RUN: ld.lld -z muldefs %t1 %t2 -o %t3
-# RUN: ld.lld -z muldefs %t2 %t1 -o %t4
+# RUN: ld.lld -z muldefs --fatal-warnings %t1 %t2 -o %t3
+# RUN: ld.lld -z muldefs --fatal-warnings %t2 %t1 -o %t4
# RUN: llvm-objdump -d %t3 | FileCheck %s
# RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s
diff --git a/test/ELF/amdgpu-elf-flags-err.s b/test/ELF/amdgpu-elf-flags-err.s
index 4c295b5b92e4..b5619352fb04 100644
--- a/test/ELF/amdgpu-elf-flags-err.s
+++ b/test/ELF/amdgpu-elf-flags-err.s
@@ -1,7 +1,6 @@
-# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o
-# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o
-# RUN: not ld.lld -shared %t-0.o %t-1.o %S/Inputs/amdgpu-kernel-2.o -o %t.so 2>&1 | FileCheck %s
-
# REQUIRES: amdgpu
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx802 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o
+# RUN: not ld.lld -shared %t-0.o %t-1.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: error: incompatible e_flags: {{.*}}amdgpu-kernel-2.o
+# CHECK: error: incompatible e_flags: {{.*}}-1.o
diff --git a/test/ELF/amdgpu-elf-flags.s b/test/ELF/amdgpu-elf-flags.s
index 85f891a98364..d062dac748ea 100644
--- a/test/ELF/amdgpu-elf-flags.s
+++ b/test/ELF/amdgpu-elf-flags.s
@@ -1,10 +1,9 @@
+# REQUIRES: amdgpu
# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o
# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o
# RUN: ld.lld -shared %t-0.o %t-1.o -o %t.so
# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
-# REQUIRES: amdgpu
-
-# CHECK: Flags [ (0x2)
-# CHECK: EF_AMDGPU_ARCH_GCN (0x2)
+# CHECK: Flags [
+# CHECK: EF_AMDGPU_MACH_AMDGCN_GFX803 (0x2A)
# CHECK: ]
diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s
index e32159b332e7..eadc4ef1e0d6 100644
--- a/test/ELF/amdgpu-globals.s
+++ b/test/ELF/amdgpu-globals.s
@@ -1,9 +1,8 @@
+# REQUIRES: amdgpu
# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t
# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
-# REQUIRES: amdgpu
-
.type glob0, @object
.data
.globl glob0
diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s
index c76613f1a336..01b1ef2757fb 100644
--- a/test/ELF/amdgpu-kernels.s
+++ b/test/ELF/amdgpu-kernels.s
@@ -1,9 +1,8 @@
+# REQUIRES: amdgpu
# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
# RUN: ld.lld -shared %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"
diff --git a/test/ELF/amdgpu-relocs.s b/test/ELF/amdgpu-relocs.s
index 8b5a61ed21f4..eeb7571e21df 100644
--- a/test/ELF/amdgpu-relocs.s
+++ b/test/ELF/amdgpu-relocs.s
@@ -1,10 +1,9 @@
+# REQUIRES: amdgpu
# RUN: llvm-mc -filetype=obj -triple=amdgcn--amdhsa -mcpu=fiji %s -o %t.o
# RUN: ld.lld --hash-style=sysv -shared %t.o -o %t.so
# RUN: llvm-readobj -r %t.so | FileCheck %s
# RUN: llvm-objdump -s %t.so | FileCheck %s --check-prefix=OBJDUMP
-# REQUIRES: amdgpu
-
.text
kernel0:
@@ -77,6 +76,15 @@ ptr:
ptr2:
.quad temp2
+# R_AMDGPU_REL64:
+.type foo, @object
+.rodata
+ .globl foo
+ .p2align 3
+foo:
+ .quad temp2@rel64
+ .size foo, 8
+
# The relocation for local_var{0, 1, 2} and var should be resolved by the
# linker.
# CHECK: Relocations [
@@ -101,6 +109,9 @@ ptr2:
# CHECK-NEXT: }
# CHECK-NEXT: ]
+# OBJDUMP: Contents of section .rodata:
+# OBJDUMP: d0f8ffff ffffffff
+
# OBJDUMP: Contents of section nonalloc:
# OBJDUMP-NEXT: 0000 00000000 04480000 00000000 08440000
# OBJDUMP-NEXT: 00000000 0c400000
diff --git a/test/ELF/archive.s b/test/ELF/archive.s
index 59c96a5fba9b..aa7455764fbf 100644
--- a/test/ELF/archive.s
+++ b/test/ELF/archive.s
@@ -1,16 +1,21 @@
+# 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 %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
+
+# RUN: rm -f %t.a
+# RUN: llvm-ar rcs %t.a %t2 %t3 %t4
+
+# RUN: ld.lld %t %t.a %t5 -o %t.out
+# RUN: llvm-nm %t.out | FileCheck %s
+
+# RUN: rm -f %t.thin
+# RUN: llvm-ar --format=gnu rcsT %t.thin %t2 %t3 %t4
+
+# RUN: ld.lld %t %t.thin %t5 -o %t.out
+# RUN: llvm-nm %t.out | FileCheck %s
# Nothing here. Just needed for the linker to create a undefined _start symbol.
@@ -31,8 +36,8 @@
# 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
+# RUN: ld.lld %t.a %t -o %t.out
+# RUN: llvm-nm %t.out | FileCheck --check-prefix=AR-FIRST %s
# AR-FIRST: T _start
# AR-FIRST-NEXT: w bar
diff --git a/test/ELF/arm-attributes.s b/test/ELF/arm-attributes.s
index 14517e8fc789..e4411e79b010 100644
--- a/test/ELF/arm-attributes.s
+++ b/test/ELF/arm-attributes.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-attributes1.s -o %t1.o
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2.o
@@ -7,7 +8,6 @@
// RUN: llvm-readobj -arm-attributes %t2 | FileCheck %s
// RUN: ld.lld %t1.o %t2.o -r -o %t3
// RUN: llvm-readobj -arm-attributes %t3 | FileCheck %s
-// REQUIRES: arm
// Check that we retain only 1 SHT_ARM_ATTRIBUTES section. At present we do not
// try and merge or use the contents of SHT_ARM_ATTRIBUTES sections. We just
diff --git a/test/ELF/arm-bl-v6.s b/test/ELF/arm-bl-v6.s
index 6317aa433d6c..c27a99e6b9e7 100644
--- a/test/ELF/arm-bl-v6.s
+++ b/test/ELF/arm-bl-v6.s
@@ -1,6 +1,6 @@
-// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
-// RUN: ld.lld %t -o %t2 2>&1 | FileCheck %s
// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s
// On Arm v6 the range of a Thumb BL instruction is only 4 megabytes as the
// extended range encoding is not supported. The following example has a Thumb
diff --git a/test/ELF/arm-blx-v4t.s b/test/ELF/arm-blx-v4t.s
index 858b93fd5891..f526b3b01f4a 100644
--- a/test/ELF/arm-blx-v4t.s
+++ b/test/ELF/arm-blx-v4t.s
@@ -1,6 +1,6 @@
-// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
-// RUN: ld.lld %t -o %t2 2>&1 | FileCheck %s
// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s
// On Arm v4t there is no blx instruction so all interworking must go via
// a thunk. At present we don't support v4t so we give a warning for unsupported
diff --git a/test/ELF/arm-blx.s b/test/ELF/arm-blx.s
index 159eee51c74c..5b44c8416c20 100644
--- a/test/ELF/arm-blx.s
+++ b/test/ELF/arm-blx.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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 { \
@@ -10,7 +11,6 @@
// 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.
diff --git a/test/ELF/arm-branch-rangethunk.s b/test/ELF/arm-branch-rangethunk.s
index c61ec899adae..739a7707dbec 100644
--- a/test/ELF/arm-branch-rangethunk.s
+++ b/test/ELF/arm-branch-rangethunk.s
@@ -1,8 +1,11 @@
+// REQUIRES: arm
// 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: ld.lld %t %tfar -o %t2 2>&1
-// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
-// REQUIRES: arm
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck --check-prefix=SHORT %s
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-long-arm-abs.s -o %tfarlong
+// RUN: ld.lld %t %tfarlong -o %t3 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck --check-prefix=LONG %s
.syntax unified
.section .text, "ax",%progbits
.globl _start
@@ -15,20 +18,32 @@ _start:
b too_far2
beq too_far3
-// CHECK: Disassembly of section .text:
-// CHECK-NEXT: _start:
-// CHECK-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1>
-// CHECK-NEXT: 20004: 03 00 00 ea b #12 <__ARMv7ABSLongThunk_too_far2>
-// CHECK-NEXT: 20008: 05 00 00 0a beq #20 <__ARMv7ABSLongThunk_too_far3>
-// CHECK: __ARMv7ABSLongThunk_too_far1:
-// CHECK-NEXT: 2000c: 08 c0 00 e3 movw r12, #8
-// CHECK-NEXT: 20010: 02 c2 40 e3 movt r12, #514
-// CHECK-NEXT: 20014: 1c ff 2f e1 bx r12
-// CHECK: __ARMv7ABSLongThunk_too_far2:
-// CHECK-NEXT: 20018: 0c c0 00 e3 movw r12, #12
-// CHECK-NEXT: 2001c: 02 c2 40 e3 movt r12, #514
-// CHECK-NEXT: 20020: 1c ff 2f e1 bx r12
-// CHECK: __ARMv7ABSLongThunk_too_far3:
-// CHECK-NEXT: 20024: 10 c0 00 e3 movw r12, #16
-// CHECK-NEXT: 20028: 02 c2 40 e3 movt r12, #514
-// CHECK-NEXT: 2002c: 1c ff 2f e1 bx r12
+// SHORT: Disassembly of section .text:
+// SHORT-NEXT: _start:
+// SHORT-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1>
+// SHORT-NEXT: 20004: 01 00 00 ea b #4 <__ARMv7ABSLongThunk_too_far2>
+// SHORT-NEXT: 20008: 01 00 00 0a beq #4 <__ARMv7ABSLongThunk_too_far3>
+// SHORT: __ARMv7ABSLongThunk_too_far1:
+// SHORT-NEXT: 2000c: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffff4>
+// SHORT: __ARMv7ABSLongThunk_too_far2:
+// SHORT-NEXT: 20010: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffff8>
+// SHORT: __ARMv7ABSLongThunk_too_far3:
+// SHORT-NEXT: 20014: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffffc>
+
+// LONG: Disassembly of section .text:
+// LONG-NEXT: _start:
+// LONG-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1>
+// LONG-NEXT: 20004: 03 00 00 ea b #12 <__ARMv7ABSLongThunk_too_far2>
+// LONG-NEXT: 20008: 05 00 00 0a beq #20 <__ARMv7ABSLongThunk_too_far3>
+// LONG: __ARMv7ABSLongThunk_too_far1:
+// LONG-NEXT: 2000c: 14 c0 00 e3 movw r12, #20
+// LONG-NEXT: 20010: 02 c2 40 e3 movt r12, #514
+// LONG-NEXT: 20014: 1c ff 2f e1 bx r12
+// LONG: __ARMv7ABSLongThunk_too_far2:
+// LONG-NEXT: 20018: 20 c0 00 e3 movw r12, #32
+// LONG-NEXT: 2001c: 02 c2 40 e3 movt r12, #514
+// LONG-NEXT: 20020: 1c ff 2f e1 bx r12
+// LONG: __ARMv7ABSLongThunk_too_far3:
+// LONG-NEXT: 20024: 2c c0 00 e3 movw r12, #44
+// LONG-NEXT: 20028: 02 c2 40 e3 movt r12, #514
+// LONG-NEXT: 2002c: 1c ff 2f e1 bx r12
diff --git a/test/ELF/arm-branch-undef-weak-plt-thunk.s b/test/ELF/arm-branch-undef-weak-plt-thunk.s
index f95da0dcec21..f47ed61ca5a6 100644
--- a/test/ELF/arm-branch-undef-weak-plt-thunk.s
+++ b/test/ELF/arm-branch-undef-weak-plt-thunk.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-shared.s -o %t
// RUN: ld.lld %t --shared -o %t.so
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2
// RUN: ld.lld %t2 %t.so -o %t3
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi -start-address=69632 -stop-address=69664 %t3 | FileCheck %s
-// REQUIRES: arm
// When we are dynamic linking, undefined weak references have a PLT entry so
// we must create a thunk for the branch to the PLT entry.
diff --git a/test/ELF/arm-branch.s b/test/ELF/arm-branch.s
index 986863d3d80c..48c497724b0d 100644
--- a/test/ELF/arm-branch.s
+++ b/test/ELF/arm-branch.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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 { \
@@ -7,7 +8,6 @@
// 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
diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s
index dc9e3628de4f..e42f93ea5bb6 100644
--- a/test/ELF/arm-copy.s
+++ b/test/ELF/arm-copy.s
@@ -1,7 +1,7 @@
// 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 -shared %t2.o -soname fixed-length-string.so -o %t2.so
// RUN: ld.lld --hash-style=sysv %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
@@ -33,7 +33,7 @@ _start:
// CHECK-NEXT: AddressAlignment: 16
// CHECK: Relocations [
-// CHECK-NEXT: Section (5) .rel.dyn {
+// CHECK-NEXT: Section {{.*}} .rel.dyn {
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Offset: 0x13000
// CHECK-NEXT: Type: R_ARM_COPY
@@ -78,4 +78,4 @@ _start:
// RODATA: Contents of section .rodata:
// S(z) = 0x13004
-// RODATA-NEXT: 10114 04300100
+// RODATA-NEXT: 10190 04300100
diff --git a/test/ELF/arm-data-prel.s b/test/ELF/arm-data-prel.s
index a8c0c280b220..78b42818609b 100644
--- a/test/ELF/arm-data-prel.s
+++ b/test/ELF/arm-data-prel.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
// RUN: echo "SECTIONS { \
// RUN: .text : { *(.text) } \
@@ -6,7 +7,6 @@
// 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
diff --git a/test/ELF/arm-data-relocs.s b/test/ELF/arm-data-relocs.s
index ed237850c4c1..586e1a6c8933 100644
--- a/test/ELF/arm-data-relocs.s
+++ b/test/ELF/arm-data-relocs.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// 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:
diff --git a/test/ELF/arm-eabi-version.s b/test/ELF/arm-eabi-version.s
index 727b805fddd7..a08374c132f0 100644
--- a/test/ELF/arm-eabi-version.s
+++ b/test/ELF/arm-eabi-version.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// 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 -file-headers %tout | FileCheck %s
-// REQUIRES: arm
.syntax unified
.text
.globl _start
diff --git a/test/ELF/arm-execute-only.s b/test/ELF/arm-execute-only.s
new file mode 100644
index 000000000000..999d88c9e768
--- /dev/null
+++ b/test/ELF/arm-execute-only.s
@@ -0,0 +1,40 @@
+// REQUIRES: arm
+
+// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck %s
+
+// RUN: ld.lld %t.o %t.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck %s
+
+// RUN: echo ".section .foo,\"ax\"; \
+// RUN: bx lr" > %t.s
+// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %t.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF %s
+
+// CHECK-NOT: LOAD
+// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x1000
+// CHECK: LOAD 0x001000 0x00001000 0x00001000 0x{{.*}} 0x{{.*}} R E 0x1000
+// CHECK: LOAD 0x002000 0x00002000 0x00002000 0x{{.*}} 0x{{.*}} E 0x1000
+// CHECK: LOAD 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000
+// CHECK-NOT: LOAD
+
+// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
+// CHECK: 02 .text
+// CHECK: 03 .foo
+// CHECK: 04 .dynamic
+
+// DIFF-NOT: LOAD
+// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x0014d 0x0014d R 0x1000
+// DIFF: LOAD 0x001000 0x00001000 0x00001000 0x0000c 0x0000c R E 0x1000
+// DIFF: LOAD 0x002000 0x00002000 0x00002000 0x00038 0x00038 RW 0x1000
+// DIFF-NOT: LOAD
+
+// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
+// DIFF: 02 .text .foo
+// DIFF: 03 .dynamic
+
+ bx lr
+ .section .foo,"axy"
+ bx lr
diff --git a/test/ELF/arm-exidx-canunwind.s b/test/ELF/arm-exidx-canunwind.s
index 96a7808e8e84..df89d0082fcf 100644
--- a/test/ELF/arm-exidx-canunwind.s
+++ b/test/ELF/arm-exidx-canunwind.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
// RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s
-// REQUIRES: arm
// Test that inline unwinding table entries and references to .ARM.extab
// entries survive the re-ordering of the .ARM.exidx section
diff --git a/test/ELF/arm-exidx-dedup.s b/test/ELF/arm-exidx-dedup.s
index 1648f77152e9..49d4c2cd1ec3 100644
--- a/test/ELF/arm-exidx-dedup.s
+++ b/test/ELF/arm-exidx-dedup.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t --no-merge-exidx-entries -o %t2
// RUN: llvm-objdump -s %t2 | FileCheck --check-prefix CHECK-DUPS %s
// RUN: ld.lld %t -o %t3
// RUN: llvm-objdump -s %t3 | FileCheck %s
-// REQUIRES: arm
// Test that lld can at least remove duplicate .ARM.exidx sections. A more
// fine grained implementation will be able to remove duplicate entries within
// a .ARM.exidx section.
diff --git a/test/ELF/arm-exidx-discard.s b/test/ELF/arm-exidx-discard.s
new file mode 100644
index 000000000000..2a204a04cd1b
--- /dev/null
+++ b/test/ELF/arm-exidx-discard.s
@@ -0,0 +1,14 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o
+// RUN: echo "ENTRY(__entrypoint) SECTIONS { . = 0x10000; .text : { *(.text .text.*) } /DISCARD/ : { *(.ARM.exidx*) *(.gnu.linkonce.armexidx.*) } }" > %t.script
+// RUN: ld.lld -T %t.script %t.o -o %t.elf 2>&1
+// RUN: llvm-readobj -sections %t.elf | FileCheck %s
+
+.globl __entrypoint
+__entrypoint:
+ bx lr
+
+// Check that .ARM.exidx/.gnu.linkonce.armexidx
+// are correctly removed if they were added.
+// CHECK-NOT: .ARM.exidx
+// CHECK-NOT: .gnu.linkonce.armexidx.
diff --git a/test/ELF/arm-exidx-gc.s b/test/ELF/arm-exidx-gc.s
index 34bd9dbe37b2..50c8616ae773 100644
--- a/test/ELF/arm-exidx-gc.s
+++ b/test/ELF/arm-exidx-gc.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t --no-merge-exidx-entries -o %t2 --gc-sections 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
-// REQUIRES: arm
// Test the behavior of .ARM.exidx sections under garbage collection
// A .ARM.exidx section is live if it has a relocation to a live executable
diff --git a/test/ELF/arm-exidx-order.s b/test/ELF/arm-exidx-order.s
index c988ad8a2cfe..7e2d4ce91d92 100644
--- a/test/ELF/arm-exidx-order.s
+++ b/test/ELF/arm-exidx-order.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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/arm-exidx-cantunwind.s -o %tcantunwind
// RUN: ld.lld --no-merge-exidx-entries %t %tcantunwind -o %t2 2>&1
@@ -11,7 +12,6 @@
// RUN: ld.lld --no-merge-exidx-entries --script %t.script %tcantunwind %t -o %t3 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT %s
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT-EXIDX %s
-// REQUIRES: arm
// Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set
// with the sh_link containing the section index of the executable section
@@ -142,28 +142,28 @@ f3:
// CHECK-SCRIPT-NEXT: 11014: 1e ff 2f e1 bx lr
// CHECK-SCRIPT-NEXT: Disassembly of section .func1:
// CHECK-SCRIPT-NEXT: func1:
-// CHECK-SCRIPT-NEXT: 11068: 1e ff 2f e1 bx lr
+// CHECK-SCRIPT-NEXT: 11018: 1e ff 2f e1 bx lr
// CHECK-SCRIPT-NEXT: Disassembly of section .func2:
// CHECK-SCRIPT-NEXT: func2:
-// CHECK-SCRIPT-NEXT: 1106c: 1e ff 2f e1 bx lr
+// CHECK-SCRIPT-NEXT: 1101c: 1e ff 2f e1 bx lr
// CHECK-SCRIPT-NEXT: Disassembly of section .func3:
// CHECK-SCRIPT-NEXT: func3:
-// CHECK-SCRIPT-NEXT: 11070: 1e ff 2f e1 bx lr
+// CHECK-SCRIPT-NEXT: 11020: 1e ff 2f e1 bx lr
// Check that the .ARM.exidx section is sorted in order as the functions
// The offset in field 1, is 32-bit so in the binary the most significant bit
-// 11018 - 18 = 11000 func4
-// 11020 - 1c = 11004 func5
-// CHECK-SCRIPT-EXIDX: 11018 e8ffff7f 01000000 e4ffff7f 01000000
-// 11028 - 20 = 11008 _start
-// 11030 - 24 = 1100c f1
-// CHECK-SCRIPT-EXIDX-NEXT: 11028 e0ffff7f 01000000 dcffff7f 01000000
-// 11038 - 28 = 11010 f2
-// 11040 - 2c = 11014 f3
-// CHECK-SCRIPT-EXIDX-NEXT: 11038 d8ffff7f 01000000 d4ffff7f 01000000
-// 11048 + 20 = 11068 func1
-// 11050 + 1c = 1106c func2
-// CHECK-SCRIPT-EXIDX-NEXT: 11048 20000000 01000000 1c000000 01000000
-// 11058 + 18 = 11070 func3
-// 11060 + 14 = 11074 func3 + sizeof(func3)
-// CHECK-SCRIPT-EXIDX-NEXT: 11058 18000000 01000000 14000000 01000000
+// 11024 - 24 = 11000 func4
+// 1102c - 28 = 11004 func5
+// CHECK-SCRIPT-EXIDX: 11024 dcffff7f 01000000 d8ffff7f 01000000
+// 11034 - 2c = 11008 _start
+// 1103c - 30 = 1100c f1
+// CHECK-SCRIPT-EXIDX-NEXT: 11034 d4ffff7f 01000000 d0ffff7f 01000000
+// 11044 - 34 = 11010 f2
+// 1104c - 38 = 11014 f3
+// CHECK-SCRIPT-EXIDX-NEXT: 11044 ccffff7f 01000000 c8ffff7f 01000000
+// 11054 - 3c = 11018 func1
+// 1105c - 40 = 1101c func2
+// CHECK-SCRIPT-EXIDX-NEXT: 11054 c4ffff7f 01000000 c0ffff7f 01000000
+// 11064 - 44 = 11020 func3
+// 11068 - 48 = 11024 func3 + sizeof(func3)
+// CHECK-SCRIPT-EXIDX-NEXT: 11064 bcffff7f 01000000 b8ffff7f 01000000
diff --git a/test/ELF/arm-exidx-output.s b/test/ELF/arm-exidx-output.s
index dca43a359934..4c65c274b713 100644
--- a/test/ELF/arm-exidx-output.s
+++ b/test/ELF/arm-exidx-output.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-readobj -sections %t2 | FileCheck %s
-// REQUIRES: arm
// Check that only a single .ARM.exidx output section is created when
// there are input sections of the form .ARM.exidx.<section-name>. The
diff --git a/test/ELF/arm-exidx-relocatable.s b/test/ELF/arm-exidx-relocatable.s
index 1b6ee3f23a4f..422dfc289ed7 100644
--- a/test/ELF/arm-exidx-relocatable.s
+++ b/test/ELF/arm-exidx-relocatable.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// 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/arm-exidx-cantunwind.s -o %tcantunwind
// Check that relocatable link maintains SHF_LINK_ORDER
// RUN: ld.lld -r %t %tcantunwind -o %t4 2>&1
// RUN: llvm-readobj -s %t4 | FileCheck %s
-// REQUIRES: arm
// Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set
// with the sh_link containing the section index of the executable section
diff --git a/test/ELF/arm-exidx-sentinel-norelocatable.s b/test/ELF/arm-exidx-sentinel-norelocatable.s
index 4a5b64d8cd18..22e3a09c573f 100644
--- a/test/ELF/arm-exidx-sentinel-norelocatable.s
+++ b/test/ELF/arm-exidx-sentinel-norelocatable.s
@@ -1,6 +1,6 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
// RUN: ld.lld -r %t.o -o %t
-// REQUIRES: arm
// RUN: llvm-readobj -s %t | FileCheck %s
// Check that when doing a relocatable link we don't add a terminating entry
// to the .ARM.exidx section
diff --git a/test/ELF/arm-exidx-sentinel-orphan.s b/test/ELF/arm-exidx-sentinel-orphan.s
index 0e68c245dd10..9aebc4299184 100644
--- a/test/ELF/arm-exidx-sentinel-orphan.s
+++ b/test/ELF/arm-exidx-sentinel-orphan.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// Use Linker script without .ARM.exidx Output Section so it is treated as
// an orphan. We must still add the sentinel table entry
@@ -6,7 +7,6 @@
// RUN: } " > %t.script
// RUN: ld.lld --no-merge-exidx-entries --script %t.script %t -o %t2
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
-// REQUIRES: arm
.syntax unified
.text
@@ -20,4 +20,4 @@ _start:
// CHECK: Contents of section .ARM.exidx:
// 11004 - 4 = 0x11000 = _start
// 1100c - 8 = 0x11004 = _start + sizeof(_start)
-// CHECK-NEXT: 11004 fcffff7f 01000000 f8ffff7f 01000000
+// CHECK-NEXT: 0000 00100100 01000000 fc0f0100 01000000
diff --git a/test/ELF/arm-exidx-shared.s b/test/ELF/arm-exidx-shared.s
index bf7c2dc383e7..631eb0711b8d 100644
--- a/test/ELF/arm-exidx-shared.s
+++ b/test/ELF/arm-exidx-shared.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld --hash-style=sysv %t --shared -o %t2 2>&1
// RUN: llvm-readobj --relocations %t2 | FileCheck %s
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXTAB %s
-// REQUIRES: arm
// Check that the relative R_ARM_PREL31 relocation can access a PLT entry
// for when the personality routine is referenced from a shared library.
@@ -37,9 +37,9 @@ __aeabi_unwind_cpp_pr0:
bx lr
// CHECK: Relocations [
-// CHECK-NEXT: Section (6) .rel.plt {
+// CHECK-NEXT: Section {{.*}} .rel.plt {
// CHECK-NEXT: 0x200C R_ARM_JUMP_SLOT __gxx_personality_v0
// CHECK-EXTAB: Contents of section .ARM.extab:
-// 014c + 0ee4 = 0x1030 = __gxx_personality_v0(PLT)
-// CHECK-EXTAB-NEXT: 014c e40e0000 b0b0b000 00000000
+// 0x0210 + 0x0e20 = 0x1030 = __gxx_personality_v0(PLT)
+// CHECK-EXTAB-NEXT: 0210 200e0000 b0b0b000 00000000
diff --git a/test/ELF/arm-gnu-ifunc-nosym.s b/test/ELF/arm-gnu-ifunc-nosym.s
index fa79aef7ced8..b76ede75b4a1 100644
--- a/test/ELF/arm-gnu-ifunc-nosym.s
+++ b/test/ELF/arm-gnu-ifunc-nosym.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// 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.
diff --git a/test/ELF/arm-gnu-ifunc-plt.s b/test/ELF/arm-gnu-ifunc-plt.s
index 2ff2ec0a143d..441c31c2bb25 100644
--- a/test/ELF/arm-gnu-ifunc-plt.s
+++ b/test/ELF/arm-gnu-ifunc-plt.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %S/Inputs/arm-shared.s -o %t1.o
// RUN: ld.lld %t1.o --shared -o %t.so
// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t.o
@@ -5,7 +6,6 @@
// RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM
// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
-// REQUIRES: arm
// Check that the IRELATIVE relocations are last in the .got
// CHECK: Relocations [
diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s
index 799b8b17f62b..8a7cb0ae237a 100644
--- a/test/ELF/arm-gnu-ifunc.s
+++ b/test/ELF/arm-gnu-ifunc.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// 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
diff --git a/test/ELF/arm-gotoff.s b/test/ELF/arm-gotoff.s
index 5169f84e6a01..b9432b20df20 100644
--- a/test/ELF/arm-gotoff.s
+++ b/test/ELF/arm-gotoff.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// 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
diff --git a/test/ELF/arm-long-thunk-converge.s b/test/ELF/arm-long-thunk-converge.s
new file mode 100644
index 000000000000..dadc7e5fc9a9
--- /dev/null
+++ b/test/ELF/arm-long-thunk-converge.s
@@ -0,0 +1,29 @@
+// REQUIRES: arm
+// RUN: llvm-mc -triple armv7-unknown-gnu -filetype=obj -o %t %s
+// RUN: ld.lld %t %S/Inputs/arm-long-thunk-converge.lds -o %t2
+// RUN: llvm-objdump -d -start-address=0x00000000 -stop-address=0x00000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d -start-address=0x02000000 -stop-address=0x02000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK2 %s
+// RUN: rm -f %t2
+
+// CHECK1: __ARMv7ABSLongThunk_bar:
+// CHECK1-NEXT: 0: 0c c0 00 e3 movw r12, #12
+// CHECK1-NEXT: 4: 00 c2 40 e3 movt r12, #512
+// CHECK1-NEXT: 8: 1c ff 2f e1 bx r12
+// CHECK1: foo:
+// CHECK1-NEXT: c: fb ff ff eb bl #-20
+
+.section .foo,"ax",%progbits,unique,1
+foo:
+bl bar
+
+// CHECK2: __ARMv7ABSLongThunk_foo:
+// CHECK2-NEXT: 2000000: 0c c0 00 e3 movw r12, #12
+// CHECK2-NEXT: 2000004: 00 c0 40 e3 movt r12, #0
+// CHECK2-NEXT: 2000008: 1c ff 2f e1 bx r12
+// CHECK2: bar:
+// CHECK2-NEXT: 200000c: fb ff ff eb bl #-20 <__ARMv7ABSLongThunk_foo>
+
+.section .bar,"ax",%progbits,unique,1
+bar:
+bl foo
+.zero 0x1000000
diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s
index 7e3ce67e0615..f49e2c102e40 100644
--- a/test/ELF/arm-mov-relocs.s
+++ b/test/ELF/arm-mov-relocs.s
@@ -1,10 +1,10 @@
+// REQUIRES: arm
// 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.
diff --git a/test/ELF/arm-pie-relative.s b/test/ELF/arm-pie-relative.s
index f225015eb5f3..582bb8aa03d2 100644
--- a/test/ELF/arm-pie-relative.s
+++ b/test/ELF/arm-pie-relative.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld --hash-style=sysv %t --pie -o %t2
// RUN: llvm-readobj -r %t2 | FileCheck %s
// RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=GOT
-// REQUIRES: arm
// Test that a R_ARM_GOT_BREL relocation with PIE results in a R_ARM_RELATIVE
// dynamic relocation
diff --git a/test/ELF/arm-plt-reloc.s b/test/ELF/arm-plt-reloc.s
index f8166d60ffcf..347bc87f6655 100644
--- a/test/ELF/arm-plt-reloc.s
+++ b/test/ELF/arm-plt-reloc.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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
@@ -5,7 +6,6 @@
// RUN: ld.lld --hash-style=sysv -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
@@ -96,7 +96,7 @@ _start:
// DSOREL-NEXT: AddressAlignment: 4
// DSOREL-NEXT: EntrySize:
// DSOREL: Relocations [
-// DSOREL-NEXT: Section (4) .rel.plt {
+// DSOREL-NEXT: Section {{.*}} .rel.plt {
// DSOREL-NEXT: 0x200C R_ARM_JUMP_SLOT func1 0x0
// DSOREL-NEXT: 0x2010 R_ARM_JUMP_SLOT func2 0x0
// DSOREL-NEXT: 0x2014 R_ARM_JUMP_SLOT func3 0x0
@@ -162,7 +162,7 @@ _start:
// DSORELHIGH-NEXT: ]
// DSORELHIGH-NEXT: Address: 0x1100000
// DSORELHIGH: Relocations [
-// DSORELHIGH-NEXT: Section (6) .rel.plt {
+// DSORELHIGH-NEXT: Section {{.*}} .rel.plt {
// DSORELHIGH-NEXT: 0x110000C R_ARM_JUMP_SLOT func1 0x0
// DSORELHIGH-NEXT: 0x1100010 R_ARM_JUMP_SLOT func2 0x0
// DSORELHIGH-NEXT: 0x1100014 R_ARM_JUMP_SLOT func3 0x0
@@ -227,7 +227,7 @@ _start:
// DSORELLONG-NEXT: ]
// DSORELLONG-NEXT: Address: 0x11111100
// DSORELLONG: Relocations [
-// DSORELLONG-NEXT: Section (6) .rel.plt {
+// DSORELLONG-NEXT: Section {{.*}} .rel.plt {
// DSORELLONG-NEXT: 0x1111110C R_ARM_JUMP_SLOT func1 0x0
// DSORELLONG-NEXT: 0x11111110 R_ARM_JUMP_SLOT func2 0x0
// DSORELLONG-NEXT: 0x11111114 R_ARM_JUMP_SLOT func3 0x0
@@ -292,7 +292,7 @@ _start:
// DSORELMIX-NEXT: SHF_WRITE
// DSORELMIX-NEXT: ]
// DSORELMIX-NEXT: Address: 0x8002020
-// DSORELMIX: Section (6) .rel.plt {
+// DSORELMIX: Section {{.*}} .rel.plt {
// DSORELMIX-NEXT: 0x800202C R_ARM_JUMP_SLOT func1 0x0
// DSORELMIX-NEXT: 0x8002030 R_ARM_JUMP_SLOT func2 0x0
// DSORELMIX-NEXT: 0x8002034 R_ARM_JUMP_SLOT func3 0x0
diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s
index 7f12717195a9..064f59bbd3fe 100644
--- a/test/ELF/arm-sbrel32.s
+++ b/test/ELF/arm-sbrel32.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
-// REQUIRES: arm
// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol
// from the static base. We define the static base to be the address of the
diff --git a/test/ELF/arm-static-defines.s b/test/ELF/arm-static-defines.s
index 815c20ca9451..4487ecdc2925 100644
--- a/test/ELF/arm-static-defines.s
+++ b/test/ELF/arm-static-defines.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld --no-merge-exidx-entries %t --static -o %t2 2>&1
// RUN: llvm-readobj --symbols %t2 | FileCheck %s
-// REQUIRES: arm
// Check that on ARM we don't get a multiply defined symbol for __tls_get_addr
// and undefined symbols for references to __exidx_start and __exidx_end
diff --git a/test/ELF/arm-symbol-ordering-file.s b/test/ELF/arm-symbol-ordering-file.s
new file mode 100644
index 000000000000..fe3de0d9d013
--- /dev/null
+++ b/test/ELF/arm-symbol-ordering-file.s
@@ -0,0 +1,32 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux %s -o %t.o
+
+# RUN: echo ordered > %t_order.txt
+# RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out
+# RUN: llvm-nm -n %t2.out | FileCheck %s
+
+# CHECK: unordered1
+# CHECK-NEXT: unordered2
+# CHECK-NEXT: unordered3
+# CHECK-NEXT: ordered
+# CHECK-NEXT: unordered4
+
+.section .foo,"ax",%progbits,unique,1
+unordered1:
+.zero 1
+
+.section .foo,"ax",%progbits,unique,2
+unordered2:
+.zero 1
+
+.section .foo,"ax",%progbits,unique,3
+unordered3:
+.zero 2
+
+.section .foo,"ax",%progbits,unique,4
+unordered4:
+.zero 4
+
+.section .foo,"ax",%progbits,unique,5
+ordered:
+.zero 1
diff --git a/test/ELF/arm-target1.s b/test/ELF/arm-target1.s
index e77fa57bbf16..2fc0b8bc4281 100644
--- a/test/ELF/arm-target1.s
+++ b/test/ELF/arm-target1.s
@@ -31,6 +31,6 @@
// RELATIVE: SYMBOL TABLE:
// RELATIVE: 00001004 .text 00000000 patatino
-// ABS: can't create dynamic relocation R_ARM_TARGET1 against symbol: patatino
+// ABS: can't create dynamic relocation R_ARM_TARGET1 against symbol: patatino in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// ABS: >>> defined in {{.*}}.o
// ABS: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/arm-target2.s b/test/ELF/arm-target2.s
index a678f7e08fdf..4dbcde88ec31 100644
--- a/test/ELF/arm-target2.s
+++ b/test/ELF/arm-target2.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
// RUN: ld.lld %t.o -o %t 2>&1
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t | FileCheck %s
@@ -7,7 +8,6 @@
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ABS %s
// RUN: ld.lld %t.o --target2=rel -o %t4 2>&1
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-REL %s
-// REQUIRES: arm
// The R_ARM_TARGET2 is present in .ARM.extab sections. It can be handled as
// either R_ARM_ABS32, R_ARM_REL32 or R_ARM_GOT_PREL. For ARM linux the default
@@ -35,16 +35,16 @@ __gxx_personality_v0:
_ZTIi: .word 0
// CHECK: Contents of section .ARM.extab:
-// 1011c + 1ee4 = 12000 = .got
-// CHECK-NEXT: 10114 f00e0000 b0b0b000 e41e0000
+// 0x1012c + 0x1ed4 = 0x12000 = .got
+// CHECK-NEXT: 10124 e00e0000 b0b0b000 d41e0000
// CHECK-ABS: Contents of section .ARM.extab:
-// 100f0 = .rodata
-// CHECK-ABS-NEXT: 100d4 300f0000 b0b0b000 f0000100
+// 0x100f0 = .rodata
+// CHECK-ABS-NEXT: 100e4 200f0000 b0b0b000 f0000100
// CHECK-REL: Contents of section .ARM.extab:
-// 100dc + c = 100e8 = .rodata
-// CHECK-REL-NEXT: 100d4 300f0000 b0b0b000 14000000
+// 0x100ec + 4 = 0x100f0 = .rodata
+// CHECK-REL-NEXT: 100e4 200f0000 b0b0b000 04000000
// CHECK: Contents of section .rodata:
// CHECK-NEXT: 10130 00000000
diff --git a/test/ELF/arm-thumb-blx.s b/test/ELF/arm-thumb-blx.s
index d79bef1835e3..5316d13dbc28 100644
--- a/test/ELF/arm-thumb-blx.s
+++ b/test/ELF/arm-thumb-blx.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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 { \
@@ -9,7 +10,6 @@
// 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
diff --git a/test/ELF/arm-thumb-branch-rangethunk.s b/test/ELF/arm-thumb-branch-rangethunk.s
index f83e64144d70..4bbd69214e93 100644
--- a/test/ELF/arm-thumb-branch-rangethunk.s
+++ b/test/ELF/arm-thumb-branch-rangethunk.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// 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: ld.lld %t %tfar -o %t2 2>&1
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2
-// REQUIRES: arm
.syntax unified
.thumb
.section .text, "ax",%progbits
diff --git a/test/ELF/arm-thumb-branch.s b/test/ELF/arm-thumb-branch.s
index 81bf7a3c68a9..89c081a69b88 100644
--- a/test/ELF/arm-thumb-branch.s
+++ b/test/ELF/arm-thumb-branch.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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 { \
@@ -7,7 +8,6 @@
// 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
diff --git a/test/ELF/arm-thumb-condbranch-thunk.s b/test/ELF/arm-thumb-condbranch-thunk.s
index c527e5df297c..c9365efb73a7 100644
--- a/test/ELF/arm-thumb-condbranch-thunk.s
+++ b/test/ELF/arm-thumb-condbranch-thunk.s
@@ -38,13 +38,9 @@ _start:
// CHECK1-NEXT: 80000: 70 47 bx lr
// CHECK1-NEXT: 80002: 7f f3 ff d7 bl #16252926
// CHECK1: __Thumbv7ABSLongThunk_tfunc05:
-// CHECK1-NEXT: 80008: 40 f2 01 0c movw r12, #1
-// CHECK1-NEXT: 8000c: c0 f2 30 0c movt r12, #48
-// CHECK1-NEXT: 80010: 60 47 bx r12
+// CHECK1-NEXT: 80008: 7f f2 fa bf b.w #2621428 <tfunc05>
// CHECK1: __Thumbv7ABSLongThunk_tfunc00:
-// CHECK1-NEXT: 80012: 40 f2 01 0c movw r12, #1
-// CHECK1-NEXT: 80016: c0 f2 08 0c movt r12, #8
-// CHECK1-NEXT: 8001a: 60 47 bx r12
+// CHECK1-NEXT: 8000c: ff f7 f8 bf b.w #-16 <tfunc00>
FUNCTION 01
// tfunc02 is within range of tfunc02
beq.w tfunc02
@@ -61,7 +57,7 @@ _start:
beq.w tfunc00
// CHECK3: 180000: 70 47 bx lr
// CHECK3-NEXT: 180002: 40 f4 01 80 bne.w #-1048574 <__Thumbv7ABSLongThunk_tfunc05>
-// CHECK3-NEXT: 180006: 00 f4 04 80 beq.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00>
+// CHECK3-NEXT: 180006: 00 f4 01 80 beq.w #-1048574 <__Thumbv7ABSLongThunk_tfunc00>
FUNCTION 03
FUNCTION 04
FUNCTION 05
@@ -70,9 +66,7 @@ _start:
FUNCTION 08
FUNCTION 09
// CHECK4: __Thumbv7ABSLongThunk_tfunc03:
-// CHECK4-NEXT: 500004: 40 f2 01 0c movw r12, #1
-// CHECK4-NEXT: 500008: c0 f2 20 0c movt r12, #32
-// CHECK4-NEXT: 50000c: 60 47 bx r12
+// CHECK4-NEXT: 500004: ff f4 fc bf b.w #-3145736 <tfunc03>
FUNCTION 10
// We can't reach any Thunk Section, create a new one
beq.w tfunc03
@@ -101,17 +95,13 @@ _start:
FUNCTION 30
FUNCTION 31
// CHECK6: __Thumbv7ABSLongThunk_tfunc33:
-// CHECK6-NEXT: 1000004: 40 f2 01 0c movw r12, #1
-// CHECK6-NEXT: 1000008: c0 f2 10 1c movt r12, #272
-// CHECK6-NEXT: 100000c: 60 47 bx r12
+// CHECK6-NEXT: 1000004: ff f0 fc bf b.w #1048568 <tfunc33>
// CHECK6: __Thumbv7ABSLongThunk_tfunc00:
-// CHECK6-NEXT: 100000e: 40 f2 01 0c movw r12, #1
-// CHECK6-NEXT: 1000012: c0 f2 08 0c movt r12, #8
-// CHECK6-NEXT: 1000016: 60 47 bx r12
+// CHECK6-NEXT: 1000008: 7f f4 fa 97 b.w #-16252940 <tfunc00>
FUNCTION 32
FUNCTION 33
// We should be able to reach an existing ThunkSection.
b.w tfunc00
// CHECK7: tfunc33:
// CHECK7-NEXT: 1100000: 70 47 bx lr
-// CHECK7-NEXT: 1100002: 00 f7 04 b8 b.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00>
+// CHECK7-NEXT: 1100002: 00 f7 01 b8 b.w #-1048574 <__Thumbv7ABSLongThunk_tfunc00>
diff --git a/test/ELF/arm-thumb-interwork-shared.s b/test/ELF/arm-thumb-interwork-shared.s
index cadcd451ad67..030ac29854b2 100644
--- a/test/ELF/arm-thumb-interwork-shared.s
+++ b/test/ELF/arm-thumb-interwork-shared.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t --shared -o %t.so
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t.so | FileCheck %s
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s -check-prefix=PLT
-// REQUIRES: arm
.syntax unified
.global sym1
.global elsewhere
diff --git a/test/ELF/arm-thumb-interwork-thunk-range.s b/test/ELF/arm-thumb-interwork-thunk-range.s
index db674f4d5f7c..d59ee1159920 100644
--- a/test/ELF/arm-thumb-interwork-thunk-range.s
+++ b/test/ELF/arm-thumb-interwork-thunk-range.s
@@ -1,6 +1,6 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
-// RUN: ld.lld %t.o -o %t -image-base=0x80000000
+// RUN: ld.lld %t.o -o /dev/null -image-base=0x80000000
// Test that when the thunk is at a high address we don't get confused with it
// being out of range.
diff --git a/test/ELF/arm-thumb-interwork-thunk.s b/test/ELF/arm-thumb-interwork-thunk.s
index 04755c4603cc..df5d6c6b7401 100644
--- a/test/ELF/arm-thumb-interwork-thunk.s
+++ b/test/ELF/arm-thumb-interwork-thunk.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
@@ -8,7 +9,7 @@
// 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) } \
-// RUN: .got.plt 0x1894 : { } } " > %t.script
+// RUN: .got.plt 0x18b4 : { } } " > %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
@@ -19,7 +20,6 @@
// 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
@@ -368,11 +368,11 @@ _start:
// 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
+// CHECK-DSO-REL: 0x18C0 R_ARM_JUMP_SLOT arm_caller
+// CHECK-DSO-REL-NEXT: 0x18C4 R_ARM_JUMP_SLOT thumb_caller
+// CHECK-DSO-REL-NEXT: 0x18C8 R_ARM_JUMP_SLOT thumb_callee1
+// CHECK-DSO-REL-NEXT: 0x18CC R_ARM_JUMP_SLOT thumb_callee2
+// CHECK-DSO-REL-NEXT: 0x18D0 R_ARM_JUMP_SLOT thumb_callee3
+// CHECK-DSO-REL-NEXT: 0x18D4 R_ARM_JUMP_SLOT arm_callee1
+// CHECK-DSO-REL-NEXT: 0x18D8 R_ARM_JUMP_SLOT arm_callee2
+// CHECK-DSO-REL-NEXT: 0x18DC R_ARM_JUMP_SLOT arm_callee3
diff --git a/test/ELF/arm-thumb-mix-range-thunk-os.s b/test/ELF/arm-thumb-mix-range-thunk-os.s
index beff4148b6ff..b5db2565f2c9 100644
--- a/test/ELF/arm-thumb-mix-range-thunk-os.s
+++ b/test/ELF/arm-thumb-mix-range-thunk-os.s
@@ -11,7 +11,7 @@
// RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651590 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s
// RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700168 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s
// RUN: llvm-objdump -d %t2 -start-address=48234500 -stop-address=48234512 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s
-// RUN: llvm-objdump -d %t2 -start-address=63963140 -stop-address=63963160 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s
+// RUN: llvm-objdump -d %t2 -start-address=53477380 -stop-address=53477392 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s
// RUN: llvm-objdump -d %t2 -start-address=68157440 -stop-address=68157452 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s
// RUN: llvm-objdump -d %t2 -start-address=69206016 -stop-address=69206024 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK11 %s
@@ -155,6 +155,13 @@ _start:
ARMFUNCTION 48
THUMBFUNCTION 49
ARMFUNCTION 50
+// Expect precreated Thunk Section here
+// CHECK9: __Thumbv7ABSLongThunk_afunc34:
+// CHECK9-NEXT: 3300004: 40 f2 00 0c movw r12, #0
+// CHECK9-NEXT: 3300008: c0 f2 30 2c movt r12, #560
+// CHECK9-NEXT: 330000c: 60 47 bx r12
+// CHECK9: __Thumbv7ABSLongThunk_tfunc35:
+// CHECK9-NEXT: 330000e: ff f4 f7 97 b.w #-15728658 <tfunc35>
THUMBFUNCTION 51
ARMFUNCTION 52
THUMBFUNCTION 53
@@ -165,15 +172,6 @@ _start:
ARMFUNCTION 58
THUMBFUNCTION 59
ARMFUNCTION 60
-// Expect precreated Thunk Section here
-// CHECK9: __Thumbv7ABSLongThunk_afunc34:
-// CHECK9-NEXT: 3d00004: 40 f2 00 0c movw r12, #0
-// CHECK9-NEXT: 3d00008: c0 f2 30 2c movt r12, #560
-// CHECK9-NEXT: 3d0000c: 60 47 bx r12
-// CHECK9: __Thumbv7ABSLongThunk_tfunc35:
-// CHECK9-NEXT: 3d0000e: 40 f2 01 0c movw r12, #1
-// CHECK9-NEXT: 3d00012: c0 f2 40 2c movt r12, #576
-// CHECK9-NEXT: 3d00016: 60 47 bx r12
THUMBFUNCTION 61
ARMFUNCTION 62
THUMBFUNCTION 63
@@ -191,5 +189,5 @@ _start:
bl tfunc35
// CHECK11: tfunc65:
// CHECK11: 4200000: 70 47 bx lr
-// CHECK11-NEXT: 4200002: ff f6 ff f7 bl #-5242882
-// CHECK11-NEXT: 4200006: 00 f7 02 f0 bl #-5242876
+// CHECK11-NEXT: 4200002: ff f4 ff d7 bl #-15728642
+// CHECK11-NEXT: 4200006: 00 f5 02 d0 bl #-15728636
diff --git a/test/ELF/arm-thumb-narrow-branch-check.s b/test/ELF/arm-thumb-narrow-branch-check.s
index 82a7164f6df6..27bac59787e1 100644
--- a/test/ELF/arm-thumb-narrow-branch-check.s
+++ b/test/ELF/arm-thumb-narrow-branch-check.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
@@ -7,7 +8,6 @@
// 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
diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s
index e8d8d8db684c..5456e7639498 100644
--- a/test/ELF/arm-thumb-no-undefined-thunk.s
+++ b/test/ELF/arm-thumb-no-undefined-thunk.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
-// REQUIRES: arm
// Check that no thunks are created for an undefined weak symbol
.syntax unified
diff --git a/test/ELF/arm-thumb-plt-range-thunk-os.s b/test/ELF/arm-thumb-plt-range-thunk-os.s
index f412faa98eca..080160bb2474 100644
--- a/test/ELF/arm-thumb-plt-range-thunk-os.s
+++ b/test/ELF/arm-thumb-plt-range-thunk-os.s
@@ -1,12 +1,12 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
-// RUN: ld.lld %t --shared -o %t.so
+// RUN: ld.lld %t --shared --icf=all -o %t.so
// The output file is large, most of it zeroes. We dissassemble only the
// parts we need to speed up the test and avoid a large output file
-// RUN: llvm-objdump -d %t.so -start-address=8388608 -stop-address=8388624 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
-// RUN: llvm-objdump -d %t.so -start-address=16777216 -stop-address=16777256 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
-// RUN: llvm-objdump -d %t.so -start-address=25165824 -stop-address=25165828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
-// RUN: llvm-objdump -d %t.so -start-address=25165828 -stop-address=25165924 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d %t.so -start-address=0x2000000 -stop-address=0x2000018 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t.so -start-address=0x2800004 -stop-address=0x2800034 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t.so -start-address=0x4000000 -stop-address=0x4000010 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t.so -start-address=0x4000010 -stop-address=0x4000100 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
.syntax unified
.thumb
@@ -19,74 +19,96 @@
.type preemptible, %function
.global far_preemptible
.type far_preemptible, %function
+ .global far_nonpreemptible
+ .hidden far_nonpreemptible
+ .type far_nonpreemptible, %function
+ .global far_nonpreemptible_alias
+ .hidden far_nonpreemptible_alias
+ .type far_nonpreemptible_alias, %function
sym1:
bl elsewhere
bl preemptible
bx lr
preemptible:
bl far_preemptible
+ bl far_nonpreemptible
+ bl far_nonpreemptible_alias
bx lr
// CHECK1: Disassembly of section .text:
// CHECK1-NEXT: sym1:
-// CHECK1-NEXT: 800000: 00 f0 00 d8 bl #8388608
-// CHECK1-NEXT: 800004: 00 f0 04 d8 bl #8388616
-// CHECK1-NEXT: 800008: 70 47 bx lr
+// CHECK1-NEXT: 2000000: 00 f0 00 d8 bl #8388608
+// CHECK1-NEXT: 2000004: 00 f0 04 d8 bl #8388616
+// CHECK1-NEXT: 2000008: 70 47 bx lr
// CHECK1: preemptible:
-// CHECK1-NEXT: 80000a: 00 f0 07 d8 bl #8388622
-// CHECK1-NEXT: 80000e: 70 47 bx lr
+// CHECK1-NEXT: 200000a: 00 f0 07 d8 bl #8388622
+// CHECK1-NEXT: 200000e: 00 f0 0b d8 bl #8388630
+// CHECK1-NEXT: 2000012: 00 f0 09 d8 bl #8388626
+// CHECK1-NEXT: 2000016: 70 47 bx lr
.section .text.2, "ax", %progbits
.balign 0x0800000
bx lr
// CHECK2: __ThumbV7PILongThunk_elsewhere:
-// CHECK2-NEXT: 1000004: 40 f2 20 0c movw r12, #32
-// CHECK2-NEXT: 1000008: c0 f2 80 0c movt r12, #128
-// CHECK2-NEXT: 100000c: fc 44 add r12, pc
-// CHECK2-NEXT: 100000e: 60 47 bx r12
+// CHECK2-NEXT: 2800004: 40 f2 20 0c movw r12, #32
+// CHECK2-NEXT: 2800008: c0 f2 80 1c movt r12, #384
+// CHECK2-NEXT: 280000c: fc 44 add r12, pc
+// CHECK2-NEXT: 280000e: 60 47 bx r12
// CHECK2: __ThumbV7PILongThunk_preemptible:
-// CHECK2-NEXT: 1000010: 40 f2 24 0c movw r12, #36
-// CHECK2-NEXT: 1000014: c0 f2 80 0c movt r12, #128
-// CHECK2-NEXT: 1000018: fc 44 add r12, pc
-// CHECK2-NEXT: 100001a: 60 47 bx r12
+// CHECK2-NEXT: 2800010: 40 f2 24 0c movw r12, #36
+// CHECK2-NEXT: 2800014: c0 f2 80 1c movt r12, #384
+// CHECK2-NEXT: 2800018: fc 44 add r12, pc
+// CHECK2-NEXT: 280001a: 60 47 bx r12
// CHECK2: __ThumbV7PILongThunk_far_preemptible:
-// CHECK2-NEXT: 100001c: 40 f2 28 0c movw r12, #40
-// CHECK2-NEXT: 1000020: c0 f2 80 0c movt r12, #128
-// CHECK2-NEXT: 1000024: fc 44 add r12, pc
-// CHECK2-NEXT: 1000026: 60 47 bx r12
+// CHECK2-NEXT: 280001c: 40 f2 28 0c movw r12, #40
+// CHECK2-NEXT: 2800020: c0 f2 80 1c movt r12, #384
+// CHECK2-NEXT: 2800024: fc 44 add r12, pc
+// CHECK2-NEXT: 2800026: 60 47 bx r12
+// CHECK2: __ThumbV7PILongThunk_far_nonpreemptible:
+// CHECK2-NEXT: 2800028: 4f f6 cd 7c movw r12, #65485
+// CHECK2-NEXT: 280002c: c0 f2 7f 1c movt r12, #383
+// CHECK2-NEXT: 2800030: fc 44 add r12, pc
+// CHECK2-NEXT: 2800032: 60 47 bx r12
.section .text.3, "ax", %progbits
-.balign 0x0800000
+.balign 0x2000000
far_preemptible:
+far_nonpreemptible:
bl elsewhere
+
+ .section .text.4, "ax", %progbits
+.balign 0x2000000
+far_nonpreemptible_alias:
+ bl elsewhere
+
// CHECK3: far_preemptible:
-// CHECK3: 1800000: 00 f0 16 e8 blx #44
+// CHECK3: 4000000: 00 f0 16 e8 blx #44
// CHECK4: Disassembly of section .plt:
// CHECK4-NEXT: $a:
-// CHECK4-NEXT: 1800010: 04 e0 2d e5 str lr, [sp, #-4]!
-// CHECK4-NEXT: 1800014: 00 e6 8f e2 add lr, pc, #0, #12
-// CHECK4-NEXT: 1800018: 00 ea 8e e2 add lr, lr, #0, #20
-// CHECK4-NEXT: 180001c: ec ff be e5 ldr pc, [lr, #4076]!
+// CHECK4-NEXT: 4000010: 04 e0 2d e5 str lr, [sp, #-4]!
+// CHECK4-NEXT: 4000014: 00 e6 8f e2 add lr, pc, #0, #12
+// CHECK4-NEXT: 4000018: 00 ea 8e e2 add lr, lr, #0, #20
+// CHECK4-NEXT: 400001c: ec ff be e5 ldr pc, [lr, #4076]!
// CHECK4: $d:
-// CHECK4-NEXT: 1800020: d4 d4 d4 d4 .word 0xd4d4d4d4
-// CHECK4-NEXT: 1800024: d4 d4 d4 d4 .word 0xd4d4d4d4
-// CHECK4-NEXT: 1800028: d4 d4 d4 d4 .word 0xd4d4d4d4
-// CHECK4-NEXT: 180002c: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 4000020: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 4000024: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 4000028: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 400002c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4: $a:
-// CHECK4-NEXT: 1800030: 00 c6 8f e2 add r12, pc, #0, #12
-// CHECK4-NEXT: 1800034: 00 ca 8c e2 add r12, r12, #0, #20
-// CHECK4-NEXT: 1800038: d4 ff bc e5 ldr pc, [r12, #4052]!
+// CHECK4-NEXT: 4000030: 00 c6 8f e2 add r12, pc, #0, #12
+// CHECK4-NEXT: 4000034: 00 ca 8c e2 add r12, r12, #0, #20
+// CHECK4-NEXT: 4000038: d4 ff bc e5 ldr pc, [r12, #4052]!
// CHECK4: $d:
-// CHECK4-NEXT: 180003c: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 400003c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4: $a:
-// CHECK4-NEXT: 1800040: 00 c6 8f e2 add r12, pc, #0, #12
-// CHECK4-NEXT: 1800044: 00 ca 8c e2 add r12, r12, #0, #20
-// CHECK4-NEXT: 1800048: c8 ff bc e5 ldr pc, [r12, #4040]!
+// CHECK4-NEXT: 4000040: 00 c6 8f e2 add r12, pc, #0, #12
+// CHECK4-NEXT: 4000044: 00 ca 8c e2 add r12, r12, #0, #20
+// CHECK4-NEXT: 4000048: c8 ff bc e5 ldr pc, [r12, #4040]!
// CHECK4: $d:
-// CHECK4-NEXT: 180004c: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 400004c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4: $a:
-// CHECK4-NEXT: 1800050: 00 c6 8f e2 add r12, pc, #0, #12
-// CHECK4-NEXT: 1800054: 00 ca 8c e2 add r12, r12, #0, #20
-// CHECK4-NEXT: 1800058: bc ff bc e5 ldr pc, [r12, #4028]!
+// CHECK4-NEXT: 4000050: 00 c6 8f e2 add r12, pc, #0, #12
+// CHECK4-NEXT: 4000054: 00 ca 8c e2 add r12, r12, #0, #20
+// CHECK4-NEXT: 4000058: bc ff bc e5 ldr pc, [r12, #4028]!
// CHECK4: $d:
-// CHECK4-NEXT: 180005c: d4 d4 d4 d4 .word 0xd4d4d4d4
+// CHECK4-NEXT: 400005c: d4 d4 d4 d4 .word 0xd4d4d4d4
diff --git a/test/ELF/arm-thumb-plt-reloc.s b/test/ELF/arm-thumb-plt-reloc.s
index dd8770edc3c1..742e95994fff 100644
--- a/test/ELF/arm-thumb-plt-reloc.s
+++ b/test/ELF/arm-thumb-plt-reloc.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// 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
@@ -6,7 +7,6 @@
// 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
diff --git a/test/ELF/arm-thumb-range-thunk-os.s b/test/ELF/arm-thumb-range-thunk-os.s
index 588539ddab8c..182b18d79cae 100644
--- a/test/ELF/arm-thumb-range-thunk-os.s
+++ b/test/ELF/arm-thumb-range-thunk-os.s
@@ -9,8 +9,8 @@
// RUN: llvm-objdump -d %t2 -start-address=4194304 -stop-address=4194310 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
// RUN: llvm-objdump -d %t2 -start-address=16777216 -stop-address=16777270 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK5 %s
// RUN: llvm-objdump -d %t2 -start-address=17825792 -stop-address=17825808 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s
-// RUN: llvm-objdump -d %t2 -start-address=31457280 -stop-address=31457286 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s
-// RUN: llvm-objdump -d %t2 -start-address=32505860 -stop-address=32505880 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s
+// RUN: llvm-objdump -d %t2 -start-address=20971524 -stop-address=20971532 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s
+// RUN: llvm-objdump -d %t2 -start-address=31457280 -stop-address=31457286 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s
// RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651594 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s
// RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700170 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s
@@ -60,7 +60,7 @@ _start:
b.w tfunc28
// CHECK4: tfunc02:
// CHECK4-NEXT: 400000: 70 47 bx lr
-// CHECK4-NEXT: 400002: 00 f0 04 90 b.w #12582920 <__Thumbv7ABSLongThunk_tfunc28>
+// CHECK4-NEXT: 400002: 00 f0 01 90 b.w #12582914 <__Thumbv7ABSLongThunk_tfunc28>
FUNCTION 03
FUNCTION 04
FUNCTION 05
@@ -75,25 +75,19 @@ _start:
FUNCTION 14
// Expect precreated ThunkSection here
// CHECK5: __Thumbv7ABSLongThunk_tfunc16:
-// CHECK5-NEXT: 1000004: 40 f2 01 0c movw r12, #1
-// CHECK5-NEXT: 1000008: c0 f2 20 1c movt r12, #288
-// CHECK5-NEXT: 100000c: 60 47 bx r12
+// CHECK5-NEXT: 1000004: ff f1 fc bf b.w #2097144 <tfunc16>
// CHECK5: __Thumbv7ABSLongThunk_tfunc28:
-// CHECK5-NEXT: 100000e: 40 f2 01 0c movw r12, #1
-// CHECK5-NEXT: 1000012: c0 f2 e0 1c movt r12, #480
-// CHECK5-NEXT: 1000016: 60 47 bx r12
+// CHECK5-NEXT: 1000008: ff f1 fa 97 b.w #14680052 <tfunc28>
// CHECK5: __Thumbv7ABSLongThunk_tfunc32:
-// CHECK5-NEXT: 1000018: 40 f2 01 0c movw r12, #1
-// CHECK5-NEXT: 100001c: c0 f2 20 2c movt r12, #544
-// CHECK5-NEXT: 1000020: 60 47 bx r12
+// CHECK5-NEXT: 100000c: 40 f2 01 0c movw r12, #1
+// CHECK5-NEXT: 1000010: c0 f2 20 2c movt r12, #544
+// CHECK5-NEXT: 1000014: 60 47 bx r12
// CHECK5: __Thumbv7ABSLongThunk_tfunc33:
-// CHECK5-NEXT: 1000022: 40 f2 01 0c movw r12, #1
-// CHECK5-NEXT: 1000026: c0 f2 30 2c movt r12, #560
-// CHECK5-NEXT: 100002a: 60 47 bx r12
+// CHECK5-NEXT: 1000016: 40 f2 01 0c movw r12, #1
+// CHECK5-NEXT: 100001a: c0 f2 30 2c movt r12, #560
+// CHECK5-NEXT: 100001e: 60 47 bx r12
// CHECK5: __Thumbv7ABSLongThunk_tfunc02:
-// CHECK5-NEXT: 100002c: 40 f2 01 0c movw r12, #1
-// CHECK5-NEXT: 1000030: c0 f2 40 0c movt r12, #64
-// CHECK5-NEXT: 1000034: 60 47 bx r12
+// CHECK5-NEXT: 1000020: ff f7 ee 97 b.w #-12582948 <tfunc02>
FUNCTION 15
// tfunc00 and tfunc01 are < 16Mb away, expect no range extension thunks
bl tfunc00
@@ -106,11 +100,16 @@ _start:
// CHECK6-NEXT: 1100000: 70 47 bx lr
// CHECK6-NEXT: 1100002: ff f4 fd d7 bl #-15728646
// CHECK6-NEXT: 1100006: ff f5 fb d7 bl #-14680074
-// CHECK6-NEXT: 110000a: 00 f7 05 f8 bl #-1048566
-// CHECK6-NEXT: 110000e: 00 f7 08 f8 bl #-1048560
+// CHECK6-NEXT: 110000a: ff f6 ff ff bl #-1048578
+// CHECK6-NEXT: 110000e: 00 f7 02 f8 bl #-1048572
FUNCTION 16
FUNCTION 17
FUNCTION 18
+// Expect another precreated thunk section here
+// CHECK7: __Thumbv7ABSLongThunk_tfunc15:
+// CHECK7-NEXT: 1400004: ff f4 fc bf b.w #-3145736 <tfunc15>
+// CHECK7: __Thumbv7ABSLongThunk_tfunc16:
+// CHECK7-NEXT: 1400008: ff f5 fa bf b.w #-2097164 <tfunc16>
FUNCTION 19
FUNCTION 20
FUNCTION 21
@@ -123,21 +122,12 @@ _start:
FUNCTION 28
// tfunc02 is > 16Mb away, expect range extension thunks in precreated thunk
// section
-// CHECK7: tfunc28:
-// CHECK7-NEXT: 1e00000: 70 47 bx lr
-// CHECK7-NEXT: 1e00002: 00 f6 13 90 b.w #-14680026 <__Thumbv7ABSLongThunk_tfunc02>
+// CHECK8: tfunc28:
+// CHECK8-NEXT: 1e00000: 70 47 bx lr
+// CHECK8-NEXT: 1e00002: 00 f6 0d 90 b.w #-14680038 <__Thumbv7ABSLongThunk_tfunc02>
b.w tfunc02
FUNCTION 29
-// Expect another precreated thunk section here
-// CHECK8: __Thumbv7ABSLongThunk_tfunc15:
-// CHECK8-NEXT: 1f00004: 40 f2 01 0c movw r12, #1
-// CHECK8-NEXT: 1f00008: c0 f2 10 1c movt r12, #272
-// CHECK8-NEXT: 1f0000c: 60 47 bx r12
-// CHECK8: __Thumbv7ABSLongThunk_tfunc16:
-// CHECK8-NEXT: 1f0000e: 40 f2 01 0c movw r12, #1
-// CHECK8-NEXT: 1f00012: c0 f2 20 1c movt r12, #288
-// CHECK8-NEXT: 1f00016: 60 47 bx r12
FUNCTION 30
FUNCTION 31
FUNCTION 32
@@ -147,13 +137,13 @@ _start:
bl tfunc16
// CHECK9: tfunc32:
// CHECK9: 2200000: 70 47 bx lr
-// CHECK9-NEXT: 2200002: ff f4 ff ff bl #-3145730
-// CHECK9-NEXT: 2200006: 00 f5 02 f8 bl #-3145724
+// CHECK9-NEXT: 2200002: ff f5 ff d7 bl #-14680066
+// CHECK9-NEXT: 2200006: ff f5 ff d7 bl #-14680066
FUNCTION 33
bl tfunc15
bl tfunc16
// CHECK10: tfunc33:
// CHECK10: 2300000: 70 47 bx lr
-// CHECK10-NEXT: 2300002: ff f7 ff f7 bl #-4194306
-// CHECK10-NEXT: 2300006: 00 f4 02 f8 bl #-4194300
+// CHECK10-NEXT: 2300002: ff f4 ff d7 bl #-15728642
+// CHECK10-NEXT: 2300006: ff f4 ff d7 bl #-15728642
diff --git a/test/ELF/arm-thumb-thunk-empty-pass.s b/test/ELF/arm-thumb-thunk-empty-pass.s
index 9ff6ed6a7807..ab9da1b8a2c2 100644
--- a/test/ELF/arm-thumb-thunk-empty-pass.s
+++ b/test/ELF/arm-thumb-thunk-empty-pass.s
@@ -2,7 +2,7 @@
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d %t2 -start-address=69632 -stop-address=69646 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
-// RUN: llvm-objdump -d %t2 -start-address=16846860 -stop-address=16846874 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t2 -start-address=16846856 -stop-address=16846874 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
.syntax unified
.global _start, foo
.type _start, %function
@@ -20,13 +20,11 @@ foo:
// CHECK1-NEXT: _start:
// CHECK1-NEXT: 11000: ff f7 fe ff bl #-4
// CHECK1: __Thumbv7ABSLongThunk__start:
-// CHECK1-NEXT: 11004: 41 f2 01 0c movw r12, #4097
-// CHECK1-NEXT: 11008: c0 f2 01 0c movt r12, #1
-// CHECK1-NEXT: 1100c: 60 47 bx r12
+// CHECK1-NEXT: 11004: ff f7 fc bf b.w #-8 <_start>
// CHECK2: __Thumbv7ABSLongThunk__start:
-// CHECK2: 101100c: 41 f2 01 0c movw r12, #4097
-// CHECK2-NEXT: 1011010: c0 f2 01 0c movt r12, #1
-// CHECK2-NEXT: 1011014: 60 47 bx r12
+// CHECK2: 1011008: 41 f2 01 0c movw r12, #4097
+// CHECK2-NEXT: 101100c: c0 f2 01 0c movt r12, #1
+// CHECK2-NEXT: 1011010: 60 47 bx r12
// CHECK2: foo:
-// CHECK2-NEXT: 1011016: ff f7 f9 ff bl #-14
+// CHECK2-NEXT: 1011012: ff f7 f9 ff bl #-14
diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s
index faa39fec0218..457d460997aa 100644
--- a/test/ELF/arm-thumb-thunk-symbols.s
+++ b/test/ELF/arm-thumb-thunk-symbols.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-readobj --symbols %t2 | FileCheck %s
// RUN: ld.lld --shared %t -o %t3 2>&1
// RUN: llvm-readobj --symbols %t3 | FileCheck -check-prefix=CHECK-PI %s
-// REQUIRES: arm
// Check that the symbols generated for Thunks have the correct symbol type
// of STT_FUNC and the correct value of bit 0 (0 for ARM 1 for Thumb)
diff --git a/test/ELF/arm-thumb-undefined-weak.s b/test/ELF/arm-thumb-undefined-weak.s
index 7f481b0ddb89..d973c58f16d8 100644
--- a/test/ELF/arm-thumb-undefined-weak.s
+++ b/test/ELF/arm-thumb-undefined-weak.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
-// REQUIRES: arm
// Check that the ARM ABI rules for undefined weak symbols are applied.
// Branch instructions are resolved to the next instruction. Relative
diff --git a/test/ELF/arm-thunk-largesection.s b/test/ELF/arm-thunk-largesection.s
index 950f789764a6..d68cd0c76141 100644
--- a/test/ELF/arm-thunk-largesection.s
+++ b/test/ELF/arm-thunk-largesection.s
@@ -1,11 +1,11 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=69632 -stop-address=69636 %t2 | FileCheck -check-prefix=CHECK1 %s
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=73732 -stop-address=73742 %t2 | FileCheck -check-prefix=CHECK2 %s
-// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=16850944 -stop-address=16850948 %t2 | FileCheck -check-prefix=CHECK3 %s
-// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=33628160 -stop-address=33628164 %t2 | FileCheck -check-prefix=CHECK4 %s
-// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=50405364 -stop-address=50405376 %t2 | FileCheck -check-prefix=CHECK5 %s
-// REQUIRES: arm
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=16850936 -stop-address=16850940 %t2 | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=33628152 -stop-address=33628156 %t2 | FileCheck -check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=50405356 -stop-address=50405376 %t2 | FileCheck -check-prefix=CHECK5 %s
.syntax unified
.balign 0x1000
.thumb
@@ -21,9 +21,7 @@ _start:
// CHECK1-NEXT: 11002: 00 00 movs r0, r0
// CHECK2: __Thumbv7ABSLongThunk__start:
-// CHECK2-NEXT: 12004: 41 f2 01 0c movw r12, #4097
-// CHECK2-NEXT: 12008: c0 f2 01 0c movt r12, #1
-// CHECK2-NEXT: 1200c: 60 47 bx r12
+// CHECK2-NEXT: 12004: fe f7 fc bf b.w #-4104 <_start>
// Gigantic section where we need a ThunkSection either side of it
.section .text.large1, "ax", %progbits
@@ -33,10 +31,10 @@ _start:
.space (16 * 1024 * 1024) - 4
bl _start
.space (16 * 1024 * 1024) - 16
-// CHECK3: 1012000: 00 f4 00 d0 bl #-16777216
-// CHECK4: 2012000: ff f3 f8 d7 bl #16777200
+// CHECK3: 1011ff8: 00 f4 04 d0 bl #-16777208
+// CHECK4: 2011ff8: ff f3 f8 d7 bl #16777200
// CHECK5: __Thumbv7ABSLongThunk__start:
-// CHECK5-NEXT: 3011ff4: 41 f2 01 0c movw r12, #4097
-// CHECK5-NEXT: 3011ff8: c0 f2 01 0c movt r12, #1
-// CHECK5-NEXT: 3011ffc: 60 47 bx r12
+// CHECK5-NEXT: 3011fec: 41 f2 01 0c movw r12, #4097
+// CHECK5-NEXT: 3011ff0: c0 f2 01 0c movt r12, #1
+// CHECK5-NEXT: 3011ff4: 60 47 bx r12
diff --git a/test/ELF/arm-thunk-linkerscript-dotexpr.s b/test/ELF/arm-thunk-linkerscript-dotexpr.s
index bd0e9a293102..ea741708bc90 100644
--- a/test/ELF/arm-thunk-linkerscript-dotexpr.s
+++ b/test/ELF/arm-thunk-linkerscript-dotexpr.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
@@ -6,7 +7,6 @@
// RUN: ld.lld --script %t.script %t -o %t2 2>&1
// RUN: llvm-objdump -d %t2 -start-address=148 -stop-address=188 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
// RUN: llvm-objdump -d %t2 -start-address=33554620 -stop-address=33554654 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
-// REQUIRES: arm
// Test that range extension thunks can handle location expressions within
// a Section Description
.syntax unified
diff --git a/test/ELF/arm-thunk-linkerscript-large.s b/test/ELF/arm-thunk-linkerscript-large.s
index 07cd1dd87976..839d7716c278 100644
--- a/test/ELF/arm-thunk-linkerscript-large.s
+++ b/test/ELF/arm-thunk-linkerscript-large.s
@@ -79,9 +79,7 @@ _start:
FUNCTIONL 08
FUNCTIONL 09
// CHECK3: __Thumbv7ABSLongThunk_tfuncl24:
-// CHECK3-NEXT: b00004: 40 f2 01 0c movw r12, #1
-// CHECK3-NEXT: b00008: c0 f2 a0 1c movt r12, #416
-// CHECK3-NEXT: b0000c: 60 47 bx r12
+// CHECK3-NEXT: b00004: ff f2 fc 97 b.w #15728632 <tfuncl24>
FUNCTIONL 10
FUNCTIONL 11
FUNCTIONL 12
diff --git a/test/ELF/arm-thunk-linkerscript-sort.s b/test/ELF/arm-thunk-linkerscript-sort.s
index 69d176765780..62ea41363f41 100644
--- a/test/ELF/arm-thunk-linkerscript-sort.s
+++ b/test/ELF/arm-thunk-linkerscript-sort.s
@@ -41,9 +41,7 @@ tfunc\suff\():
FUNCTION 16
FUNCTION 15
// CHECK2: __Thumbv7ABSLongThunk_tfunc31:
-// CHECK2-NEXT: 1000004: 40 f2 01 0c movw r12, #1
-// CHECK2-NEXT: 1000008: c0 f2 00 2c movt r12, #512
-// CHECK2-NEXT: 100000c: 60 47 bx r12
+// CHECK2-NEXT: 1000004: ff f3 fc 97 b.w #16777208 <tfunc31>
FUNCTION 14
FUNCTION 13
FUNCTION 12
diff --git a/test/ELF/arm-thunk-linkerscript.s b/test/ELF/arm-thunk-linkerscript.s
index 9aaa29237cbe..7728ddf76a97 100644
--- a/test/ELF/arm-thunk-linkerscript.s
+++ b/test/ELF/arm-thunk-linkerscript.s
@@ -1,3 +1,4 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
@@ -6,7 +7,6 @@
// RUN: } " > %t.script
// RUN: ld.lld --script %t.script %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
-// REQUIRES: arm
// Simple test that we can support range extension thunks with linker scripts
.syntax unified
.section .text_low, "ax", %progbits
diff --git a/test/ELF/arm-thunk-multipass.s b/test/ELF/arm-thunk-multipass.s
index 25bf5235f755..b353bb148ff6 100644
--- a/test/ELF/arm-thunk-multipass.s
+++ b/test/ELF/arm-thunk-multipass.s
@@ -5,7 +5,7 @@
// parts we need to speed up the test and avoid a large output file
// RUN: llvm-objdump -d %t2 -start-address=1048578 -stop-address=1048586 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
// RUN: llvm-objdump -d %t2 -start-address=16777224 -stop-address=16777254 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
-// RUN: llvm-objdump -d %t2 -start-address=17825818 -stop-address=17825828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t2 -start-address=17825812 -stop-address=17825826 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
// In this test case a branch that is in range and does not need its range
// extended can be pushed out of range by another Thunk, necessitating another
// pass
@@ -64,19 +64,15 @@ arm_target:
// CHECK2-NEXT: 100000c: c0 f2 00 1c movt r12, #256
// CHECK2-NEXT: 1000010: 60 47 bx r12
// CHECK2: __Thumbv7ABSLongThunk_target:
-// CHECK2-NEXT: 1000012: 40 f2 1b 0c movw r12, #27
-// CHECK2-NEXT: 1000016: c0 f2 10 1c movt r12, #272
-// CHECK2-NEXT: 100001a: 60 47 bx r12
+// CHECK2-NEXT: 1000012: ff f0 ff bf b.w #1048574 <target>
// CHECK2: __Thumbv7ABSLongThunk_target2:
-// CHECK2-NEXT: 100001c: 40 f2 13 0c movw r12, #19
-// CHECK2-NEXT: 1000020: c0 f2 10 0c movt r12, #16
-// CHECK2-NEXT: 1000024: 60 47 bx r12
+// CHECK2-NEXT: 1000016: ff f4 fc 97 b.w #-15728648 <target2>
.section .text.17, "ax", %progbits
// Just enough space so that bl target is in range if no extension thunks are
// generated.
- .space 0x100000 - 12
+ .space 0x100000 - 6
.section .text.18, "ax", %progbits
.thumb
@@ -90,7 +86,7 @@ target:
nop
bx lr
// CHECK3: target:
-// CHECK3-NEXT: 110001a: ff f6 ff ff bl #-1048578
-// CHECK3-NEXT: 110001e: 00 bf nop
-// CHECK3-NEXT: 1100020: 00 bf nop
-// CHECK3-NEXT: 1100022: 70 47 bx lr
+// CHECK3-NEXT: 1100014: ff f6 ff ff bl #-1048578
+// CHECK3-NEXT: 1100018: 00 bf nop
+// CHECK3-NEXT: 110001a: 00 bf nop
+// CHECK3-NEXT: 110001c: 70 47 bx lr
diff --git a/test/ELF/arm-thunk-nosuitable.s b/test/ELF/arm-thunk-nosuitable.s
new file mode 100644
index 000000000000..cde790665c42
--- /dev/null
+++ b/test/ELF/arm-thunk-nosuitable.s
@@ -0,0 +1,33 @@
+// REQUIRES: ARM
+// RUN: llvm-mc %s --arm-add-build-attributes --triple=armv7a-linux-gnueabihf --filetype=obj -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -triple=thumbv7a-linux-gnueabihf -d -start-address=2166784 -stop-address=2166794 %t | FileCheck %s
+
+ // Create a conditional branch too far away from a precreated thunk
+ // section. This will need a thunk section created within range.
+ .syntax unified
+ .thumb
+
+ .section .text.0, "ax", %progbits
+ .space 2 * 1024 * 1024
+ .globl _start
+ .type _start, %function
+_start:
+ // Range of +/- 1 Megabyte, new ThunkSection will need creating after
+ // .text.1
+ beq.w target
+ .section .text.1, "ax", %progbits
+ bx lr
+
+// CHECK: _start:
+// CHECK-NEXT: 211000: 00 f0 00 80 beq.w #0
+// CHECK: __Thumbv7ABSLongThunk_target:
+// CHECK-NEXT: 211004: 00 f0 01 90 b.w #12582914
+// CHECK: $t.1:
+// CHECK-NEXT: 211008: 70 47 bx lr
+
+ .section .text.2, "ax", %progbits
+ .space 12 * 1024 * 1024
+ .globl target
+ .type target, %function
+target: bx lr
diff --git a/test/ELF/arm-thunk-section-too-large.s b/test/ELF/arm-thunk-section-too-large.s
new file mode 100644
index 000000000000..9174093380f7
--- /dev/null
+++ b/test/ELF/arm-thunk-section-too-large.s
@@ -0,0 +1,21 @@
+// REQUIRES: ARM
+// RUN: llvm-mc %s -triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK: InputSection too large for range extension thunk
+ .syntax unified
+ .thumb
+ .text
+ .globl _start
+ .type _start, %function
+_start:
+ .space 2 * 1024 * 1024
+ // conditional branch has range of 1 Mb expect error as we can't place
+ // a thunk in range of the branch.
+ beq target
+ .space 2 * 1024 * 1024
+
+ .section .text.2, "ax", %progbits
+ .globl target
+ .type target, %function
+target: bx lr
diff --git a/test/ELF/arm-thunk-toolargesection.s b/test/ELF/arm-thunk-toolargesection.s
index 28fb94a8ccfd..13d0ea78368b 100644
--- a/test/ELF/arm-thunk-toolargesection.s
+++ b/test/ELF/arm-thunk-toolargesection.s
@@ -1,6 +1,6 @@
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
-// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.syntax unified
.balign 0x1000
.thumb
diff --git a/test/ELF/arm-tls-gd-nonpreemptible.s b/test/ELF/arm-tls-gd-nonpreemptible.s
index ebaad4788c76..e72d422bad8b 100644
--- a/test/ELF/arm-tls-gd-nonpreemptible.s
+++ b/test/ELF/arm-tls-gd-nonpreemptible.s
@@ -1,10 +1,10 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: llvm-objdump -s %t2 | FileCheck %s
// RUN: ld.lld --hash-style=sysv %t --shared -o %t3.so
// RUN: llvm-objdump -s %t3.so | FileCheck -check-prefix=CHECK-SHARED %s
-// REQUIRES: arm
// For an executable, we write the module index 1 and the offset into the TLS
// directly into the GOT. For a shared library we can only write the offset
diff --git a/test/ELF/arm-tls-gd32.s b/test/ELF/arm-tls-gd32.s
index a32e26f2aeb9..28ef4967aba8 100644
--- a/test/ELF/arm-tls-gd32.s
+++ b/test/ELF/arm-tls-gd32.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared
// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
-// REQUIRES: arm
// Test the handling of the global-dynamic TLS model. Dynamic Loader finds
// module index R_ARM_TLS_DTPMOD32 and the offset within the module
diff --git a/test/ELF/arm-tls-ie32.s b/test/ELF/arm-tls-ie32.s
index 26e1265568c8..b12bc1be3161 100644
--- a/test/ELF/arm-tls-ie32.s
+++ b/test/ELF/arm-tls-ie32.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared
// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
-// REQUIRES: arm
// Test the handling of the initial-exec TLS model. Relative location within
// static TLS is a run-time constant computed by dynamic loader as a result
diff --git a/test/ELF/arm-tls-ldm32.s b/test/ELF/arm-tls-ldm32.s
index 629dcd038899..94931d945761 100644
--- a/test/ELF/arm-tls-ldm32.s
+++ b/test/ELF/arm-tls-ldm32.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared
// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
-// REQUIRES: arm
// Test the handling of the local-dynamic TLS model. Dynamic loader finds
// module index R_ARM_TLS_DTPMOD32. The offset in the next GOT slot is 0
diff --git a/test/ELF/arm-tls-le32.s b/test/ELF/arm-tls-le32.s
index 4d42a06b0fff..7834dedf1be0 100644
--- a/test/ELF/arm-tls-le32.s
+++ b/test/ELF/arm-tls-le32.s
@@ -1,8 +1,8 @@
+// REQUIRES: arm
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld %t.o -o %t
// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck --check-prefix=SEC %s
// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t | FileCheck %s
-// REQUIRES: arm
// Test the handling of the local exec TLS model. TLS can be resolved
// statically for an application. The code sequences assume a thread pointer
diff --git a/test/ELF/arm-tls-norelax-gd-ie.s b/test/ELF/arm-tls-norelax-gd-ie.s
index bcee56165958..ba60521520fe 100644
--- a/test/ELF/arm-tls-norelax-gd-ie.s
+++ b/test/ELF/arm-tls-norelax-gd-ie.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t
// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s
-// REQUIRES: arm
// This tls global-dynamic sequence is with respect to a preemptible symbol but
// is in an application so a relaxation to Initial Exec would normally be
diff --git a/test/ELF/arm-tls-norelax-gd-le.s b/test/ELF/arm-tls-norelax-gd-le.s
index 788c845b3f8b..f1e78c4c76b1 100644
--- a/test/ELF/arm-tls-norelax-gd-le.s
+++ b/test/ELF/arm-tls-norelax-gd-le.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t
// RUN: llvm-objdump -s %t | FileCheck %s
-// REQUIRES: arm
// This tls global-dynamic sequence is with respect to a non-preemptible
// symbol in an application so a relaxation to Local Exec would normally be
diff --git a/test/ELF/arm-tls-norelax-ie-le.s b/test/ELF/arm-tls-norelax-ie-le.s
index eb96aa0fad57..be8af9760481 100644
--- a/test/ELF/arm-tls-norelax-ie-le.s
+++ b/test/ELF/arm-tls-norelax-ie-le.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t
// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t | FileCheck %s
-// REQUIRES: arm
// This tls Initial Exec sequence is with respect to a non-preemptible symbol
// so a relaxation would normally be possible. This would result in an assertion
diff --git a/test/ELF/arm-tls-norelax-ld-le.s b/test/ELF/arm-tls-norelax-ld-le.s
index fc5b72b80f9c..ce0697ad9047 100644
--- a/test/ELF/arm-tls-norelax-ld-le.s
+++ b/test/ELF/arm-tls-norelax-ld-le.s
@@ -1,9 +1,9 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t
// RUN: llvm-objdump -s %t | FileCheck %s
-// REQUIRES: arm
.global __tls_get_addr
.text
diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s
index 8af9f4916a95..0d4714a54835 100644
--- a/test/ELF/arm-undefined-weak.s
+++ b/test/ELF/arm-undefined-weak.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t2 | FileCheck %s
-// REQUIRES: arm
// Check that the ARM ABI rules for undefined weak symbols are applied.
// Branch instructions are resolved to the next instruction. Undefined
diff --git a/test/ELF/arm-use-r-output.s b/test/ELF/arm-use-r-output.s
index 918362466d3a..2d2350863165 100644
--- a/test/ELF/arm-use-r-output.s
+++ b/test/ELF/arm-use-r-output.s
@@ -1,7 +1,7 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
// RUN: ld.lld -r %t.o -o %t2.o
-// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld -shared %t2.o -o /dev/null
// We used to crash using the output of -r because of the relative order of
// SHF_LINK_ORDER sections.
diff --git a/test/ELF/as-needed-lazy.s b/test/ELF/as-needed-lazy.s
new file mode 100644
index 000000000000..e892b9980aad
--- /dev/null
+++ b/test/ELF/as-needed-lazy.s
@@ -0,0 +1,14 @@
+# 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/as-needed-lazy.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: rm -f %t2.a
+# RUN: llvm-ar rc %t2.a %t2.o
+# RUN: ld.lld %t1.o %t2.a --as-needed %t2.so -o %t
+# RUN: llvm-readobj -d %t | FileCheck %s
+
+# CHECK-NOT: NEEDED
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/as-needed-weak.s b/test/ELF/as-needed-weak.s
new file mode 100644
index 000000000000..f009c72d6f48
--- /dev/null
+++ b/test/ELF/as-needed-weak.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: echo '.globl foo; .type foo, @function; foo:' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o
+# RUN: ld.lld -shared -o %t1.so -soname libfoo %t1.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: ld.lld -o %t.exe %t2.o --as-needed %t1.so
+# RUN: llvm-readelf -dynamic-table -dyn-symbols %t.exe | FileCheck %s
+
+# CHECK-NOT: libfoo
+
+# CHECK: Symbol table of .hash for image:
+# CHECK-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 1 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo@
+
+.globl _start
+.weak foo
+
+_start:
+ mov $foo, %eax
+ callq foo
diff --git a/test/ELF/as-needed.s b/test/ELF/as-needed.s
index bcfa32d01f66..a7bba79d57b0 100644
--- a/test/ELF/as-needed.s
+++ b/test/ELF/as-needed.s
@@ -22,7 +22,7 @@
// 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.
+/// GROUP command is the same as listing the files on the command line.
// RUN: echo "GROUP(\"%t2.so\" \"%t3.so\" \"%t4.so\")" > %t.script
// RUN: ld.lld %t.o %t.script -o %t2
diff --git a/test/ELF/auxiliary.s b/test/ELF/auxiliary.s
index 18fbdf05f9ec..86551e3e84bf 100644
--- a/test/ELF/auxiliary.s
+++ b/test/ELF/auxiliary.s
@@ -2,6 +2,8 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld %t.o -shared -f aaa --auxiliary bbb -o %t
# RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+# RUN: ld.lld %t.o -shared -f aaa --auxiliary=bbb -o %t
+# RUN: llvm-readobj --dynamic-table %t | FileCheck %s
# CHECK: DynamicSection [
# CHECK-NEXT: Tag Type Name/Value
diff --git a/test/ELF/basic-aarch64.s b/test/ELF/basic-aarch64.s
index 6527d3dc0def..efbe0080844f 100644
--- a/test/ELF/basic-aarch64.s
+++ b/test/ELF/basic-aarch64.s
@@ -1,8 +1,8 @@
+# REQUIRES: aarch64
# 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
diff --git a/test/ELF/basic-freebsd.s b/test/ELF/basic-freebsd.s
index 375fdb5f8078..f614bb64b069 100644
--- a/test/ELF/basic-freebsd.s
+++ b/test/ELF/basic-freebsd.s
@@ -1,9 +1,9 @@
+# REQUIRES: x86
# 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:
diff --git a/test/ELF/basic-mips.s b/test/ELF/basic-mips.s
index a193529b3487..9ecabff47f6a 100644
--- a/test/ELF/basic-mips.s
+++ b/test/ELF/basic-mips.s
@@ -1,10 +1,9 @@
+# REQUIRES: mips
# 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:
@@ -19,7 +18,7 @@ __start:
# CHECK-NEXT: DataEncoding: LittleEndian (0x1)
# CHECK-NEXT: FileVersion: 1
# CHECK-NEXT: OS/ABI: SystemV (0x0)
-# CHECK-NEXT: ABIVersion: 0
+# CHECK-NEXT: ABIVersion: 1
# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
# CHECK-NEXT: }
# CHECK-NEXT: Type: Executable (0x2)
diff --git a/test/ELF/basic-ppc.s b/test/ELF/basic-ppc.s
index cda32245fd2b..48b146a21d44 100644
--- a/test/ELF/basic-ppc.s
+++ b/test/ELF/basic-ppc.s
@@ -1,7 +1,7 @@
+# REQUIRES: ppc
# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
# RUN: ld.lld --hash-style=sysv -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
@@ -144,9 +144,9 @@
// 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: 0000: 00000006 00000114 0000000B 00000010
+// CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001
+// CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
@@ -165,7 +165,7 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 1
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
+// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
@@ -215,7 +215,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x20A1
-// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Size: 10
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
diff --git a/test/ELF/basic-ppc64.s b/test/ELF/basic-ppc64.s
new file mode 100644
index 000000000000..f586d6320d16
--- /dev/null
+++ b/test/ELF/basic-ppc64.s
@@ -0,0 +1,323 @@
+# REQUIRES: ppc
+# # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s
+.abiversion 2
+# Exits with return code 55 on linux.
+.text
+ li 0,1
+ li 3,55
+ sc
+
+// CHECK:Format: ELF64-ppc64
+// CHECK-NEXT:Arch: powerpc64le
+// CHECK-NEXT:AddressSize: 64bit
+// CHECK-NEXT:LoadName:
+// CHECK-NEXT:ElfHeader {
+// CHECK-NEXT: Ident {
+// CHECK-NEXT: Magic: (7F 45 4C 46)
+// CHECK-NEXT: Class: 64-bit (0x2)
+// CHECK-NEXT: DataEncoding: LittleEndian (0x1)
+// CHECK-NEXT: FileVersion: 1
+// CHECK-NEXT: OS/ABI: SystemV (0x0)
+// CHECK-NEXT: ABIVersion: 0
+// CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
+// CHECK-NEXT: }
+// CHECK-NEXT: Type: SharedObject (0x3)
+// CHECK-NEXT: Machine: EM_PPC64 (0x15)
+// CHECK-NEXT: Version: 1
+// CHECK-NEXT: Entry: 0x10000
+// CHECK-NEXT: ProgramHeaderOffset: 0x40
+// CHECK-NEXT: SectionHeaderOffset:
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: 0x2
+// CHECK-NEXT: ]
+// CHECK-NEXT: HeaderSize: 64
+// CHECK-NEXT: ProgramHeaderEntrySize: 56
+// CHECK-NEXT: ProgramHeaderCount: 7
+// CHECK-NEXT: SectionHeaderEntrySize: 64
+// 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: 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: 0x1C8
+// CHECK-NEXT: Offset: 0x1C8
+// CHECK-NEXT: Size: 24
+// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Info: 1
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 24
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................|
+// CHECK-NEXT: 0010: 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: 0x1E0
+// CHECK-NEXT: Offset: 0x1E0
+// 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: 01000000 01000000 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: 0x1F0
+// CHECK-NEXT: Offset: 0x1F0
+// 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: 0x10000
+// 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-NEXT: 0000: 01000038 37006038 02000044 |...87.`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: 0x20000
+// CHECK-NEXT: Offset: 0x20000
+// CHECK-NEXT: Size: 96
+// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 16
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 06000000 00000000 C8010000 00000000 |................|
+// CHECK-NEXT: 0010: 0B000000 00000000 18000000 00000000 |................|
+// CHECK-NEXT: 0020: 05000000 00000000 F0010000 00000000 |................|
+// CHECK-NEXT: 0030: 0A000000 00000000 01000000 00000000 |................|
+// CHECK-NEXT: 0040: 04000000 00000000 E0010000 00000000 |................|
+// CHECK-NEXT: 0050: 00000000 00000000 00000000 00000000 |................|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 6
+// CHECK-NEXT: Name: .comment (38)
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x30)
+// CHECK-NEXT: SHF_MERGE (0x10)
+// CHECK-NEXT: SHF_STRINGS (0x20)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x20060
+// 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: 4C4C4420 312E3000 |LLD 1.0.|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 7
+// CHECK-NEXT: Name: .symtab (47)
+// CHECK-NEXT: Type: SHT_SYMTAB (0x2)
+// CHECK-NEXT: Flags [ (0x0)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x20068
+// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Link: 9
+// CHECK-NEXT: Info: 2
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 24
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................|
+// CHECK-NEXT: 0010: 00000000 00000000 01000000 00020500 |................|
+// CHECK-NEXT: 0020: 00000200 00000000 00000000 00000000 |................|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 8
+// CHECK-NEXT: Name: .shstrtab (55)
+// CHECK-NEXT: Type: SHT_STRTAB (0x3)
+// CHECK-NEXT: Flags [ (0x0)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x20098
+// CHECK-NEXT: Size: 73
+// 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 63002E63 6F6D6D65 6E74002E |namic..comment..|
+// CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab|
+// CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 9
+// CHECK-NEXT: Name: .strtab (65)
+// CHECK-NEXT: Type: SHT_STRTAB (0x3)
+// CHECK-NEXT: Flags [ (0x0)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x200E1
+// CHECK-NEXT: Size: 10
+// 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: 0x40
+// CHECK-NEXT: VirtualAddress: 0x40
+// CHECK-NEXT: PhysicalAddress: 0x40
+// CHECK-NEXT: FileSize: 392
+// CHECK-NEXT: MemSize: 392
+// 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: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: FileSize: 497
+// CHECK-NEXT: MemSize: 497
+// 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: 0x10000
+// CHECK-NEXT: PhysicalAddress: 0x10000
+// 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: 0x20000
+// CHECK-NEXT: PhysicalAddress: 0x20000
+// CHECK-NEXT: FileSize: 96
+// CHECK-NEXT: MemSize: 96
+// 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_DYNAMIC (0x2)
+// CHECK-NEXT: Offset: 0x20000
+// CHECK-NEXT: VirtualAddress: 0x20000
+// CHECK-NEXT: PhysicalAddress: 0x20000
+// CHECK-NEXT: FileSize: 96
+// CHECK-NEXT: MemSize: 96
+// CHECK-NEXT: Flags [ (0x6)
+// CHECK-NEXT: PF_R (0x4)
+// CHECK-NEXT: PF_W (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 8
+// CHECK-NEXT: }
+// CHECK-NEXT: ProgramHeader {
+// CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552)
+// CHECK-NEXT: Offset: 0x20000
+// CHECK-NEXT: VirtualAddress: 0x20000
+// CHECK-NEXT: PhysicalAddress: 0x20000
+// CHECK-NEXT: FileSize: 96
+// CHECK-NEXT: MemSize: 4096
+// 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-sparcv9.s b/test/ELF/basic-sparcv9.s
index 75c20476a43b..272fe01cfc40 100644
--- a/test/ELF/basic-sparcv9.s
+++ b/test/ELF/basic-sparcv9.s
@@ -1,8 +1,8 @@
+# REQUIRES: sparc
# RUN: llvm-mc -filetype=obj -triple=sparc64-unknown-openbsd %s -o %t
# RUN: ld.lld %t -o %t2
# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
# RUN: | FileCheck %s
-# REQUIRES: sparc
# exits with return code 42 on OpenBSD/sparc64
.global _start
diff --git a/test/ELF/basic32.s b/test/ELF/basic32.s
index 071a06332f0a..72058dc6b168 100644
--- a/test/ELF/basic32.s
+++ b/test/ELF/basic32.s
@@ -1,7 +1,7 @@
+# REQUIRES: x86
# 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
diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s
index d16f4a074175..2bef1545153e 100644
--- a/test/ELF/basic64be.s
+++ b/test/ELF/basic64be.s
@@ -1,29 +1,14 @@
+# REQUIRES: ppc
# 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: ElfHeader {
# CHECK-NEXT: Ident {
# CHECK-NEXT: Magic: (7F 45 4C 46)
# CHECK-NEXT: Class: 64-bit (0x2)
@@ -36,17 +21,18 @@ _start:
# CHECK-NEXT: Type: Executable (0x2)
# CHECK-NEXT: Machine: EM_PPC64 (0x15)
# CHECK-NEXT: Version: 1
-# CHECK-NEXT: Entry: 0x10020040
+# CHECK-NEXT: Entry: 0x10010000
# CHECK-NEXT: ProgramHeaderOffset: 0x40
-# CHECK-NEXT: SectionHeaderOffset: 0x30080
-# CHECK-NEXT: Flags [ (0x0)
+# CHECK-NEXT: SectionHeaderOffset: 0x11050
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: 0x2
# CHECK-NEXT: ]
# CHECK-NEXT: HeaderSize: 64
# CHECK-NEXT: ProgramHeaderEntrySize: 56
-# CHECK-NEXT: ProgramHeaderCount: 6
+# CHECK-NEXT: ProgramHeaderCount: 4
# CHECK-NEXT: SectionHeaderEntrySize: 64
-# CHECK-NEXT: SectionHeaderCount: 10
-# CHECK-NEXT: StringTableSectionIndex: 8
+# CHECK-NEXT: SectionHeaderCount: 6
+# CHECK-NEXT: StringTableSectionIndex: 4
# CHECK-NEXT: }
# CHECK-NEXT: Sections [
# CHECK-NEXT: Section {
@@ -67,7 +53,7 @@ _start:
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index: 1
-# CHECK-NEXT: Name: .text
+# CHECK-NEXT: Name: .text (1)
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
# CHECK-NEXT: Flags [ (0x6)
# CHECK-NEXT: SHF_ALLOC (0x2)
@@ -81,152 +67,80 @@ _start:
# CHECK-NEXT: AddressAlignment: 4
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: SectionData (
-# CHECK: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 2
-# 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: 3
-# 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: 0000: 38000001 3860002A 44000002 |8...8`.*D...|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 4
-# 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 10038000 |................|
-# CHECK-NEXT: 0010: 00000000 00000000 |........|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 5
-# 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: 0x10030000
-# CHECK-NEXT: Offset: 0x30000
-# 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: 6
-# CHECK-NEXT: Name: .comment
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Name: .comment (7)
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
# CHECK-NEXT: Flags [ (0x30)
# CHECK-NEXT: SHF_MERGE (0x10)
# CHECK-NEXT: SHF_STRINGS (0x20)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30000
+# CHECK-NEXT: Offset: 0x11000
# 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: 4C4C4420 312E3000 |LLD 1.0.|
+# CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 7
-# CHECK-NEXT: Name: .symtab
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .symtab (16)
# CHECK-NEXT: Type: SHT_SYMTAB (0x2)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30008
-# CHECK-NEXT: Size: 48
-# CHECK-NEXT: Link: 9
+# CHECK-NEXT: Offset: 0x11008
+# CHECK-NEXT: Size: 24
+# CHECK-NEXT: Link: 5
# CHECK-NEXT: Info: 1
# CHECK-NEXT: AddressAlignment: 8
# CHECK-NEXT: EntrySize: 24
# CHECK-NEXT: SectionData (
-# CHECK: )
+# CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................|
+# CHECK-NEXT: 0010: 00000000 00000000 |........|
+# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 8
-# CHECK-NEXT: Name: .shstrtab
-# CHECK-NEXT: Type: SHT_STRTAB
-# CHECK-NEXT: Flags [
+# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Name: .shstrtab (24)
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
+# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30038
-# CHECK-NEXT: Size: 63
+# CHECK-NEXT: Offset: 0x11020
+# CHECK-NEXT: Size: 42
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: SectionData (
-# CHECK: )
+# CHECK-NEXT: 0000: 002E7465 7874002E 636F6D6D 656E7400 |..text..comment.|
+# CHECK-NEXT: 0010: 2E73796D 74616200 2E736873 74727461 |.symtab..shstrta|
+# CHECK-NEXT: 0020: 62002E73 74727461 6200 |b..strtab.|
+# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 9
-# CHECK-NEXT: Name: .strtab
-# CHECK-NEXT: Type: SHT_STRTAB
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Name: .strtab (34)
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30077
-# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Offset: 0x1104A
+# 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: 005F7374 61727400 |._start.|
+# CHECK-NEXT: 0000: 00 |.|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: ]
@@ -236,74 +150,49 @@ _start:
# 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: 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: 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: 65536
-# CHECK-NEXT: MemSize: 65536
-# 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: 0x30000
-# CHECK-NEXT: VirtualAddress: 0x10030000
-# CHECK-NEXT: PhysicalAddress: 0x10030000
-# 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: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x10000000
+# CHECK-NEXT: PhysicalAddress: 0x10000000
+# CHECK-NEXT: FileSize: 288
+# CHECK-NEXT: MemSize: 288
+# 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: 0x10010000
+# CHECK-NEXT: PhysicalAddress: 0x10010000
+# CHECK-NEXT: FileSize: 4096
+# CHECK-NEXT: MemSize: 4096
+# 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_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
index abd7f2e564d7..d35449828aed 100644
--- a/test/ELF/bss.s
+++ b/test/ELF/bss.s
@@ -1,7 +1,7 @@
+// 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 %t2 | FileCheck %s
-// REQUIRES: x86
// Test that bss takes no space on disk.
diff --git a/test/ELF/bsymbolic-undef.s b/test/ELF/bsymbolic-undef.s
index 19bb3162fd95..1269cb456228 100644
--- a/test/ELF/bsymbolic-undef.s
+++ b/test/ELF/bsymbolic-undef.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/ELF/bsymbolic.s b/test/ELF/bsymbolic.s
index 5a089d55492d..adb9b3ce3630 100644
--- a/test/ELF/bsymbolic.s
+++ b/test/ELF/bsymbolic.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s
index 9447a14d4e8a..5ff2996dc8ea 100644
--- a/test/ELF/build-id.s
+++ b/test/ELF/build-id.s
@@ -7,6 +7,8 @@
# RUN: ld.lld --build-id %t -o %t2 -threads
# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
+# RUN: ld.lld --build-id=fast %t -o %t2 -threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
# RUN: ld.lld --build-id %t -o %t2 -no-threads
# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
diff --git a/test/ELF/cgprofile-bad-clusters.s b/test/ELF/cgprofile-bad-clusters.s
new file mode 100644
index 000000000000..a6a09bd04252
--- /dev/null
+++ b/test/ELF/cgprofile-bad-clusters.s
@@ -0,0 +1,70 @@
+# REQUIRES: x86
+# This test checks that CallGraphSort ignores edges that would form "bad"
+# clusters.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "A C 1" > %t.call_graph
+# RUN: echo "E B 4" >> %t.call_graph
+# RUN: echo "C D 2" >> %t.call_graph
+# RUN: echo "B D 1" >> %t.call_graph
+# RUN: echo "F G 6" >> %t.call_graph
+# RUN: echo "G H 5" >> %t.call_graph
+# RUN: echo "H I 4" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ retq
+
+ .section .text.D,"ax",@progbits
+D:
+ .fill 1000, 1, 0
+
+ .section .text.E,"ax",@progbits
+E:
+ retq
+
+ .section .text.C,"ax",@progbits
+C:
+ retq
+
+ .section .text.B,"ax",@progbits
+B:
+ .fill 1000, 1, 0
+
+ .section .text.F,"ax",@progbits
+F:
+ .fill (1024 * 1024) - 1, 1, 0
+
+ .section .text.G,"ax",@progbits
+G:
+ retq
+
+ .section .text.H,"ax",@progbits
+H:
+ retq
+
+ .section .text.I,"ax",@progbits
+I:
+ .fill 13, 1, 0
+
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201011
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x20100F
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x2013F9
+# CHECK: Name: E
+# CHECK-NEXT: Value: 0x201010
+# CHECK: Name: F
+# CHECK-NEXT: Value: 0x2017E1
+# CHECK: Name: G
+# CHECK-NEXT: Value: 0x3017E0
+# CHECK: Name: H
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: I
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x20100E
diff --git a/test/ELF/cgprofile-err.s b/test/ELF/cgprofile-err.s
new file mode 100644
index 000000000000..6b5425dfafab
--- /dev/null
+++ b/test/ELF/cgprofile-err.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "A B C 100" > %t.call_graph
+# RUN: not ld.lld %t --call-graph-ordering-file \
+# RUN: %t.call_graph -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}.call_graph: parse error
+
+# RUN: echo "A B C" > %t.call_graph
+# RUN: not ld.lld %t --call-graph-ordering-file \
+# RUN: %t.call_graph -o /dev/null 2>&1 | FileCheck %s
diff --git a/test/ELF/cgprofile-icf.s b/test/ELF/cgprofile-icf.s
new file mode 100644
index 000000000000..93b7274a5d33
--- /dev/null
+++ b/test/ELF/cgprofile-icf.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "A B 100" > %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "C D 61" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out -icf=all
+# RUN: llvm-readobj -symbols %t.out | FileCheck %s
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2.out
+# RUN: llvm-readobj -symbols %t2.out | FileCheck %s --check-prefix=NOICF
+
+ .section .text.D,"ax",@progbits
+ .globl D
+D:
+ mov $60, %rax
+ retq
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ mov $60, %rax
+ retq
+
+ .section .text.B,"ax",@progbits
+ .globl B
+B:
+ mov $2, %rax
+ retq
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ mov $42, %rax
+ retq
+
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201010
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201008
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201008
+
+# NOICF: Name: A
+# NOICF-NEXT: Value: 0x201000
+# NOICF: Name: B
+# NOICF-NEXT: Value: 0x201008
+# NOICF: Name: C
+# NOICF-NEXT: Value: 0x201010
+# NOICF: Name: D
+# NOICF-NEXT: Value: 0x201018
diff --git a/test/ELF/cgprofile-txt.s b/test/ELF/cgprofile-txt.s
new file mode 100644
index 000000000000..ee5149aac90d
--- /dev/null
+++ b/test/ELF/cgprofile-txt.s
@@ -0,0 +1,185 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -e A %t -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOSORT
+
+# RUN: echo "A B 10" > %t.call_graph
+# RUN: echo "A B 10" >> %t.call_graph
+# RUN: echo "Aa B 80" >> %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "B C 30" >> %t.call_graph
+# RUN: echo "C D 90" >> %t.call_graph
+# RUN: echo "PP TS 100" >> %t.call_graph
+# RUN: echo "_init2 _init 24567837" >> %t.call_graph
+# RUN: echo "TS QC 9001" >> %t.call_graph
+# RUN: echo "TooManyPreds0 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds1 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds2 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds3 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds4 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds5 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds6 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds7 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds8 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds9 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds10 TooManyPreds 11" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+ .section .text.D,"ax",@progbits
+D:
+ retq
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ retq
+
+ .section .text.B,"ax",@progbits
+ .globl B
+B:
+ retq
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+Aa:
+ retq
+
+ .section .ponies,"ax",@progbits,unique,1
+ .globl TS
+TS:
+ retq
+
+ .section .ponies,"ax",@progbits,unique,2
+ .globl PP
+PP:
+ retq
+
+ .section .other,"ax",@progbits,unique,1
+ .globl QC
+QC:
+ retq
+
+ .section .other,"ax",@progbits,unique,2
+ .globl GB
+GB:
+ retq
+
+ .section .init,"ax",@progbits,unique,1
+ .globl _init
+_init:
+ retq
+
+ .section .init,"ax",@progbits,unique,2
+ .globl _init2
+_init2:
+ retq
+
+ .section .text.TooManyPreds,"ax",@progbits
+TooManyPreds:
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+
+ .section .text.TooManyPreds0,"ax",@progbits
+TooManyPreds0:
+ retq
+
+ .section .text.TooManyPreds1,"ax",@progbits
+TooManyPreds1:
+ retq
+
+ .section .text.TooManyPreds2,"ax",@progbits
+TooManyPreds2:
+ retq
+
+ .section .text.TooManyPreds3,"ax",@progbits
+TooManyPreds3:
+ retq
+
+ .section .text.TooManyPreds4,"ax",@progbits
+TooManyPreds4:
+ retq
+
+ .section .text.TooManyPreds5,"ax",@progbits
+TooManyPreds5:
+ retq
+
+ .section .text.TooManyPreds6,"ax",@progbits
+TooManyPreds6:
+ retq
+
+ .section .text.TooManyPreds7,"ax",@progbits
+TooManyPreds7:
+ retq
+
+ .section .text.TooManyPreds8,"ax",@progbits
+TooManyPreds8:
+ retq
+
+ .section .text.TooManyPreds9,"ax",@progbits
+TooManyPreds9:
+ retq
+
+ .section .text.TooManyPreds10,"ax",@progbits
+TooManyPreds10:
+ retq
+
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201003
+# CHECK: Name: TooManyPreds
+# CHECK-NEXT: Value: 0x201004
+# CHECK: Name: TooManyPreds10
+# CHECK-NEXT: Value: 0x201018
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201002
+# CHECK: Name: GB
+# CHECK-NEXT: Value: 0x20101F
+# CHECK: Name: PP
+# CHECK-NEXT: Value: 0x20101C
+# CHECK: Name: QC
+# CHECK-NEXT: Value: 0x20101E
+# CHECK: Name: TS
+# CHECK-NEXT: Value: 0x20101D
+# CHECK: Name: _init
+# CHECK-NEXT: Value: 0x201020
+# CHECK: Name: _init2
+# CHECK-NEXT: Value: 0x201021
+
+# NOSORT: Name: D
+# NOSORT-NEXT: Value: 0x201000
+# NOSORT: Name: TooManyPreds
+# NOSORT-NEXT: Value: 0x201004
+# NOSORT: Name: TooManyPreds10
+# NOSORT-NEXT: Value: 0x201018
+# NOSORT: Name: A
+# NOSORT-NEXT: Value: 0x201003
+# NOSORT: Name: B
+# NOSORT-NEXT: Value: 0x201002
+# NOSORT: Name: C
+# NOSORT-NEXT: Value: 0x201001
+# NOSORT: Name: GB
+# NOSORT-NEXT: Value: 0x20101C
+# NOSORT: Name: PP
+# NOSORT-NEXT: Value: 0x20101A
+# NOSORT: Name: QC
+# NOSORT-NEXT: Value: 0x20101B
+# NOSORT: Name: TS
+# NOSORT-NEXT: Value: 0x201019
+# NOSORT: Name: _init
+# NOSORT-NEXT: Value: 0x20101D
+# NOSORT: Name: _init2
+# NOSORT-NEXT: Value: 0x20101E
diff --git a/test/ELF/cgprofile-warn.s b/test/ELF/cgprofile-warn.s
new file mode 100644
index 000000000000..bfb89c4c3b57
--- /dev/null
+++ b/test/ELF/cgprofile-warn.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "A B 100" > %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "B C 30" >> %t.call_graph
+# RUN: echo "adena1 A 30" >> %t.call_graph
+# RUN: echo "A adena2 30" >> %t.call_graph
+# RUN: echo "poppy A 30" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o /dev/null \
+# RUN: -noinhibit-exec -icf=all 2>&1 | FileCheck %s
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ mov poppy, %rax
+ retq
+
+B = 0x1234
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ mov poppy, %rax
+ retq
+
+# CHECK: unable to order absolute symbol: B
+# CHECK: {{.*}}.call_graph: no such symbol: adena1
+# CHECK: {{.*}}.call_graph: no such symbol: adena2
+# CHECK: unable to order undefined symbol: poppy
+
+# RUN: ld.lld %t --call-graph-ordering-file %t.call_graph -o /dev/null \
+# RUN: -noinhibit-exec -icf=all --no-warn-symbol-ordering 2>&1 \
+# RUN: | FileCheck %s --check-prefix=NOWARN
+# NOWARN-NOT: unable to order
diff --git a/test/ELF/color-diagnostics.test b/test/ELF/color-diagnostics.test
index 074bba29c54a..6dfa0ab1af92 100644
--- a/test/ELF/color-diagnostics.test
+++ b/test/ELF/color-diagnostics.test
@@ -9,6 +9,9 @@
# COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument: -xyz}}
# COLOR: {{ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}}
+# RUN: not ld.lld -color-diagnostics=foobar 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: unknown option: --color-diagnostics=foobar
+
# RUN: not ld.lld /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s
# RUN: not ld.lld -color-diagnostics=never /nosuchfile 2>&1 \
# RUN: | FileCheck -check-prefix=NOCOLOR %s
diff --git a/test/ELF/combrelocs.s b/test/ELF/combrelocs.s
index 3c8be807053b..595f6049f5fa 100644
--- a/test/ELF/combrelocs.s
+++ b/test/ELF/combrelocs.s
@@ -4,6 +4,9 @@
# RUN: ld.lld -shared %t.o -o %t.out
# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+# RUN: ld.lld -shared %t.o -o %t.out -z combreloc
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.dyn {
# CHECK-NEXT: Relocation {
diff --git a/test/ELF/comdat-discarded-reloc.s b/test/ELF/comdat-discarded-reloc.s
new file mode 100644
index 000000000000..d23baf386e92
--- /dev/null
+++ b/test/ELF/comdat-discarded-reloc.s
@@ -0,0 +1,17 @@
+# 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/comdat-discarded-reloc.s -o %t2.o
+# RUN: ld.lld -gc-sections %t.o %t2.o -o %t
+
+## ELF spec doesn't allow a relocation to point to a deduplicated
+## COMDAT section. Unfortunately this happens in practice (e.g. .eh_frame)
+## Test case checks we do not crash.
+
+.global bar, _start
+
+.section .text.foo,"aG",@progbits,group,comdat
+
+.section .text
+_start:
+ .quad .text.foo
+ .quad bar
diff --git a/test/ELF/comdat-linkonce.s b/test/ELF/comdat-linkonce.s
index 78611b4a9f26..8721f58bb20c 100644
--- a/test/ELF/comdat-linkonce.s
+++ b/test/ELF/comdat-linkonce.s
@@ -1,3 +1,4 @@
+// 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/comdat.s -o %t2.o
// RUN: ld.lld -shared %t.o %t2.o -o %t
diff --git a/test/ELF/comdat.s b/test/ELF/comdat.s
index 5b190b177ee0..4728dd34af5f 100644
--- a/test/ELF/comdat.s
+++ b/test/ELF/comdat.s
@@ -1,18 +1,18 @@
+// 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/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
// Check that we don't crash with --gc-section and that we print a list of
// reclaimed sections on stderr.
// RUN: ld.lld --gc-sections --print-gc-sections -shared %t.o %t.o %t2.o -o %t \
// RUN: 2>&1 | FileCheck --check-prefix=GC %s
-// GC: removing unused section from '.text' in file
-// GC: removing unused section from '.text3' in file
-// GC: removing unused section from '.text' in file
-// GC: removing unused section from '.text' in file
+// GC: removing unused section {{.*}}.o:(.text)
+// GC: removing unused section {{.*}}.o:(.text3)
+// GC: removing unused section {{.*}}.o:(.text)
+// GC: removing unused section {{.*}}.o:(.text)
.section .text2,"axG",@progbits,foo,comdat,unique,0
foo:
diff --git a/test/ELF/common.s b/test/ELF/common.s
index 7f241ee4d65b..da6657173bfd 100644
--- a/test/ELF/common.s
+++ b/test/ELF/common.s
@@ -1,8 +1,8 @@
+// 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/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
diff --git a/test/ELF/compatible-section-types.s b/test/ELF/compatible-section-types.s
index a5dadb867dc0..e47006c5514a 100644
--- a/test/ELF/compatible-section-types.s
+++ b/test/ELF/compatible-section-types.s
@@ -1,3 +1,4 @@
+// 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-objdump -section-headers %t | FileCheck %s
diff --git a/test/ELF/compress-debug-sections-reloc.s b/test/ELF/compress-debug-sections-reloc.s
new file mode 100644
index 000000000000..b4ee4ea6dd97
--- /dev/null
+++ b/test/ELF/compress-debug-sections-reloc.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86, zlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/compress-debug.s -o %t2.o
+# RUN: ld.lld %t2.o %t.o -o %t1 --compress-debug-sections=zlib -Ttext=0
+# RUN: llvm-dwarfdump %t1 -debug-str | FileCheck %s
+# These two checks correspond to the patched values of a_sym and a_debug_sym.
+# D = 0x44 - address of .text input section for this file (the start address of
+# .text is 0 as requested on the command line, and the size of the
+# preceding .text in the other input file is 0x44).
+# C = 0x43 - offset of .debug_info section for this file (the size of
+# the preceding .debug_info from the other input file is 0x43).
+# CHECK: 0x00000000: "D"
+# CHECK: 0x00000004: "C"
+
+.text
+a_sym:
+nop
+
+.section .debug_str,"",@progbits
+.long a_sym
+.long a_debug_sym
+
+.section .debug_info,"",@progbits
+a_debug_sym:
+.long 0x88776655
diff --git a/test/ELF/compressed-debug-conflict.s b/test/ELF/compressed-debug-conflict.s
index c67bc9201803..e8c24262b7f4 100644
--- a/test/ELF/compressed-debug-conflict.s
+++ b/test/ELF/compressed-debug-conflict.s
@@ -1,15 +1,15 @@
# REQUIRES: x86, zlib
# RUN: llvm-mc -filetype=obj -triple i686-linux-gnu -compress-debug-sections=zlib %s -o %t.o
# RUN: llvm-readobj -sections %t.o | FileCheck -check-prefix=OBJ %s
-# RUN: not ld.lld %t.o %t.o -o %tout 2>&1 | FileCheck -check-prefix=ERROR %s
+# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck -check-prefix=ERROR %s
# OBJ: Sections [
# OBJ: Section {
-# OBJ: Index: 3
-# OBJ-NEXT: Name: .debug_line (16)
-# OBJ-NEXT: Type: SHT_PROGBITS (0x1)
-# OBJ-NEXT: Flags [ (0x800)
-# OBJ-NEXT: SHF_COMPRESSED (0x800)
+# OBJ: Index:
+# OBJ: Name: .debug_line
+# OBJ-NEXT: Type: SHT_PROGBITS
+# OBJ-NEXT: Flags [
+# OBJ-NEXT: SHF_COMPRESSED
# OBJ-NEXT: ]
# ERROR: error: duplicate symbol: main
@@ -27,3 +27,24 @@ main:
xorl %eax, %eax
retl
.file 2 "/tmp/repeat/repeat/repeat/repeat" "repeat.h"
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 4 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+ .long .debug_line # DW_AT_stmt_list
+.Lend0:
+ .section .debug_line,"",@progbits
diff --git a/test/ELF/compressed-debug-input-err.s b/test/ELF/compressed-debug-input-err.s
new file mode 100644
index 000000000000..e32ba315b342
--- /dev/null
+++ b/test/ELF/compressed-debug-input-err.s
@@ -0,0 +1,11 @@
+# REQUIRES: zlib, x86
+
+# 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 we are able to report zlib decompressor errors.
+# CHECK: error: {{.*}}.o:(.zdebug_str): decompress failed: zlib error: Z_DATA_ERROR
+
+.section .zdebug_str,"MS",@progbits,1
+ .ascii "ZLIB"
+ .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1
diff --git a/test/ELF/conflict-debug-variable-file-index.s b/test/ELF/conflict-debug-variable-file-index.s
new file mode 100644
index 000000000000..c7bd8bbcbafb
--- /dev/null
+++ b/test/ELF/conflict-debug-variable-file-index.s
@@ -0,0 +1,103 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s
+
+## Check we are able to report errors even if DW_AT_decl_file
+## contains invalid file name index.
+## We did not try to support this intentionally but have
+## an error handling and reporting logic that can take care
+## of that and hence needs a test.
+
+# CHECK: duplicate symbol: foo
+# CHECK-NEXT: >>> defined at {{.*}}.o:(foo)
+# CHECK-NEXT: >>> {{.*}}.o:(.bss+0x0)
+
+# Used modified output from the following code and gcc 7.1.0:
+# Source (1.c):
+# int foo = 0;
+# Invocation: g++ -g -S 1.c
+
+.bss
+.globl foo
+.type foo, @object
+.size foo, 4
+foo:
+
+.text
+.file 1 "1.c"
+
+.section .debug_info,"",@progbits
+ .long 0x35 # Compile Unit: length = 0x0000004b)
+ .value 0x4 # version = 0x0004
+ .long 0 # abbr_offset = 0x0
+ .byte 0x8 # addr_size = 0x08
+
+ .uleb128 0x1 # DW_TAG_compile_unit [1] *
+ .long 0 # DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000000] = )
+ .byte 0x4 # DW_AT_language [DW_FORM_data1] (DW_LANG_C_plus_plus)
+ .string "1.c" # DW_AT_name [DW_FORM_string] ("1.c")
+ .long 0 # DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000000] = )
+ .long 0 # DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000)
+
+ .uleb128 0x2 # DW_TAG_variable [2]
+ .string "foo" # DW_AT_name [DW_FORM_string] ("foo")
+ .byte 0xFE # DW_AT_decl_file [DW_FORM_data1] <broken file>
+ .byte 0x1 # DW_AT_decl_line [DW_FORM_data1] (1)
+ .long 0x32 # DW_AT_type [DW_FORM_ref4] (cu + 0x0032 => {0x00000032})
+ .uleb128 0x9 # DW_AT_external [DW_FORM_flag_present] (true)
+ .byte 0x3
+ .quad foo # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0)
+
+ .uleb128 0x3 # DW_TAG_base_type [3]
+ .byte 0x4 # DW_AT_byte_size [DW_FORM_data1] (0x04)
+ .byte 0x5 # DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
+ .string "int" # DW_AT_name [DW_FORM_string] ("int")
+
+.section .debug_abbrev,"",@progbits
+ .uleb128 0x1 # Abbreviation code.
+ .uleb128 0x11 # DW_TAG_compile_unit
+
+ .byte 0x1 # ID
+ .uleb128 0x25 # DW_AT_producer, DW_FORM_strp
+ .uleb128 0xe
+ .uleb128 0x13 # DW_AT_language, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x3 # DW_AT_name, DW_FORM_string
+ .uleb128 0x8
+ .uleb128 0x1b # DW_AT_comp_dir, DW_FORM_strp
+ .uleb128 0xe
+ .uleb128 0x10 # DW_AT_stmt_list, DW_FORM_sec_offset
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+
+ .uleb128 0x2 # ID
+ .uleb128 0x34 # DW_TAG_variable, DW_CHILDREN_no
+ .byte 0
+ .uleb128 0x3 # DW_AT_name, DW_FORM_string
+ .uleb128 0x8
+ .uleb128 0x3a # DW_AT_decl_file, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x3b # DW_AT_decl_line, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x49 # DW_AT_type, DW_FORM_ref4
+ .uleb128 0x13
+ .uleb128 0x3f # DW_AT_external, DW_FORM_flag_present
+ .uleb128 0x19
+ .uleb128 0x2 # DW_AT_location, DW_FORM_exprloc
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+
+ .uleb128 0x3 # ID
+ .uleb128 0x24 # DW_TAG_base_type, DW_CHILDREN_no
+ .byte 0
+ .uleb128 0xb # DW_AT_byte_size, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x3e # DW_AT_encoding, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x3 # DW_AT_name, DW_FORM_string
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .byte 0
diff --git a/test/ELF/conflict-debug-variable.s b/test/ELF/conflict-debug-variable.s
index 297ed4bbe1ea..244ac146a01b 100644
--- a/test/ELF/conflict-debug-variable.s
+++ b/test/ELF/conflict-debug-variable.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: llvm-dwarfdump %t.o | FileCheck -check-prefix=INPUT %s
# RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s
@@ -7,14 +8,14 @@
# INPUT-NEXT: DW_AT_name ("foo")
# INPUT-NEXT: DW_AT_decl_file ("1.c")
# INPUT-NEXT: DW_AT_decl_line (1)
-# INPUT-NEXT: DW_AT_type (cu + 0x0032 "int")
+# INPUT-NEXT: DW_AT_type (0x00000032 "int")
# INPUT-NEXT: DW_AT_external (true)
# INPUT-NEXT: DW_AT_location (DW_OP_addr 0x0)
# INPUT: DW_TAG_variable
# INPUT-NEXT: DW_AT_name ("bar")
# INPUT-NEXT: DW_AT_decl_file ("1.c")
# INPUT-NEXT: DW_AT_decl_line (2)
-# INPUT-NEXT: DW_AT_type (cu + 0x0032 "int")
+# INPUT-NEXT: DW_AT_type (0x00000032 "int")
# INPUT-NEXT: DW_AT_external (true)
# INPUT-NEXT: DW_AT_location (DW_OP_addr 0x0)
@@ -38,6 +39,7 @@
# Source (1.c):
# int foo = 0;
# int bar = 1;
+# static int zed = 3;
# Invocation: g++ -g -S 1.c
.bss
@@ -51,12 +53,16 @@ foo:
.type bar, @object
.size bar, 4
bar:
+ .byte 0
+
+.local zed
+zed:
.text
.file 1 "1.c"
.section .debug_info,"",@progbits
- .long 0x4b # Compile Unit: length = 0x0000004b)
+ .long 0x5a # Compile Unit: length = 0x0000004b)
.value 0x4 # version = 0x0004
.long 0 # abbr_offset = 0x0
.byte 0x8 # addr_size = 0x08
@@ -90,6 +96,14 @@ bar:
.uleb128 0x9 # DW_AT_external [DW_FORM_flag_present] (true)
.byte 0x3
.quad bar # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0)
+
+ .uleb128 0x4 # DW_TAG_variable [2]
+ .string "zed" # DW_AT_name [DW_FORM_string] ("zed")
+ .byte 0x1 # DW_AT_decl_file [DW_FORM_data1] ("1.c")
+ .byte 0x3 # DW_AT_decl_line [DW_FORM_data1] (2)
+ .long 0x32 # DW_AT_type [DW_FORM_ref4] (cu + 0x0032 => {0x00000032})
+ .quad zed # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0)
+
.byte 0 # END
@@ -140,5 +154,21 @@ bar:
.uleb128 0x8
.byte 0
.byte 0
+
+ .uleb128 0x4 # ID
+ .uleb128 0x34 # DW_TAG_variable, DW_CHILDREN_no
+ .byte 0
+ .uleb128 0x3 # DW_AT_name, DW_FORM_string
+ .uleb128 0x8
+ .uleb128 0x3a # DW_AT_decl_file, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x3b # DW_AT_decl_line, DW_FORM_data1
+ .uleb128 0xb
+ .uleb128 0x49 # DW_AT_type, DW_FORM_ref4
+ .uleb128 0x13
+ .uleb128 0x2 # DW_AT_location, DW_FORM_exprloc
+ .uleb128 0x18
+ .byte 0
.byte 0
+ .byte 0
diff --git a/test/ELF/conflict-debug-variable2.s b/test/ELF/conflict-debug-variable2.s
index 1fb9b09443b4..3fb59e6b4d02 100644
--- a/test/ELF/conflict-debug-variable2.s
+++ b/test/ELF/conflict-debug-variable2.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: llvm-dwarfdump -v %t.o | FileCheck -check-prefix=INPUT %s
@@ -18,7 +19,7 @@
# INPUT-NEXT: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0)
## Check we use information from .debug_info in messages.
-# RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: duplicate symbol: bar
# CHECK-NEXT: >>> defined at test.c:2
# CHECK-NEXT: >>> {{.*}}:(bar)
diff --git a/test/ELF/conflict-variable-linkage-name.s b/test/ELF/conflict-variable-linkage-name.s
new file mode 100644
index 000000000000..9b201d93a830
--- /dev/null
+++ b/test/ELF/conflict-variable-linkage-name.s
@@ -0,0 +1,176 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck %s
+
+## Check we can report the locations of 2 different "bar" variables.
+# CHECK: duplicate symbol: A::bar
+# CHECK-NEXT: >>> defined at 1.cpp:2
+# CHECK-NEXT: >>> {{.*}}:(A::bar)
+# CHECK-NEXT: >>> defined at 1.cpp:2
+# CHECK-NEXT: >>> {{.*}}:(.bss+0x0)
+# CHECK: duplicate symbol: Z::bar
+# CHECK-NEXT: >>> defined at 1.cpp:6
+# CHECK-NEXT: >>> {{.*}}:(Z::bar)
+# CHECK-NEXT: >>> defined at 1.cpp:6
+# CHECK-NEXT: >>> {{.*}}:(.data+0x0)
+
+# Used reduced output from following code and clang version 7.0.0 (trunk 332701)
+# to produce this input file:
+# Source (1.cpp):
+# namespace A {
+# int bar;
+# }
+#
+# namespace Z {
+# int bar;
+# }
+# Invocation: clang-7 -g -S 1.cpp
+
+.text
+.file "1.cpp"
+.file 1 "/path" "1.cpp"
+
+.type _ZN1A3barE,@object
+.bss
+.globl _ZN1A3barE
+_ZN1A3barE:
+ .long 0
+ .size _ZN1A3barE, 4
+
+.type _ZN1Z3barE,@object
+.data
+.globl _ZN1Z3barE
+_ZN1Z3barE:
+ .long 1
+ .size _ZN1Z3barE, 4
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 7.0.0 (trunk 332701)" # string offset=0
+.Linfo_string1:
+ .asciz "1.cpp" # string offset=35
+.Linfo_string2:
+ .asciz "/path" # string offset=41
+.Linfo_string3:
+ .asciz "A" # string offset=87
+.Linfo_string4:
+ .asciz "bar" # string offset=89
+.Linfo_string5:
+ .asciz "int" # string offset=93
+.Linfo_string6:
+ .asciz "_ZN1A3barE" # string offset=97
+.Linfo_string7:
+ .asciz "Z" # string offset=108
+.Linfo_string8:
+ .asciz "_ZN1Z3barE" # string offset=110
+
+.section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 14 # DW_FORM_strp
+ .ascii "\264B" # DW_AT_GNU_pubnames
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+
+ .byte 2 # Abbreviation Code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+
+ .byte 3 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+
+ .byte 4 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long 96 # Length of Unit
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+
+ .byte 1 # Abbrev [1] 0xb:0x59 DW_TAG_compile_unit
+ .long .Linfo_string0 # DW_AT_producer
+ .short 4 # DW_AT_language
+ .long .Linfo_string1 # DW_AT_name
+ .long 0 # DW_AT_stmt_list
+ .long .Linfo_string2 # DW_AT_comp_dir
+ # DW_AT_GNU_pubnames
+
+ .byte 2 # Abbrev [2] 0x1e:0x1f DW_TAG_namespace
+ .long .Linfo_string3 # DW_AT_name
+
+ .byte 3 # Abbrev [3] 0x23:0x19 DW_TAG_variable
+ .long .Linfo_string4 # DW_AT_name
+ .long 61 # DW_AT_type
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .byte 9 # DW_AT_location
+ .byte 3
+ .quad _ZN1A3barE
+ .long .Linfo_string6 # DW_AT_linkage_name
+ .byte 0 # End Of Children Mark
+
+ .byte 4 # Abbrev [4] 0x3d:0x7 DW_TAG_base_type
+ .long .Linfo_string5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+
+ .byte 2 # Abbrev [2] 0x44:0x1f DW_TAG_namespace
+ .long .Linfo_string7 # DW_AT_name
+
+ .byte 3 # Abbrev [3] 0x49:0x19 DW_TAG_variable
+ .long .Linfo_string4 # DW_AT_name
+ .long 61 # DW_AT_type
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .byte 9 # DW_AT_location
+ .byte 3
+ .quad _ZN1Z3barE
+ .long .Linfo_string8 # DW_AT_linkage_name
+
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
diff --git a/test/ELF/conflict.s b/test/ELF/conflict.s
index 4318759cbc11..cbe1b5b8845a 100644
--- a/test/ELF/conflict.s
+++ b/test/ELF/conflict.s
@@ -34,7 +34,7 @@
# ARCHIVE-NEXT: >>> defined at {{.*}}:(.text+0x0) in archive {{.*}}.a
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/conflict-debug.s -o %t-dbg.o
-# RUN: not ld.lld %t-dbg.o %t-dbg.o -o %t-dbg 2>&1 | FileCheck -check-prefix=DBGINFO %s
+# RUN: not ld.lld %t-dbg.o %t-dbg.o -o /dev/null 2>&1 | FileCheck -check-prefix=DBGINFO %s
# DBGINFO: duplicate symbol: zed
# DBGINFO-NEXT: >>> defined at conflict-debug.s:4
diff --git a/test/ELF/copy-errors.s b/test/ELF/copy-errors.s
index 0af4638120d1..40f73178557d 100644
--- a/test/ELF/copy-errors.s
+++ b/test/ELF/copy-errors.s
@@ -7,12 +7,19 @@
// CHECK: cannot preempt symbol: bar
// CHECK: >>> defined in {{.*}}.so
// CHECK: >>> referenced by {{.*}}.o:(.text+0x1)
-// CHECK: symbol 'zed' defined in {{.*}}.so has no type
+
+// CHECK: error: symbol 'zed' has no type
+// CHECK-NEXT: >>> defined in {{.*}}.so
+// CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x6)
// RUN: not ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck %s --check-prefix=NOINHIBIT
-// NOINHIBIT: warning: symbol 'zed' defined in {{.*}}.so has no type
+// NOINHIBIT: warning: symbol 'zed' has no type
+// NOINHIBIT-NEXT: >>> defined in {{.*}}.so
+// NOINHIBIT-NEXT: >>> referenced by {{.*}}.o:(.text+0x6)
.global _start
_start:
-call bar
-call zed
+.byte 0xe8
+.long bar - .
+.byte 0xe8
+.long zed - .
diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s
index 70439853c7c1..a5508932d035 100644
--- a/test/ELF/copy-in-shared.s
+++ b/test/ELF/copy-in-shared.s
@@ -2,9 +2,9 @@
// 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
+// RUN: not ld.lld %t2.o %t1.so -o /dev/null -shared 2>&1 | FileCheck %s
-// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.so
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/copy-rel-corrupted.s b/test/ELF/copy-rel-corrupted.s
index 3cdad7cf8037..76f64fa7725c 100644
--- a/test/ELF/copy-rel-corrupted.s
+++ b/test/ELF/copy-rel-corrupted.s
@@ -1,10 +1,11 @@
+// REQUIRES: x86
// 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
+// RUN: not ld.lld %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s
// CHECK: error: cannot create a copy relocation for symbol x
.global _start
_start:
- call x
+ .long x - .
diff --git a/test/ELF/copy-rel-pie-error.s b/test/ELF/copy-rel-pie-error.s
index 6f7677e25e3a..379442e1176c 100644
--- a/test/ELF/copy-rel-pie-error.s
+++ b/test/ELF/copy-rel-pie-error.s
@@ -1,13 +1,14 @@
+// REQUIRES: x86
// 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
+// RUN: not ld.lld %t.o %t2.so -o /dev/null -pie 2>&1 | FileCheck %s
-// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: bar
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: bar in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.so
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
-// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.so
// CHECK: >>> referenced by {{.*}}.o:(.text+0x8)
diff --git a/test/ELF/copy-rel-pie.s b/test/ELF/copy-rel-pie.s
index dcccf8e30b1d..9bf91595db12 100644
--- a/test/ELF/copy-rel-pie.s
+++ b/test/ELF/copy-rel-pie.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
@@ -7,8 +8,10 @@
.global _start
_start:
- call bar
- call foo
+ .byte 0xe8
+ .long bar - . -4
+ .byte 0xe8
+ .long foo - . -4
// CHECK: Name: .plt
// CHECK-NEXT: Type: SHT_PROGBITS
diff --git a/test/ELF/copy-rel-version.s b/test/ELF/copy-rel-version.s
new file mode 100644
index 000000000000..29fae8ecbb05
--- /dev/null
+++ b/test/ELF/copy-rel-version.s
@@ -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/copy-rel-version.s -o %t1.o
+// RUN: echo "v1 {}; v2 {};" > %t.ver
+// RUN: ld.lld %t1.o -shared -soname t1.so --version-script=%t.ver -o %t1.so
+// RUN: ld.lld %t.o %t1.so -o %t
+// RUN: llvm-readobj -t %t | FileCheck %s
+
+.global _start
+_start:
+ leaq foo, %rax
+
+// CHECK: Name: foo (
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 8
diff --git a/test/ELF/copy-relocation-zero-abs-addr.s b/test/ELF/copy-relocation-zero-abs-addr.s
new file mode 100644
index 000000000000..fae963e9bd9e
--- /dev/null
+++ b/test/ELF/copy-relocation-zero-abs-addr.s
@@ -0,0 +1,44 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-relocation-zero-abs-addr.s -o %t.o
+// RUN: ld.lld -shared -o %t2.so %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o
+// RUN: ld.lld %t2.so %t3.o -o %t4
+// RUN: llvm-readobj -symbols %t2.so | FileCheck -check-prefix=ABSADDR %s
+// RUN: llvm-readobj -s -r --expand-relocs %t4 | FileCheck %s
+
+// This tests that symbols with absolute addresses are properly
+// handled. Normal DSO symbols are handled as usual.
+
+.text
+.globl _start
+_start:
+ movl $5, foo
+
+// ABSADDR: Name: ver1
+// ABSADDR-NEXT: Value: 0x0
+// ABSADDR-NEXT: Size: 0
+// ABSADDR-NEXT: Binding: Global
+// ABSADDR-NEXT: Type: None
+// ABSADDR-NEXT: Other: 0
+// ABSADDR-NEXT: Section: Absolute (0xFFF1)
+// ABSADDR-NEXT: }
+// ABSADDR-NEXT: Symbol {
+// ABSADDR-NEXT: Name: ver2
+// ABSADDR-NEXT: Value: 0x0
+// ABSADDR-NEXT: Size: 0
+// ABSADDR-NEXT: Binding: Global
+// ABSADDR-NEXT: Type: None
+// ABSADDR-NEXT: Other: 0
+// ABSADDR-NEXT: Section: Absolute (0xFFF1)
+// ABSADDR-NEXT: }
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section (5) .rela.dyn {
+// CHECK-NEXT: Relocation {
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Type: R_X86_64_COPY
+// CHECK-NEXT: Symbol: foo
+// CHECK-NEXT: Addend:
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
diff --git a/test/ELF/copy-relocation-zero-nonabs-addr.s b/test/ELF/copy-relocation-zero-nonabs-addr.s
new file mode 100644
index 000000000000..50876056b256
--- /dev/null
+++ b/test/ELF/copy-relocation-zero-nonabs-addr.s
@@ -0,0 +1,29 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-relocation-zero-nonabs-addr.s -o %t1.o
+// RUN: ld.lld -Ttext=0 -o %t2.so --script=%p/Inputs/copy-relocation-zero-nonabs-addr.script %t1.o -shared
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o
+// RUN: ld.lld %t2.so %t3.o -o %t4
+// RUN: llvm-readobj --symbols %t2.so | FileCheck --check-prefix=CHECKSO %s
+// RUN: llvm-readobj --symbols %t4 | FileCheck %s
+
+.text
+.globl _start
+_start:
+ movl $5, foo
+
+// Make sure foo has st_value == 0.
+// CHECKSO: Name: foo
+// CHECKSO-NEXT: Value: 0x0
+// CHECKSO-NEXT: Size: 4
+// CHECKSO-NEXT: Binding: Global
+// CHECKSO-NEXT: Type: Object
+// CHECKSO-NEXT: Other: 0
+// CHECKSO-NEXT: Section: .text
+
+// When foo has st_value == 0, it carries the section alignment.
+// In this case, section alignment is 2^10, 0x202400 meets the requirement.
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x202400
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
diff --git a/test/ELF/corrupted-version-reference.s b/test/ELF/corrupted-version-reference.s
index d37f272f445d..203dc2afd8a1 100644
--- a/test/ELF/corrupted-version-reference.s
+++ b/test/ELF/corrupted-version-reference.s
@@ -1,6 +1,6 @@
-# RUN: llvm-mc -triple=mips64-unknown-freebsd %s -filetype=obj -o %t.o
-# RUN: not ld.lld %t.o %S/Inputs/corrupt-version-reference.so -o %t.exe 2>&1 | FileCheck %s
# REQUIRES: mips
+# RUN: llvm-mc -triple=mips64-unknown-freebsd %s -filetype=obj -o %t.o
+# RUN: not ld.lld %t.o %S/Inputs/corrupt-version-reference.so -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: corrupt input file: version definition index 9 for symbol __cxa_finalize is out of bounds
# CHECK: >>> defined in {{.+}}/corrupt-version-reference.so
diff --git a/test/ELF/cref.s b/test/ELF/cref.s
new file mode 100644
index 000000000000..2a82f4252e84
--- /dev/null
+++ b/test/ELF/cref.s
@@ -0,0 +1,33 @@
+// REQUIRES: x86
+
+// RUN: echo '.global foo; foo:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t1.o
+// RUN: echo '.global foo, bar; bar:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+// RUN: echo '.global zed; zed:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %ta.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %ta.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o
+// RUN: ld.lld -shared -o %t1.so %t1.o
+// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o %t.a -gc-sections -cref | FileCheck -strict-whitespace %s
+
+// CHECK: Symbol File
+// CHECK-NEXT: bar {{.*}}2.o
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NEXT: foo {{.*}}1.so
+// CHECK-NEXT: {{.*}}2.o
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NEXT: _start {{.*}}3.o
+// CHECK-NEXT: baz {{.*}}3.o
+// CHECK-NEXT: zed {{.*}}.a({{.*}}a.o)
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NOT: discarded
+
+.global _start, foo, bar, baz, discarded
+_start:
+ call foo
+ call bar
+ call zed
+localsym:
+baz:
+
+.section .text.a,"ax",@progbits
+discarded:
diff --git a/test/ELF/ctors_dtors_priority.s b/test/ELF/ctors_dtors_priority.s
index fcddcbb020f3..203bf247aa34 100644
--- a/test/ELF/ctors_dtors_priority.s
+++ b/test/ELF/ctors_dtors_priority.s
@@ -1,3 +1,4 @@
+// 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 \
// RUN: %p/Inputs/ctors_dtors_priority1.s -o %t-crtbegin.o
@@ -7,7 +8,6 @@
// 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:
diff --git a/test/ELF/defined-tls_get_addr.s b/test/ELF/defined-tls_get_addr.s
index 509c293cca1d..66ec01597566 100644
--- a/test/ELF/defined-tls_get_addr.s
+++ b/test/ELF/defined-tls_get_addr.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
-// RUN: ld.lld %t.o -o %t
+// RUN: ld.lld %t.o -o /dev/null
// Don't error if __tls_get_addr is defined.
diff --git a/test/ELF/defsym-reserved-syms.s b/test/ELF/defsym-reserved-syms.s
new file mode 100644
index 000000000000..fdab00fed66b
--- /dev/null
+++ b/test/ELF/defsym-reserved-syms.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t %t.o --defsym=foo2=etext
+# RUN: llvm-readobj -t -s %t | FileCheck %s
+
+## Check 'foo2' value is equal to value of 'etext'.
+# CHECK: Symbol {
+# CHECK: Name: foo2
+# CHECK-NEXT: Value: 0x[[VAL:.*]]
+# CHECK: Symbol {
+# CHECK: Name: etext
+# CHECK-NEXT: Value: 0x[[VAL]]
+
+## Check 'foo2' value set correctly when using
+## reserved symbol 'etext' in expression.
+# RUN: ld.lld -o %t %t.o --defsym=foo2=etext+2
+# RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=EXPR
+# EXPR: Symbol {
+# EXPR: Name: foo2
+# EXPR-NEXT: Value: 0x201007
+# EXPR: Symbol {
+# EXPR: Name: etext
+# EXPR-NEXT: Value: 0x201005
+
+.globl foo1
+ foo1 = 0x123
+
+.global _start
+_start:
+ movl $foo2, %edx
diff --git a/test/ELF/discard-locals.s b/test/ELF/discard-locals.s
index 9deaccff11c7..50cf5a04e985 100644
--- a/test/ELF/discard-locals.s
+++ b/test/ELF/discard-locals.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/discard-merge-locals.s b/test/ELF/discard-merge-locals.s
index 01b4d337cb2d..20be35c6e4e8 100644
--- a/test/ELF/discard-merge-locals.s
+++ b/test/ELF/discard-merge-locals.s
@@ -1,7 +1,7 @@
+// 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 -t %t2 | FileCheck %s
-// REQUIRES: x86
leaq .L.str(%rip), %rdi
diff --git a/test/ELF/discard-none.s b/test/ELF/discard-none.s
index 89e06fd7b7e4..4a42639c63f1 100644
--- a/test/ELF/discard-none.s
+++ b/test/ELF/discard-none.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/dont-export-hidden.s b/test/ELF/dont-export-hidden.s
index 8088c8d94d89..161e342bea84 100644
--- a/test/ELF/dont-export-hidden.s
+++ b/test/ELF/dont-export-hidden.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/driver.test b/test/ELF/driver.test
index ac324cbaac45..20bc79509725 100644
--- a/test/ELF/driver.test
+++ b/test/ELF/driver.test
@@ -35,25 +35,35 @@
# 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 --gdb-index together
+# RUN: not ld.lld -r --gdb-index %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: -r and --gdb-index 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
+# RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: -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
+# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: -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
+# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR7 %s
+# ERR7: -shared and -pie may not be used together
## "--output=foo" is equivalent to "-o foo".
-# RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR7 %s
-# ERR7: cannot open output file /no/such/file
+# RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s
+# ERR8: cannot open output file /no/such/file
## "-output=foo" is equivalent to "-o utput=foo".
-# RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s
-# ERR8: cannot open output file utput=/no/such/file
+# RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR9 %s
+# ERR9: cannot open output file utput=/no/such/file
+
+# RUN: not ld.lld %t -z foo 2>&1 | FileCheck -check-prefix=ERR10 %s
+# ERR10: unknown -z value: foo
+
+# RUN: not ld.lld %t -z max-page-size 2>&1 | FileCheck -check-prefix=ERR11 %s
+# ERR11: unknown -z value: max-page-size
.globl _start
_start:
diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s
index 431f83df7ab3..e160e0600378 100644
--- a/test/ELF/dt_flags.s
+++ b/test/ELF/dt_flags.s
@@ -2,19 +2,24 @@
# 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 nodlopen -z origin -Bsymbolic %t %t.so -o %t1
-# RUN: ld.lld %t %t.so -o %t2
+
+# RUN: ld.lld -z initfirst -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1
# RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s
+
+# RUN: ld.lld %t %t.so -o %t2
+# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+# RUN: ld.lld -z lazy %t %t.so -o %t2
# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
# FLAGS: DynamicSection [
# FLAGS: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
-# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN
+# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE INITFIRST NOOPEN ORIGIN
# FLAGS: ]
# CHECK: DynamicSection [
-# CHECK-NOT: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
-# CHECK-NOT: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN
+# CHECK-NOT: FLAGS
+# CHECK-NOT: FLAGS_1
# CHECK: ]
.globl _start
diff --git a/test/ELF/duplicated-synthetic-sym.s b/test/ELF/duplicated-synthetic-sym.s
index 92de33ec6278..bc4f5cf7650a 100644
--- a/test/ELF/duplicated-synthetic-sym.s
+++ b/test/ELF/duplicated-synthetic-sym.s
@@ -1,11 +1,17 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: cd %S
-// RUN: not ld.lld %t.o --format=binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s
-// RUN: not ld.lld %t.o --format binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s
+// RUN: rm -rf %t.dir
+// RUN: mkdir %t.dir
+// RUN: cd %t.dir
+// RUN: echo > file.bin
-// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start
-// CHECK: defined at <internal>:(.data+0x0)
+// RUN: not ld.lld %t.o --format=binary file.bin -o %t.elf 2>&1 | FileCheck %s
+// RUN: not ld.lld %t.o --format binary file.bin -o %t.elf 2>&1 | FileCheck %s
- .globl _binary_duplicated_synthetic_sym_s_start
-_binary_duplicated_synthetic_sym_s_start:
- .long 0
+// CHECK: duplicate symbol: _binary_file_bin_start
+// CHECK-NEXT: defined at {{.*}}.o:(.text+0x0)
+// CHECK-NEXT: defined at file.bin:(.data+0x0)
+
+.globl _binary_file_bin_start
+_binary_file_bin_start:
+ .long 0
diff --git a/test/ELF/dynamic-got-rela.s b/test/ELF/dynamic-got-rela.s
index 0aeb6d477a26..b46afaae0fef 100644
--- a/test/ELF/dynamic-got-rela.s
+++ b/test/ELF/dynamic-got-rela.s
@@ -1,24 +1,45 @@
// 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 -l -section-data %t.so | FileCheck %s
+// RUN: ld.lld %t.o -o %t.so -shared --apply-dynamic-relocs
+// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s
+// RUN: ld.lld %t.o -o %t2.so -shared
+// RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s
+// RUN: ld.lld %t.o -o %t2.so -shared --no-apply-dynamic-relocs
+// RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s
-// CHECK: Name: .got
-// CHECK-NEXT: Type: SHT_PROGBITS
-// CHECK-NEXT: Flags [
-// CHECK-NEXT: SHF_ALLOC
-// CHECK-NEXT: SHF_WRITE
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x[[GOT:.*]]
-// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size:
-// CHECK-NEXT: Link:
-// CHECK-NEXT: Info:
-// CHECK-NEXT: AddressAlignment:
-// CHECK-NEXT: EntrySize:
-// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 00000000 00000000 |
-// CHECK-NEXT: )
+// APPLYDYNREL: Name: .got
+// APPLYDYNREL-NEXT: Type: SHT_PROGBITS
+// APPLYDYNREL-NEXT: Flags [
+// APPLYDYNREL-NEXT: SHF_ALLOC
+// APPLYDYNREL-NEXT: SHF_WRITE
+// APPLYDYNREL-NEXT: ]
+// APPLYDYNREL-NEXT: Address: 0x[[GOT:.*]]
+// APPLYDYNREL-NEXT: Offset:
+// APPLYDYNREL-NEXT: Size:
+// APPLYDYNREL-NEXT: Link:
+// APPLYDYNREL-NEXT: Info:
+// APPLYDYNREL-NEXT: AddressAlignment:
+// APPLYDYNREL-NEXT: EntrySize:
+// APPLYDYNREL-NEXT: SectionData (
+// APPLYDYNREL-NEXT: 0000: 00200000 00000000 |
+// APPLYDYNREL-NEXT: )
+
+// NOAPPLYDYNREL: Name: .got
+// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS
+// NOAPPLYDYNREL-NEXT: Flags [
+// NOAPPLYDYNREL-NEXT: SHF_ALLOC
+// NOAPPLYDYNREL-NEXT: SHF_WRITE
+// NOAPPLYDYNREL-NEXT: ]
+// NOAPPLYDYNREL-NEXT: Address: 0x[[GOT:.*]]
+// NOAPPLYDYNREL-NEXT: Offset:
+// NOAPPLYDYNREL-NEXT: Size:
+// NOAPPLYDYNREL-NEXT: Link:
+// NOAPPLYDYNREL-NEXT: Info:
+// NOAPPLYDYNREL-NEXT: AddressAlignment:
+// NOAPPLYDYNREL-NEXT: EntrySize:
+// NOAPPLYDYNREL-NEXT: SectionData (
+// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 |
+// NOAPPLYDYNREL-NEXT: )
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
diff --git a/test/ELF/dynamic-got.s b/test/ELF/dynamic-got.s
index 385394b9d342..844e4f48b3f7 100644
--- a/test/ELF/dynamic-got.s
+++ b/test/ELF/dynamic-got.s
@@ -3,6 +3,23 @@
// RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared
// RUN: llvm-readobj -s -l -section-data -r %t.so | FileCheck %s
+// 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:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 00300000 00000000 00000000
+// CHECK-NEXT: )
+
// CHECK: Name: .got
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
@@ -17,19 +34,19 @@
// CHECK-NEXT: AddressAlignment:
// CHECK-NEXT: EntrySize:
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 00200000 |
+// CHECK-NEXT: 0000: 00300000
// CHECK-NEXT: )
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rel.dyn {
-// CHECK-NEXT: 0x2050 R_386_RELATIVE - 0x0
+// CHECK-NEXT: 0x3050 R_386_RELATIVE - 0x0
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK: Type: PT_DYNAMIC
-// CHECK-NEXT: Offset: 0x2000
-// CHECK-NEXT: VirtualAddress: 0x2000
-// CHECK-NEXT: PhysicalAddress: 0x2000
+// CHECK-NEXT: Offset: 0x3000
+// CHECK-NEXT: VirtualAddress: 0x3000
+// CHECK-NEXT: PhysicalAddress: 0x3000
calll .L0$pb
.L0$pb:
diff --git a/test/ELF/dynamic-linker.s b/test/ELF/dynamic-linker.s
new file mode 100644
index 000000000000..3faf8e8a169e
--- /dev/null
+++ b/test/ELF/dynamic-linker.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t1.o
+# RUN: ld.lld -shared %t1.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: ld.lld --dynamic-linker foo %t.o %t.so -o %t
+# RUN: llvm-readelf -program-headers %t | FileCheck %s
+
+# RUN: ld.lld --dynamic-linker=foo %t.o %t.so -o %t
+# RUN: llvm-readelf -program-headers %t | FileCheck %s
+
+# CHECK: [Requesting program interpreter: foo]
+
+# RUN: ld.lld %t.o %t.so -o %t
+# RUN: llvm-readelf -program-headers %t | FileCheck --check-prefix=NO %s
+
+# RUN: ld.lld --dynamic-linker foo --no-dynamic-linker %t.o %t.so -o %t
+# RUN: llvm-readelf -program-headers %t | FileCheck --check-prefix=NO %s
+
+# NO-NOT: PT_INTERP
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/dynamic-list-archive.s b/test/ELF/dynamic-list-archive.s
new file mode 100644
index 000000000000..5879bf1b0a57
--- /dev/null
+++ b/test/ELF/dynamic-list-archive.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: rm -f %t.a
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t1.o
+# RUN: llvm-ar rcs %t.a %t1.o
+
+# RUN: echo "{ foo; };" > %t.list
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: ld.lld -shared -o %t.so --dynamic-list %t.list %t.a %t2.o
+
+# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s
+# CHECK-NOT: foo
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/dynamic-list-extern.s b/test/ELF/dynamic-list-extern.s
index dfeb31d4fc07..bb06cebf5f52 100644
--- a/test/ELF/dynamic-list-extern.s
+++ b/test/ELF/dynamic-list-extern.s
@@ -4,12 +4,8 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo '{ \
-# RUN: extern "C" { \
-# RUN: foo; \
-# RUN: }; \
-# RUN: extern "C++" { \
-# RUN: bar; \
-# RUN: }; \
-# RUN: };' > %t.list
+# RUN: echo '{ extern "C" { foo; }; extern "C++" { bar; }; };' > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t.o -shared -o %t.so
+
+# RUN: echo '{ extern "C" { foo }; extern "C++" { bar }; };' > %t.list
# RUN: ld.lld --dynamic-list %t.list %t.o -shared -o %t.so
diff --git a/test/ELF/dynamic-no-rosegment.s b/test/ELF/dynamic-no-rosegment.s
index e5ad26e3fa44..f2b5f352d967 100644
--- a/test/ELF/dynamic-no-rosegment.s
+++ b/test/ELF/dynamic-no-rosegment.s
@@ -7,9 +7,9 @@
# CHECK-NEXT: Tag Type Name/Value
# CHECK-NEXT: 0x0000000000000006 SYMTAB 0x120
# CHECK-NEXT: 0x000000000000000B SYMENT 24 (bytes)
-# CHECK-NEXT: 0x0000000000000005 STRTAB 0x1D0
+# CHECK-NEXT: 0x0000000000000005 STRTAB 0x1D8
# CHECK-NEXT: 0x000000000000000A STRSZ 1 (bytes)
# CHECK-NEXT: 0x000000006FFFFEF5 GNU_HASH 0x138
-# CHECK-NEXT: 0x0000000000000004 HASH 0x150
+# CHECK-NEXT: 0x0000000000000004 HASH 0x154
# CHECK-NEXT: 0x0000000000000000 NULL 0x0
# CHECK-NEXT: ]
diff --git a/test/ELF/dynamic-reloc-in-ro.s b/test/ELF/dynamic-reloc-in-ro.s
index ecdbfeb6658e..920f1d5fe349 100644
--- a/test/ELF/dynamic-reloc-in-ro.s
+++ b/test/ELF/dynamic-reloc-in-ro.s
@@ -1,8 +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
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
-// CHECK: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC
+// CHECK: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK-NEXT: >>> defined in {{.*}}.o
// CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/dynamic-reloc-index.s b/test/ELF/dynamic-reloc-index.s
index 47e8c6c4ef7d..0c14d3454571 100644
--- a/test/ELF/dynamic-reloc-index.s
+++ b/test/ELF/dynamic-reloc-index.s
@@ -1,3 +1,4 @@
+// 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/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
diff --git a/test/ELF/dynamic-reloc-weak.s b/test/ELF/dynamic-reloc-weak.s
index b4da2e552e11..8e4840bb4c4b 100644
--- a/test/ELF/dynamic-reloc-weak.s
+++ b/test/ELF/dynamic-reloc-weak.s
@@ -1,9 +1,9 @@
+// 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/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:
diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s
index 4d95e41fb803..3a957ac0d05e 100644
--- a/test/ELF/dynamic-reloc.s
+++ b/test/ELF/dynamic-reloc.s
@@ -1,10 +1,10 @@
+// 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/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 --hash-style=sysv %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
diff --git a/test/ELF/dynstr-no-rosegment.s b/test/ELF/dynstr-no-rosegment.s
index 0e12721dac44..bad6300801e2 100644
--- a/test/ELF/dynstr-no-rosegment.s
+++ b/test/ELF/dynstr-no-rosegment.s
@@ -1,6 +1,6 @@
+# REQUIRES: x86
# Verify that a .dynstr in the .text segment has null byte terminators
-# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld %t.o -no-rosegment -o %t.so -shared
# RUN: llvm-objdump %t.so -s -j .dynstr | FileCheck %s
diff --git a/test/ELF/edata-etext.s b/test/ELF/edata-etext.s
index 2358399857de..52070cbc4ce3 100644
--- a/test/ELF/edata-etext.s
+++ b/test/ELF/edata-etext.s
@@ -10,10 +10,11 @@
## 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.
+## 4) Addresses of _edata == edata, _end == end and _etext == etext.
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000001 0000000000201000 TEXT DATA
+# CHECK-NEXT: 1 .text 00000001 0000000000201000 TEXT
# CHECK-NEXT: 2 .data 00000002 0000000000202000 DATA
# CHECK-NEXT: 3 .bss 00000006 0000000000202004 BSS
# CHECK: SYMBOL TABLE:
@@ -22,6 +23,9 @@
# CHECK-NEXT: 000000000020200a .bss 00000000 _end
# CHECK-NEXT: 0000000000201001 .text 00000000 _etext
# CHECK-NEXT: 0000000000201000 .text 00000000 _start
+# CHECK-NEXT: 0000000000202002 .data 00000000 edata
+# CHECK-NEXT: 000000000020200a .bss 00000000 end
+# CHECK-NEXT: 0000000000201001 .text 00000000 etext
# RUN: ld.lld -r %t.o -o %t2
# RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=RELOCATABLE
@@ -29,7 +33,7 @@
# RELOCATABLE-NEXT: 0000000000000000 *UND* 00000000 _end
# RELOCATABLE-NEXT: 0000000000000000 *UND* 00000000 _etext
-.global _start,_end,_etext,_edata
+.global _start,_end,_etext,_edata,end,etext,edata
.text
_start:
nop
diff --git a/test/ELF/eh-frame-dyn-rel.s b/test/ELF/eh-frame-dyn-rel.s
index 289e6c0150d2..f54e62b5eedc 100644
--- a/test/ELF/eh-frame-dyn-rel.s
+++ b/test/ELF/eh-frame-dyn-rel.s
@@ -1,8 +1,8 @@
// 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
+// RUN: not ld.lld %t.o %t.o -o /dev/null -shared 2>&1 | FileCheck %s
-// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
// CHECK: >>> defined in {{.*}}.o
// CHECK: >>> referenced by {{.*}}.o:(.eh_frame+0x12)
diff --git a/test/ELF/eh-frame-hdr-abs-fde.s b/test/ELF/eh-frame-hdr-abs-fde.s
index c3dc862ceb49..7f75058d4b35 100644
--- a/test/ELF/eh-frame-hdr-abs-fde.s
+++ b/test/ELF/eh-frame-hdr-abs-fde.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# 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.
@@ -6,8 +7,6 @@
# 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: 10128 011b033b 00000010 00000001 0000fed8
# ^-- 0x20000 - 0x10138
diff --git a/test/ELF/eh-frame-hdr-augmentation.s b/test/ELF/eh-frame-hdr-augmentation.s
index 135f8119662a..934f9200a27c 100644
--- a/test/ELF/eh-frame-hdr-augmentation.s
+++ b/test/ELF/eh-frame-hdr-augmentation.s
@@ -11,6 +11,7 @@
// CHECK-NEXT: Code alignment factor: 1
// CHECK-NEXT: Data alignment factor: -8
// CHECK-NEXT: Return address column: 16
+// CHECK-NEXT: Personality Address: 00000dad
// CHECK-NEXT: Augmentation data:
// CHECK: DW_CFA_def_cfa: reg7 +8
@@ -19,6 +20,7 @@
// CHECK-NEXT: DW_CFA_nop:
// CHECK: 00000020 00000014 00000024 FDE cie=00000024 pc=00000d98...00000d98
+// CHECK-NEXT: LSDA Address: 00000d8f
// CHECK-NEXT: DW_CFA_nop:
// CHECK-NEXT: DW_CFA_nop:
// CHECK-NEXT: DW_CFA_nop:
diff --git a/test/ELF/eh-frame-hdr-icf-fde.s b/test/ELF/eh-frame-hdr-icf-fde.s
index 54c2cd8bf8c9..68de65d5724c 100644
--- a/test/ELF/eh-frame-hdr-icf-fde.s
+++ b/test/ELF/eh-frame-hdr-icf-fde.s
@@ -52,7 +52,7 @@
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x200178
# CHECK-NEXT: Offset: 0x178
-# CHECK-NEXT: Size: 72
+# CHECK-NEXT: Size: 76
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 8
@@ -62,7 +62,7 @@
# CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000
# CHECK-NEXT: 0020: 680E0000 01000000 00000000 00000000
# CHECK-NEXT: 0030: 14000000 34000000 520E0000 01000000
-# CHECK-NEXT: 0040: 00000000 00000000
+# CHECK-NEXT: 0040: 00000000 00000000 00000000
# CHECK-NEXT: )
# CHECK-NEXT: }
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
index 4498d7d30eaa..0c33bc6dde3e 100644
--- a/test/ELF/eh-frame-hdr.s
+++ b/test/ELF/eh-frame-hdr.s
@@ -60,7 +60,7 @@ _start:
// HDR-NEXT: Size: 36
// HDR-NEXT: Link: 0
// HDR-NEXT: Info: 0
-// HDR-NEXT: AddressAlignment: 1
+// HDR-NEXT: AddressAlignment: 4
// HDR-NEXT: EntrySize: 0
// HDR-NEXT: SectionData (
// HDR-NEXT: 0000: 011B033B 24000000 03000000 A80E0000
@@ -92,7 +92,7 @@ _start:
// HDR-NEXT: ]
// HDR-NEXT: Address: 0x200180
// HDR-NEXT: Offset: 0x180
-// HDR-NEXT: Size: 96
+// HDR-NEXT: Size: 100
// HDR-NEXT: Link: 0
// HDR-NEXT: Info: 0
// HDR-NEXT: AddressAlignment: 8
@@ -104,6 +104,7 @@ _start:
// HDR-NEXT: 0030: 14000000 34000000 490E0000 01000000
// HDR-NEXT: 0040: 00000000 00000000 14000000 4C000000
// HDR-NEXT: 0050: 320E0000 01000000 00000000 00000000
+// HDR-NEXT: 0060: 00000000
// HDR-NEXT: )
// CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
// FDE(1): 14000000 1C000000 600E0000 01000000 00000000 00000000
@@ -130,5 +131,5 @@ _start:
// HDR-NEXT: Flags [
// HDR-NEXT: PF_R
// HDR-NEXT: ]
-// HDR-NEXT: Alignment: 1
+// HDR-NEXT: Alignment: 4
// HDR-NEXT: }
diff --git a/test/ELF/eh-frame-marker.s b/test/ELF/eh-frame-marker.s
index 30bac460ae25..f5696bdef36f 100644
--- a/test/ELF/eh-frame-marker.s
+++ b/test/ELF/eh-frame-marker.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
// RUN: llvm-readobj -t -s %t.so | FileCheck %s
diff --git a/test/ELF/eh-frame-merge.s b/test/ELF/eh-frame-merge.s
index 4b54c173c699..6731d90f844b 100644
--- a/test/ELF/eh-frame-merge.s
+++ b/test/ELF/eh-frame-merge.s
@@ -27,7 +27,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address:
// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size: 96
+// CHECK-NEXT: Size: 100
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 8
@@ -39,6 +39,7 @@
// CHECK-NEXT: 0030: 14000000 34000000 D20D0000 02000000 |
// CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000 |
// CHECK-NEXT: 0050: B90D0000 01000000 00000000 00000000 |
+// CHECK-NEXT: 0060: 00000000
// CHECK-NEXT: )
// CHECK: Name: foo
diff --git a/test/ELF/eh-frame-multilpe-cie.s b/test/ELF/eh-frame-multilpe-cie.s
index 12781ff5b6e9..a52e686d9d15 100644
--- a/test/ELF/eh-frame-multilpe-cie.s
+++ b/test/ELF/eh-frame-multilpe-cie.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// 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
+// RUN: ld.lld --eh-frame-hdr %t.o -o /dev/null -shared
// We would fail to parse multiple cies in the same file.
.cfi_startproc
diff --git a/test/ELF/eh-frame-negative-pcrel-sdata2.s b/test/ELF/eh-frame-negative-pcrel-sdata2.s
new file mode 100644
index 000000000000..30ee8560f0a3
--- /dev/null
+++ b/test/ELF/eh-frame-negative-pcrel-sdata2.s
@@ -0,0 +1,85 @@
+# REQUIRES: x86
+
+# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata2.
+# This situation can arise when .eh_frame is placed after .text.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script
+# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1001
+# CHECK-NEXT: Offset: 0x1001
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101
+# CHECK-NEXT: 0010: 1A000000 00000000 0C000000 1C000000
+# CHECK-NEXT: 0020: DFFFFFFF
+# ^
+# DFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20)
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame_hdr
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1030
+# CHECK-NEXT: Offset: 0x1030
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 011B033B CDFFFFFF 01000000 D0FFFFFF
+# CHECK-NEXT: 0010: E9FFFFFF
+# Header (always 4 bytes): 011B033B
+# CDFFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1030) - 4
+# 01000000 = 1 = the number of FDE pointers in the table.
+# D0FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1030)
+# E9FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1030)
+
+.text
+.global _start
+_start:
+ nop
+
+.section .eh_frame, "a"
+ .long 16 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x7A # Augmentation string: "zR"
+ .byte 0x52
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01 # LEB128
+ .byte 0x1A # DW_EH_PE_pcrel | DW_EH_PE_sdata2
+
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+
+ .long 10 # Size
+ .long 24 # ID
+fde:
+ .long _start - fde
+ .word 0
diff --git a/test/ELF/eh-frame-negative-pcrel-sdata4.s b/test/ELF/eh-frame-negative-pcrel-sdata4.s
new file mode 100644
index 000000000000..71b91cf1f4a6
--- /dev/null
+++ b/test/ELF/eh-frame-negative-pcrel-sdata4.s
@@ -0,0 +1,85 @@
+# REQUIRES: x86
+
+# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata4.
+# This situation can arise when .eh_frame is placed after .text.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script
+# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1001
+# CHECK-NEXT: Offset: 0x1001
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101
+# CHECK-NEXT: 0010: 1B000000 00000000 0C000000 1C000000
+# CHECK-NEXT: 0020: DFFFFFFF
+# ^
+# DFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20)
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame_hdr
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1030
+# CHECK-NEXT: Offset: 0x1030
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 011B033B CDFFFFFF 01000000 D0FFFFFF
+# CHECK-NEXT: 0010: E9FFFFFF
+# Header (always 4 bytes): 011B033B
+# CDFFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1030) - 4
+# 01000000 = 1 = the number of FDE pointers in the table.
+# D0FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1030)
+# E9FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1030)
+
+.text
+.global _start
+_start:
+ nop
+
+.section .eh_frame, "a"
+ .long 16 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x7A # Augmentation string: "zR"
+ .byte 0x52
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01 # LEB128
+ .byte 0x1B # DW_EH_PE_pcrel | DW_EH_PE_sdata4
+
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+
+ .long 12 # Size
+ .long 24 # ID
+fde:
+ .long _start - fde
+ .long 0
diff --git a/test/ELF/eh-frame-negative-pcrel-sdata8.s b/test/ELF/eh-frame-negative-pcrel-sdata8.s
new file mode 100644
index 000000000000..2c6c9f27cd38
--- /dev/null
+++ b/test/ELF/eh-frame-negative-pcrel-sdata8.s
@@ -0,0 +1,85 @@
+# REQUIRES: x86
+
+# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata8.
+# This situation can arise when .eh_frame is placed after .text.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script
+# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1001
+# CHECK-NEXT: Offset: 0x1001
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101
+# CHECK-NEXT: 0010: 1C000000 00000000 14000000 1C000000
+# CHECK-NEXT: 0020: DFFFFFFF FFFFFFFF
+# ^
+# DFFFFFFF FFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20)
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame_hdr
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1038
+# CHECK-NEXT: Offset: 0x1038
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 011B033B C5FFFFFF 01000000 C8FFFFFF
+# CHECK-NEXT: 0010: E1FFFFFF
+# Header (always 4 bytes): 011B033B
+# C5FFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1038) - 4
+# 01000000 = 1 = the number of FDE pointers in the table.
+# C8FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1038)
+# E1FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1038)
+
+.text
+.global _start
+_start:
+ nop
+
+.section .eh_frame, "a"
+ .long 16 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x7A # Augmentation string: "zR"
+ .byte 0x52
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01 # LEB128
+ .byte 0x1C # DW_EH_PE_pcrel | DW_EH_PE_sdata8
+
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+
+ .long 16 # Size
+ .long 24 # ID
+fde:
+ .quad _start - fde
+ .long 0
diff --git a/test/ELF/eh-frame-padding-no-rosegment.s b/test/ELF/eh-frame-padding-no-rosegment.s
index e106f2989d4b..222ce0da6ca9 100644
--- a/test/ELF/eh-frame-padding-no-rosegment.s
+++ b/test/ELF/eh-frame-padding-no-rosegment.s
@@ -7,6 +7,7 @@
.global bar
.hidden bar
bar:
+ ret
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
@@ -37,8 +38,7 @@ bar:
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s
// PHDR: Segment Sections
-// PHDR: .text
-// PHDR-SAME: .eh_frame
+// PHDR: .eh_frame {{.*}}.text
// Check that the CIE and FDE are padded with 0x00 and not 0xCC when the
// .eh_frame section is placed in the executable segment
@@ -58,7 +58,7 @@ bar:
// CHECK-NEXT: EntrySize:
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810
-// CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000
-// CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000
+// CHECK-NEXT: 0010: 061B2A00 00001B0C 07089001 00000000
+// CHECK-NEXT: 0020: 14000000 24000000 14000000 00000000
// CHECK-NEXT: 0030: 00000000 00000000
// CHECK-NEXT: )
diff --git a/test/ELF/eh-frame-pcrel-overflow.s b/test/ELF/eh-frame-pcrel-overflow.s
new file mode 100644
index 000000000000..9b88edab2a93
--- /dev/null
+++ b/test/ELF/eh-frame-pcrel-overflow.s
@@ -0,0 +1,33 @@
+# 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/eh-frame-pcrel-overflow.s -o %t1.o
+# RUN: ld.lld --eh-frame-hdr -Ttext=0x90000000 %t.o -o /dev/null
+# RUN: not ld.lld --eh-frame-hdr %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}.o:(.eh_frame): PC offset is too large: 0x90000eac
+
+.text
+.global _start
+_start:
+ ret
+
+.section .eh_frame, "a"
+ .long 12 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x52 # Augmentation string: 'R','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x00 # DW_EH_PE_absptr
+
+ .byte 0xFF
+
+ .long 12 # Size
+ .long 0x14 # ID
+ .quad _start + 0x70000000
diff --git a/test/ELF/eh-frame-rel.s b/test/ELF/eh-frame-rel.s
index a417dc126087..d633e6a082ec 100644
--- a/test/ELF/eh-frame-rel.s
+++ b/test/ELF/eh-frame-rel.s
@@ -1,6 +1,6 @@
// 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
+// RUN: ld.lld %t.o %t.o -o /dev/null -shared
// We used to try to read the relocations as RELA and error out
.cfi_startproc
diff --git a/test/ELF/eh-frame-value-format1.s b/test/ELF/eh-frame-value-format1.s
new file mode 100644
index 000000000000..a8bcffb4fe4f
--- /dev/null
+++ b/test/ELF/eh-frame-value-format1.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x14
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x04 # DW_EH_PE_udata8
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format2.s b/test/ELF/eh-frame-value-format2.s
new file mode 100644
index 000000000000..6d2d82e267c7
--- /dev/null
+++ b/test/ELF/eh-frame-value-format2.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x14
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x0C # DW_EH_PE_sdata8
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format3.s b/test/ELF/eh-frame-value-format3.s
new file mode 100644
index 000000000000..1f174ae60a0d
--- /dev/null
+++ b/test/ELF/eh-frame-value-format3.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x0A # DW_EH_PE_sdata2
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format4.s b/test/ELF/eh-frame-value-format4.s
new file mode 100644
index 000000000000..d10988a4fc86
--- /dev/null
+++ b/test/ELF/eh-frame-value-format4.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x02 # DW_EH_PE_udata2
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format5.s b/test/ELF/eh-frame-value-format5.s
new file mode 100644
index 000000000000..fd5b35a8b05e
--- /dev/null
+++ b/test/ELF/eh-frame-value-format5.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x14
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x08 # DW_EH_PE_signed
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format6.s b/test/ELF/eh-frame-value-format6.s
new file mode 100644
index 000000000000..ee76fa7a050f
--- /dev/null
+++ b/test/ELF/eh-frame-value-format6.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld --eh-frame-hdr %t -o /dev/null
+
+.section .eh_frame
+ .byte 0x14
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x00 # DW_EH_PE_absptr
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+ .byte 0xFF
+
+ .byte 0xFF
diff --git a/test/ELF/eh-frame-value-format7.s b/test/ELF/eh-frame-value-format7.s
new file mode 100644
index 000000000000..90543a2b72f2
--- /dev/null
+++ b/test/ELF/eh-frame-value-format7.s
@@ -0,0 +1,75 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+## Check we are able to handle DW_EH_PE_udata2 encoding.
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame_hdr
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2000
+# CHECK-NEXT: Offset: 0x2000
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 011B033B 10000000 01000000 34F2FFFF
+# CHECK-NEXT: 0010: 24000000
+# Header (always 4 bytes): 011B033B
+# 10000000 = .eh_frame(0x2014) - .eh_frame_hdr(0x2000) - 4
+# 01000000 = 1 = the number of FDE pointers in the table.
+# 34F2FFFF = foo(0x1000) - 0x234(addend) - .eh_frame_hdr(0x2000)
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2014
+# CHECK-NEXT: Offset: 0x2014
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 0C000000 00000000 01520001 010102FF
+# CHECK-NEXT: 0010: 0C000000 14000000 34120000 00000000
+# ^
+# ---> ADDR(foo) + 0x234 = 0x1234
+
+.text
+.global foo
+foo:
+ nop
+
+.section .eh_frame
+ .long 12 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x52 # Augmentation string: 'R','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x02 # DW_EH_PE_udata2
+
+ .byte 0xFF
+
+ .long 0x6 # Size
+ .long 0x14 # ID
+ .short foo + 0x234
diff --git a/test/ELF/eh-frame-value-format8.s b/test/ELF/eh-frame-value-format8.s
new file mode 100644
index 000000000000..60324706665e
--- /dev/null
+++ b/test/ELF/eh-frame-value-format8.s
@@ -0,0 +1,74 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+## Check we are able to handle DW_EH_PE_absptr encoding.
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame_hdr
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2000
+# CHECK-NEXT: Offset: 0x2000
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 011B033B 10000000 01000000 34F2FFFF
+# CHECK-NEXT: 0010: 24000000
+# Header (always 4 bytes): 011B033B
+# 10000000 = .eh_frame(0x2014) - .eh_frame_hdr(0x2000) - 4
+# 01000000 = 1 = the number of FDE pointers in the table.
+# 34F2FFFF = foo(0x1000) - 0x234(addend) - .eh_frame_hdr(0x2000)
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2014
+# CHECK-NEXT: Offset: 0x2014
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 0C000000 00000000 01520001 010100FF
+# CHECK-NEXT: 0010: 0C000000 14000000 34120000 00000000
+# ^
+# ---> ADDR(foo) + 0x234 = 0x1234
+.text
+.global foo
+foo:
+ nop
+
+.section .eh_frame, "ax"
+ .long 12 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x52 # Augmentation string: 'R','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x00 # DW_EH_PE_absptr
+
+ .byte 0xFF
+
+ .long 12 # Size
+ .long 0x14 # ID
+ .quad foo + 0x234
diff --git a/test/ELF/eh-frame-value-format9.s b/test/ELF/eh-frame-value-format9.s
new file mode 100644
index 000000000000..1b9ce6944eea
--- /dev/null
+++ b/test/ELF/eh-frame-value-format9.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld --eh-frame-hdr %t.o -o %t 2>&1 | FileCheck %s
+# CHECK: error: unknown FDE size encoding
+
+.section .eh_frame, "ax"
+ .long 12 # Size
+ .long 0x00 # ID
+ .byte 0x01 # Version.
+
+ .byte 0x52 # Augmentation string: 'R','\0'
+ .byte 0x00
+
+# Code and data alignment factors.
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+# Return address register.
+ .byte 0x01 # LEB128
+
+ .byte 0xFE # 'R' value: invalid <0xFE>
+
+ .byte 0xFF
+
+ .long 12 # Size
+ .long 0x14 # ID
+ .quad .eh_frame
diff --git a/test/ELF/ehframe-relocation.s b/test/ELF/ehframe-relocation.s
index 0213b1bebf83..4ab44c20f8ae 100644
--- a/test/ELF/ehframe-relocation.s
+++ b/test/ELF/ehframe-relocation.s
@@ -12,7 +12,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x200120
// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Size: 52
// CHECK-NOT: .eh_frame
// 0x200120 = 2097440
diff --git a/test/ELF/elf-header.s b/test/ELF/elf-header.s
new file mode 100644
index 000000000000..e188650f7311
--- /dev/null
+++ b/test/ELF/elf-header.s
@@ -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 %t1
+# RUN: llvm-readobj -file-headers %t1 | FileCheck %s
+
+# RUN: ld.lld %t.o -no-rosegment -o %t2
+# RUN: llvm-readobj -file-headers %t2 | FileCheck %s
+
+# 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: }
diff --git a/test/ELF/emit-relocs-eh-frame.s b/test/ELF/emit-relocs-eh-frame.s
new file mode 100644
index 000000000000..4df88585d341
--- /dev/null
+++ b/test/ELF/emit-relocs-eh-frame.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld --emit-relocs %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section {{.*}} .rela.eh_frame {
+# CHECK-NEXT: 0x{{.*}} R_X86_64_PC32 .text 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.text
+.globl foo
+foo:
+ .cfi_startproc
+ .cfi_endproc
diff --git a/test/ELF/emit-relocs-gc.s b/test/ELF/emit-relocs-gc.s
index 0741e78ab955..9379630e7bff 100644
--- a/test/ELF/emit-relocs-gc.s
+++ b/test/ELF/emit-relocs-gc.s
@@ -11,8 +11,8 @@
## .rela.text because we keep .text.
# RUN: ld.lld --gc-sections --emit-relocs --print-gc-sections %t.o -o %t \
# RUN: | FileCheck --check-prefix=MSG %s
-# MSG: removing unused section from '.bar' in file
-# MSG: removing unused section from '.rela.bar' in file
+# MSG: removing unused section {{.*}}.o:(.bar)
+# MSG: removing unused section {{.*}}.o:(.rela.bar)
# RUN: llvm-objdump %t -section-headers | FileCheck %s --check-prefix=GC
# GC-NOT: rela.bar
# GC: rela.text
diff --git a/test/ELF/emit-relocs-icf.s b/test/ELF/emit-relocs-icf.s
new file mode 100644
index 000000000000..59e003f38ead
--- /dev/null
+++ b/test/ELF/emit-relocs-icf.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld --emit-relocs --icf=all %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section {{.*}} .rela.text {
+# CHECK-NEXT: R_X86_64_32 .text 0x1
+# CHECK-NEXT: R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.section .text.fn,"ax",@progbits,unique,0
+.globl fn
+.type fn,@function
+fn:
+ nop
+
+bar:
+ movl $bar, %edx
+ callq fn@PLT
+ nop
+
+.section .text.fn2,"ax",@progbits,unique,1
+.globl fn2
+.type fn2,@function
+fn2:
+ nop
+
+foo:
+ movl $foo, %edx
+ callq fn2@PLT
+ nop
diff --git a/test/ELF/emit-relocs-shared.s b/test/ELF/emit-relocs-shared.s
index 65a12c15ee2e..cb87d9f84805 100644
--- a/test/ELF/emit-relocs-shared.s
+++ b/test/ELF/emit-relocs-shared.s
@@ -7,10 +7,10 @@
.quad foo
# CHECK: Relocations [
-# CHECK-NEXT: Section (4) .rela.dyn {
+# CHECK-NEXT: Section {{.*}} .rela.dyn {
# CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0
# CHECK-NEXT: }
-# CHECK-NEXT: Section (8) .rela.data {
+# CHECK-NEXT: Section {{.*}} .rela.data {
# CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/emit-relocs.s b/test/ELF/emit-relocs.s
index 95e70d80acf5..b91bb9abe182 100644
--- a/test/ELF/emit-relocs.s
+++ b/test/ELF/emit-relocs.s
@@ -13,7 +13,7 @@
# CHECK: Section {
# CHECK: Index: 2
-# CHECK-NEXT: Name: .rela.text
+# CHECK: Name: .rela.text
# CHECK-NEXT: Type: SHT_RELA
# CHECK-NEXT: Flags [
# CHECK-NEXT: SHF_INFO_LINK
diff --git a/test/ELF/empty-archive.s b/test/ELF/empty-archive.s
index ffb0a7814419..72232415a588 100644
--- a/test/ELF/empty-archive.s
+++ b/test/ELF/empty-archive.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
+// RUN: ld.lld -shared %t.o %t.a -o /dev/null
diff --git a/test/ELF/empty-ver2.s b/test/ELF/empty-ver2.s
new file mode 100644
index 000000000000..2aceee128ba3
--- /dev/null
+++ b/test/ELF/empty-ver2.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: mkdir -p %t.dir
+# RUN: cd %t.dir
+# 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: Symbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 0
+# CHECK-NEXT: Name: @
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Name: bar@@
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.global bar@
+bar@:
diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s
index 05efd0b94cb2..98f78b8ec1df 100644
--- a/test/ELF/emulation.s
+++ b/test/ELF/emulation.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86,ppc,mips,aarch64
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %tx64
# RUN: ld.lld -m elf_amd64_fbsd %tx64 -o %t2x64
# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=AMD64 %s
@@ -208,7 +209,8 @@
# PPC64-NEXT: Entry:
# PPC64-NEXT: ProgramHeaderOffset: 0x40
# PPC64-NEXT: SectionHeaderOffset:
-# PPC64-NEXT: Flags [ (0x0)
+# PPC64-NEXT: Flags [ (0x2)
+# PPC64-NEXT: 0x2
# PPC64-NEXT: ]
# PPC64-NEXT: HeaderSize: 64
# PPC64-NEXT: ProgramHeaderEntrySize: 56
@@ -218,6 +220,38 @@
# PPC64-NEXT: StringTableSectionIndex:
# PPC64-NEXT: }
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %tppc64le
+# RUN: ld.lld -m elf64lppc %tppc64le -o %t2ppc64le
+# RUN: llvm-readobj -file-headers %t2ppc64le | FileCheck --check-prefix=PPC64LE %s
+# RUN: ld.lld %tppc64le -o %t3ppc64le
+# RUN: llvm-readobj -file-headers %t3ppc64le | FileCheck --check-prefix=PPC64LE %s
+# PPC64LE: ElfHeader {
+# PPC64LE-NEXT: Ident {
+# PPC64LE-NEXT: Magic: (7F 45 4C 46)
+# PPC64LE-NEXT: Class: 64-bit (0x2)
+# PPC64LE-NEXT: DataEncoding: LittleEndian (0x1)
+# PPC64LE-NEXT: FileVersion: 1
+# PPC64LE-NEXT: OS/ABI: SystemV (0x0)
+# PPC64LE-NEXT: ABIVersion: 0
+# PPC64LE-NEXT: Unused: (00 00 00 00 00 00 00)
+# PPC64LE-NEXT: }
+# PPC64LE-NEXT: Type: Executable (0x2)
+# PPC64LE-NEXT: Machine: EM_PPC64 (0x15)
+# PPC64LE-NEXT: Version: 1
+# PPC64LE-NEXT: Entry:
+# PPC64LE-NEXT: ProgramHeaderOffset: 0x40
+# PPC64LE-NEXT: SectionHeaderOffset:
+# PPC64LE-NEXT: Flags [ (0x2)
+# PPC64LE-NEXT: 0x2
+# PPC64LE-NEXT: ]
+# PPC64LE-NEXT: HeaderSize: 64
+# PPC64LE-NEXT: ProgramHeaderEntrySize: 56
+# PPC64LE-NEXT: ProgramHeaderCount:
+# PPC64LE-NEXT: SectionHeaderEntrySize: 64
+# PPC64LE-NEXT: SectionHeaderCount:
+# PPC64LE-NEXT: StringTableSectionIndex:
+# PPC64LE-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
@@ -230,7 +264,7 @@
# MIPS-NEXT: DataEncoding: BigEndian (0x2)
# MIPS-NEXT: FileVersion: 1
# MIPS-NEXT: OS/ABI: SystemV (0x0)
-# MIPS-NEXT: ABIVersion: 0
+# MIPS-NEXT: ABIVersion: 1
# MIPS-NEXT: Unused: (00 00 00 00 00 00 00)
# MIPS-NEXT: }
# MIPS-NEXT: Type: Executable (0x2)
@@ -259,7 +293,7 @@
# MIPSEL-NEXT: DataEncoding: LittleEndian (0x1)
# MIPSEL-NEXT: FileVersion: 1
# MIPSEL-NEXT: OS/ABI: SystemV (0x0)
-# MIPSEL-NEXT: ABIVersion: 0
+# MIPSEL-NEXT: ABIVersion: 1
# MIPSEL-NEXT: Unused: (00 00 00 00 00 00 00)
# MIPSEL-NEXT: }
# MIPSEL-NEXT: Type: Executable (0x2)
@@ -333,8 +367,12 @@
# 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: ld.lld -m aarch64elf %taarch64 -o %t3aarch64
# RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s
+# RUN: ld.lld -m aarch64_elf64_le_vec %taarch64 -o %t4aarch64
+# RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s
+# RUN: ld.lld %taarch64 -o %t5aarch64
+# RUN: llvm-readobj -file-headers %t5aarch64 | FileCheck --check-prefix=AARCH64 %s
# AARCH64: ElfHeader {
# AARCH64-NEXT: Ident {
# AARCH64-NEXT: Magic: (7F 45 4C 46)
@@ -354,7 +392,5 @@
# 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
index 71d86d1c8faf..d25170605cb3 100644
--- a/test/ELF/end-preserve.s
+++ b/test/ELF/end-preserve.s
@@ -1,5 +1,5 @@
-// Should preserve the value of the "end" symbol if it is defined.
// REQUIRES: x86
+// Should preserve the value of the "end" symbol if it is defined.
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: ld.lld %t.o -o %t
diff --git a/test/ELF/end-update.s b/test/ELF/end-update.s
index afb137fd2d73..9ece23ce9ac2 100644
--- a/test/ELF/end-update.s
+++ b/test/ELF/end-update.s
@@ -1,5 +1,5 @@
-// Should set the value of the "end" symbol if it is undefined.
// REQUIRES: x86
+// Should set the value of the "end" symbol if it is undefined.
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: ld.lld %t.o -o %t
diff --git a/test/ELF/end.s b/test/ELF/end.s
index f40c5db8b5ff..530a00783704 100644
--- a/test/ELF/end.s
+++ b/test/ELF/end.s
@@ -1,5 +1,5 @@
-// Should set the value of the "_end" symbol to the end of the data segment.
// REQUIRES: x86
+// Should set the value of the "_end" symbol to the end of the data segment.
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
diff --git a/test/ELF/entry.s b/test/ELF/entry.s
index f288bcf6ae50..cc7a7248f082 100644
--- a/test/ELF/entry.s
+++ b/test/ELF/entry.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
# RUN: ld.lld -e foobar %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN1 %s
diff --git a/test/ELF/exclude-libs.s b/test/ELF/exclude-libs.s
index dc7530068586..c061c484b344 100644
--- a/test/ELF/exclude-libs.s
+++ b/test/ELF/exclude-libs.s
@@ -3,9 +3,10 @@
// 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/exclude-libs.s -o %t2.o
+// RUN: llvm-as --data-layout=elf %p/Inputs/exclude-libs.ll -o %t3.o
// RUN: mkdir -p %t.dir
// RUN: rm -f %t.dir/exc.a
-// RUN: llvm-ar rcs %t.dir/exc.a %t2.o
+// RUN: llvm-ar rcs %t.dir/exc.a %t2.o %t3.o
// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s
@@ -22,6 +23,9 @@
// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
+// RUN: ld.lld -shared %t.o %t2.o %t3.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s
+
// RUN: ld.lld -shared --whole-archive %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
@@ -29,8 +33,13 @@
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
// DEFAULT: Name: fn
+// DEFAULT: Name: fn2
+// DEFAULT: Name: foo
// EXCLUDE-NOT: Name: fn
+// EXCLUDE-NOT: Name: fn2
+// EXCLUDE: Name: foo
-.globl fn
+.globl fn, fn2, foo
foo:
call fn@PLT
+ call fn2@PLT
diff --git a/test/ELF/executable-undefined-protected-ignoreall.s b/test/ELF/executable-undefined-protected-ignoreall.s
index 37911791e124..967a69388670 100644
--- a/test/ELF/executable-undefined-protected-ignoreall.s
+++ b/test/ELF/executable-undefined-protected-ignoreall.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: not ld.lld %t -o %tout --unresolved-symbols=ignore-all -pie 2>&1 | FileCheck %s
+# RUN: not ld.lld %t -o /dev/null --unresolved-symbols=ignore-all -pie 2>&1 | FileCheck %s
# CHECK: error: undefined symbol: foo
.protected foo
diff --git a/test/ELF/export-dynamic-symbol.s b/test/ELF/export-dynamic-symbol.s
new file mode 100644
index 000000000000..22536035424c
--- /dev/null
+++ b/test/ELF/export-dynamic-symbol.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: rm -f %t.a
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t1.o
+# RUN: llvm-ar rcs %t.a %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+
+# RUN: ld.lld -shared -o %t.so --export-dynamic-symbol foo %t.a %t2.o
+# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s
+
+# RUN: ld.lld -shared -o %t.so --export-dynamic --export-dynamic-symbol foo %t.a %t2.o
+# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s
+
+# CHECK: foo
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/fatal-warnings.s b/test/ELF/fatal-warnings.s
index 0bc2a2b44476..51f2864a0598 100644
--- a/test/ELF/fatal-warnings.s
+++ b/test/ELF/fatal-warnings.s
@@ -2,11 +2,11 @@
# 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: ld.lld --warn-common %t1.o %t2.o -o /dev/null 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: not ld.lld --warn-common --fatal-warnings %t1.o %t2.o -o /dev/null 2>&1 | \
# RUN: FileCheck -check-prefix=ERR %s
.globl _start
diff --git a/test/ELF/file-sym.s b/test/ELF/file-sym.s
deleted file mode 100644
index eddb461490c6..000000000000
--- a/test/ELF/file-sym.s
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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/fill-trap-ppc.s b/test/ELF/fill-trap-ppc.s
new file mode 100644
index 000000000000..da7d7cb320bb
--- /dev/null
+++ b/test/ELF/fill-trap-ppc.s
@@ -0,0 +1,31 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.ppc64le
+# RUN: llvm-readobj -program-headers %t.ppc64le | FileCheck %s
+# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64le | FileCheck %s -check-prefix=LE
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.ppc64
+# RUN: llvm-readobj -program-headers %t.ppc64 | FileCheck %s
+# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64 | FileCheck %s -check-prefix=BE
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: Offset: 0x10000{{$}}
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize: 4096
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+
+## Check that executable page is filled with traps at its end.
+# LE: 010ff0 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f
+# BE: 010ff0 7f e0 00 08 7f e0 00 08 7f e0 00 08 7f e0 00 08
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/filter.s b/test/ELF/filter.s
index 4c9104a32510..2b07c01013df 100644
--- a/test/ELF/filter.s
+++ b/test/ELF/filter.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld %t.o -shared -F foo.so -F boo.so -o %t1
# RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s
@@ -15,5 +16,5 @@
# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [foo.so]
# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [boo.so]
-# RUN: not ld.lld %t.o -F x -o %t 2>&1 | FileCheck -check-prefix=ERR %s
+# RUN: not ld.lld %t.o -F x -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s
# ERR: -F may not be used without -shared
diff --git a/test/ELF/format-binary-non-ascii.s b/test/ELF/format-binary-non-ascii.s
index 5a3ad960c30e..36263e5ddaba 100644
--- a/test/ELF/format-binary-non-ascii.s
+++ b/test/ELF/format-binary-non-ascii.s
@@ -4,9 +4,9 @@
# RUN: ld.lld -o %t.elf %t£.o --format=binary %t£.o
# RUN: llvm-readobj -symbols %t.elf | FileCheck %s
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_start
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_end
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_size
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_start
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_end
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_size
.text
.align 4
diff --git a/test/ELF/gc-absolute.s b/test/ELF/gc-absolute.s
index 29e671678ee7..bd0870c263a7 100644
--- a/test/ELF/gc-absolute.s
+++ b/test/ELF/gc-absolute.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 -shared --gc-sections
+# RUN: ld.lld %t -o /dev/null -shared --gc-sections
.global foo
foo = 0x123
diff --git a/test/ELF/gc-debuginfo-tls.s b/test/ELF/gc-debuginfo-tls.s
index d1a250b9c944..e23578f58c25 100644
--- a/test/ELF/gc-debuginfo-tls.s
+++ b/test/ELF/gc-debuginfo-tls.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld %t.o --gc-sections -shared -o %t1
# RUN: ld.lld %t.o -shared -o %t2
diff --git a/test/ELF/gc-merge-local-sym.s b/test/ELF/gc-merge-local-sym.s
index b02a3a4e4762..b82d0cebae82 100644
--- a/test/ELF/gc-merge-local-sym.s
+++ b/test/ELF/gc-merge-local-sym.s
@@ -1,3 +1,4 @@
+// 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 -O3 --gc-sections
// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
@@ -9,7 +10,7 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x235
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
diff --git a/test/ELF/gc-sections-local-sym.s b/test/ELF/gc-sections-local-sym.s
index 89121e289cc2..15bca37ca409 100644
--- a/test/ELF/gc-sections-local-sym.s
+++ b/test/ELF/gc-sections-local-sym.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/gc-sections-merge-addend.s b/test/ELF/gc-sections-merge-addend.s
index 8595f5802be5..4dd95b43bfc0 100644
--- a/test/ELF/gc-sections-merge-addend.s
+++ b/test/ELF/gc-sections-merge-addend.s
@@ -1,3 +1,4 @@
+// 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 --gc-sections
// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
diff --git a/test/ELF/gc-sections-merge-implicit-addend.s b/test/ELF/gc-sections-merge-implicit-addend.s
index 8a7c804a830a..36bb21126434 100644
--- a/test/ELF/gc-sections-merge-implicit-addend.s
+++ b/test/ELF/gc-sections-merge-implicit-addend.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/gc-sections-merge.s b/test/ELF/gc-sections-merge.s
index ef2688659871..08dfdaaea669 100644
--- a/test/ELF/gc-sections-merge.s
+++ b/test/ELF/gc-sections-merge.s
@@ -1,3 +1,4 @@
+// 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: ld.lld %t.o -o %t.gc.so -shared --gc-sections
diff --git a/test/ELF/gc-sections-metadata-startstop.s b/test/ELF/gc-sections-metadata-startstop.s
index 10c0b5477b25..ede1899698c4 100644
--- a/test/ELF/gc-sections-metadata-startstop.s
+++ b/test/ELF/gc-sections-metadata-startstop.s
@@ -1,5 +1,5 @@
-# LINK_ORDER cnamed sections are not kept alive by the __start_* reference.
# REQUIRES: x86
+# LINK_ORDER cnamed sections are not kept alive by the __start_* reference.
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld --gc-sections %t.o -o %t
diff --git a/test/ELF/gc-sections-no-undef-error.s b/test/ELF/gc-sections-no-undef-error.s
new file mode 100644
index 000000000000..31945241a77a
--- /dev/null
+++ b/test/ELF/gc-sections-no-undef-error.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# Sanity check that the link will fail with the undefined error without
+# gc-sections.
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+# CHECK: error: undefined symbol: undefined
+
+# RUN: ld.lld %t.o --gc-sections -o %t
+
+.section .text.unused,"ax",@progbits
+unused:
+ callq undefined
+
+.text
+.global _start
+_start:
+ nop
diff --git a/test/ELF/gc-sections-print.s b/test/ELF/gc-sections-print.s
index e05824177c1f..a822e9ef3479 100644
--- a/test/ELF/gc-sections-print.s
+++ b/test/ELF/gc-sections-print.s
@@ -2,8 +2,8 @@
# 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
+# PRINT: removing unused section {{.*}}:(.text.x)
+# PRINT-NEXT: removing unused section {{.*}}:(.text.y)
# RUN: ld.lld %t --gc-sections --print-gc-sections --no-print-gc-sections -o %t2 >& %t.log
# RUN: echo >> %t.log
diff --git a/test/ELF/gc-sections-protected.s b/test/ELF/gc-sections-protected.s
index 9f1efed5938a..28e779b1b7a1 100644
--- a/test/ELF/gc-sections-protected.s
+++ b/test/ELF/gc-sections-protected.s
@@ -1,3 +1,4 @@
+// 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 --gc-sections
// RUN: llvm-readobj -s %t.so | FileCheck %s
diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s
index 2976213e910a..c0ebf403a333 100644
--- a/test/ELF/gc-sections-shared.s
+++ b/test/ELF/gc-sections-shared.s
@@ -25,6 +25,15 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: qux
+# CHECK-NEXT: Value:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Binding: Weak
+# CHECK-NEXT: Type:
+# CHECK-NEXT: Other:
+# CHECK-NEXT: Section: Undefined
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: bar
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
@@ -51,15 +60,6 @@
# CHECK-NEXT: Other:
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
-# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: qux
-# CHECK-NEXT: Value:
-# CHECK-NEXT: Size:
-# CHECK-NEXT: Binding: Weak
-# CHECK-NEXT: Type:
-# CHECK-NEXT: Other:
-# CHECK-NEXT: Section: Undefined
-# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NOT: NEEDED
@@ -68,64 +68,12 @@
# Test with %t.o at the end too.
# RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t --as-needed %t2.so %t3.so %t4.so %t.o
-# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK2 %s
-
-# CHECK2: DynamicSymbols [
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name:
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Local
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined (0x0)
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: bar
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: .text
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: baz
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: qux
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Weak
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: foo
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: .text
-# CHECK2-NEXT: }
-# CHECK2-NEXT: ]
-
-# CHECK2-NOT: NEEDED
-# CHECK2: NEEDED Shared library: [{{.*}}3.so]
-# CHECK2-NOT: NEEDED
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK %s
.section .text.foo, "ax"
.globl foo
foo:
-call bar
+.long bar - .
.section .text.bar, "ax"
.globl bar
@@ -136,9 +84,9 @@ ret
.globl _start
.weak qux
_start:
-call baz
-call qux
+.long baz - .
+.long qux - .
ret
.section .text.unused, "ax"
-call bar2
+.long bar2 - .
diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s
deleted file mode 100644
index f5df00c453cc..000000000000
--- a/test/ELF/gdb-index-dup-types.s
+++ /dev/null
@@ -1,60 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: ld.lld --gdb-index %t.o -o %t
-# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
-
-## Testcase is based on output produced by gcc version 5.4.1 20160904
-## it has duplicate entries in .debug_gnu_pubtypes which seems to be
-## compiler bug. In that case it is useless to have them in .gdb_index
-## and we filter such entries out to reduce size of .gdb_index.
-
-## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors:
-## CHECK-NOT: 0(0x0): 0x90000000 0x90000000
-
-.section .debug_abbrev,"",@progbits
- .byte 1 # Abbreviation Code
- .byte 17 # DW_TAG_compile_unit
- .byte 0 # DW_CHILDREN_no
- .byte 16 # DW_AT_stmt_list
- .byte 23 # DW_FORM_sec_offset
- .ascii "\260B" # DW_AT_GNU_dwo_name
- .byte 14 # DW_FORM_strp
- .byte 27 # DW_AT_comp_dir
- .byte 14 # DW_FORM_strp
- .ascii "\264B" # DW_AT_GNU_pubnames
- .byte 25 # DW_FORM_flag_present
- .ascii "\261B" # DW_AT_GNU_dwo_id
- .byte 7 # DW_FORM_data8
- .ascii "\263B" # DW_AT_GNU_addr_base
- .byte 23 # DW_FORM_sec_offset
- .byte 0 # EOM(1)
- .byte 0 # EOM(2)
- .byte 0 # EOM(3)
-
-.section .debug_info,"",@progbits
-.Lcu_begin0:
- .long 32 # Length of Unit
- .short 4 # DWARF version number
- .long .debug_abbrev # Offset Into Abbrev. Section
- .byte 8 # Address Size (in bytes)
- .byte 1 # Abbrev [1] 0xb:0x19 DW_TAG_compile_unit
- .long 0 # DW_AT_stmt_list
- .long 0 # DW_AT_GNU_dwo_name
- .long 0 # DW_AT_comp_dir
- .quad 0 # DW_AT_GNU_dwo_id
- .long 0 # DW_AT_GNU_addr_base
-
-.section .debug_gnu_pubtypes,"",@progbits
-.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
-.LpubTypes_begin0:
- .short 2 # DWARF Version
- .long .Lcu_begin0 # Offset of Compilation Unit Info
- .long 36 # Compilation Unit Length
- .long 36 # DIE offset
- .byte 144 # Kind: TYPE, STATIC
- .asciz "int" # External Name
- .long 36 # DIE offset
- .byte 144 # Kind: TYPE, STATIC
- .asciz "int" # External Name
- .long 0 # End Mark
-.LpubTypes_end0:
diff --git a/test/ELF/gdb-index-noranges.s b/test/ELF/gdb-index-noranges.s
index 29ba91eb5a75..12080642e6cd 100644
--- a/test/ELF/gdb-index-noranges.s
+++ b/test/ELF/gdb-index-noranges.s
@@ -10,7 +10,7 @@
##
## Debug information does not contain any address ranges.
## We crashed in that case. Check we don't.
-# RUN: ld.lld --gdb-index %t1.o -o %t
+# RUN: ld.lld --gdb-index %t1.o -o /dev/null
.section .debug_str,"MS",@progbits,1
.Lskel_string0:
diff --git a/test/ELF/gdb-index-tls.s b/test/ELF/gdb-index-tls.s
index 0fd7b6115676..785e13f0056f 100644
--- a/test/ELF/gdb-index-tls.s
+++ b/test/ELF/gdb-index-tls.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld --gdb-index -shared %t.o -o %t
+# RUN: ld.lld --gdb-index -shared %t.o -o /dev/null
# This used to fail trying to compute R_X86_64_DTPOFF64
diff --git a/test/ELF/gdb-index.s b/test/ELF/gdb-index.s
index 8fea83d145fa..e7f96066bd02 100644
--- a/test/ELF/gdb-index.s
+++ b/test/ELF/gdb-index.s
@@ -1,9 +1,19 @@
-# REQUIRES: x86
+# REQUIRES: x86, zlib
# 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/gdb-index.s -o %t2.o
# RUN: ld.lld --gdb-index %t1.o %t2.o -o %t
-# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
+
+# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -sections %t | FileCheck %s --check-prefix=SECTION
+
+# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-pc-linux \
+# RUN: %p/Inputs/gdb-index.s -o %t2.o
+# RUN: ld.lld --gdb-index %t1.o %t2.o -o %t
+
# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -sections %t | FileCheck %s --check-prefix=SECTION
# DISASM: Disassembly of section .text:
# DISASM: entrypoint:
@@ -11,29 +21,31 @@
# DISASM-CHECK: 201001: cc int3
# DISASM-CHECK: 201002: cc int3
# DISASM-CHECK: 201003: cc int3
-# DISASM: main2:
+# DISASM: aaaaaaaaaaaaaaaa:
# DISASM-CHECK: 201004: 90 nop
# DISASM-CHECK: 201005: 90 nop
-# CHECK: .gnu_index contents:
-# CHECK-NEXT: Version = 7
-# CHECK: CU list offset = 0x18, has 2 entries:
-# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34
-# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34
-# CHECK: Address area offset = 0x38, has 2 entries:
-# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
-# CHECK-NEXT: Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1
-# CHECK: Symbol table offset = 0x60, size = 1024, filled slots:
-# CHECK-NEXT: 754: Name offset = 0x27, CU vector offset = 0x8
-# CHECK-NEXT: String name: int, CU vector index: 1
-# CHECK-NEXT: 822: Name offset = 0x1c, CU vector offset = 0x0
-# CHECK-NEXT: String name: entrypoint, CU vector index: 0
-# CHECK-NEXT: 956: Name offset = 0x2b, CU vector offset = 0x14
-# CHECK-NEXT: String name: main2, CU vector index: 2
-# CHECK: Constant pool offset = 0x2060, has 3 CU vectors:
-# CHECK-NEXT: 0(0x0): 0x30000000
-# CHECK-NEXT: 1(0x8): 0x90000000 0x90000001
-# CHECK-NEXT: 2(0x14): 0x30000001
+# DWARF: .gnu_index contents:
+# DWARF-NEXT: Version = 7
+# DWARF: CU list offset = 0x18, has 2 entries:
+# DWARF-NEXT: 0: Offset = 0x0, Length = 0x34
+# DWARF-NEXT: 1: Offset = 0x34, Length = 0x34
+# DWARF: Address area offset = 0x38, has 2 entries:
+# DWARF-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+# DWARF-NEXT: Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1
+# DWARF: Symbol table offset = 0x60, size = 1024, filled slots:
+# DWARF-NEXT: 512: Name offset = 0x1c, CU vector offset = 0x0
+# DWARF-NEXT: String name: aaaaaaaaaaaaaaaa, CU vector index: 0
+# DWARF-NEXT: 754: Name offset = 0x38, CU vector offset = 0x10
+# DWARF-NEXT: String name: int, CU vector index: 2
+# DWARF-NEXT: 822: Name offset = 0x2d, CU vector offset = 0x8
+# DWARF-NEXT: String name: entrypoint, CU vector index: 1
+# DWARF: Constant pool offset = 0x2060, has 3 CU vectors:
+# DWARF-NEXT: 0(0x0): 0x30000001
+# DWARF-NEXT: 1(0x8): 0x30000000
+# DWARF-NEXT: 2(0x10): 0x90000000 0x90000001
+
+# SECTION-NOT: debug_gnu_pubnames
# RUN: ld.lld --gdb-index --no-gdb-index %t1.o %t2.o -o %t2
# RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=NOGDB %s
diff --git a/test/ELF/global-offset-table-position-aarch64.s b/test/ELF/global-offset-table-position-aarch64.s
index 68bc4a4254ed..7fdc7978825f 100644
--- a/test/ELF/global-offset-table-position-aarch64.s
+++ b/test/ELF/global-offset-table-position-aarch64.s
@@ -1,7 +1,7 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
// RUN: ld.lld --hash-style=sysv -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
-// REQUIRES: aarch64
.globl a
.type a,@object
.comm a,4,4
@@ -20,11 +20,11 @@ _start:
.long _GLOBAL_OFFSET_TABLE_ - .
// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11)
-// CHECK-NEXT: Value: 0x30090
+// CHECK-NEXT: Value: 0x20008
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local (0x0)
// CHECK-NEXT: Type: None (0x0)
// CHECK-NEXT: Other [ (0x2)
// CHECK-NEXT: STV_HIDDEN (0x2)
// CHECK-NEXT: ]
-// CHECK-NEXT: Section: .got
+// CHECK-NEXT: Section: .got.plt
diff --git a/test/ELF/global-offset-table-position-arm.s b/test/ELF/global-offset-table-position-arm.s
index 19619b2cc9e8..9abca8b46317 100644
--- a/test/ELF/global-offset-table-position-arm.s
+++ b/test/ELF/global-offset-table-position-arm.s
@@ -1,7 +1,7 @@
+// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t
// RUN: ld.lld --hash-style=sysv -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
-// REQUIRES: arm
// The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
.globl a
diff --git a/test/ELF/global-offset-table-position-i386.s b/test/ELF/global-offset-table-position-i386.s
index 9f778e1efb50..e3d343427015 100644
--- a/test/ELF/global-offset-table-position-i386.s
+++ b/test/ELF/global-offset-table-position-i386.s
@@ -1,9 +1,10 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
// RUN: ld.lld --hash-style=sysv -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
-// REQUIRES: x86
-// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt
+// section.
.globl a
.type a,@object
.comm a,4,4
@@ -21,11 +22,11 @@ addl $_GLOBAL_OFFSET_TABLE_, %eax
calll f@PLT
// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1)
-// CHECK-NEXT: Value: 0x306C
+// CHECK-NEXT: Value: 0x2000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local (0x0)
// CHECK-NEXT: Type: None (0x0)
// CHECK-NEXT: Other [ (0x2)
// CHECK-NEXT: STV_HIDDEN (0x2)
// CHECK-NEXT: ]
-// CHECK-NEXT: Section: .got (0xA)
+// CHECK-NEXT: Section: .got.plt
diff --git a/test/ELF/global-offset-table-position-mips.s b/test/ELF/global-offset-table-position-mips.s
index 92daed1c7914..a5577f2e1421 100644
--- a/test/ELF/global-offset-table-position-mips.s
+++ b/test/ELF/global-offset-table-position-mips.s
@@ -1,9 +1,8 @@
+// REQUIRES: mips
// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t
// RUN: ld.lld -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
-// REQUIRES: mips
-
// The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
.globl a
diff --git a/test/ELF/global-offset-table-position.s b/test/ELF/global-offset-table-position.s
index f1195b2cf674..aa8083654039 100644
--- a/test/ELF/global-offset-table-position.s
+++ b/test/ELF/global-offset-table-position.s
@@ -1,9 +1,10 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
// RUN: ld.lld --hash-style=sysv -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
-// REQUIRES: x86
-// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt
+// section.
.globl a
.type a,@object
.comm a,4,4
@@ -21,11 +22,11 @@ callq f@PLT
.long _GLOBAL_OFFSET_TABLE_ - .
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
-// CHECK-NEXT: Value: 0x30D8
+// CHECK-NEXT: Value: 0x2008
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None (0x0)
// CHECK-NEXT: Other [
// CHECK-NEXT: STV_HIDDEN
// CHECK-NEXT: ]
-// CHECK-NEXT: Section: .got
+// CHECK-NEXT: Section: .got.plt
diff --git a/test/ELF/global_offset_table.s b/test/ELF/global_offset_table.s
index 47e95e9f9b84..3b86f00ae3ab 100644
--- a/test/ELF/global_offset_table.s
+++ b/test/ELF/global_offset_table.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
-// RUN: ld.lld %t -o %t2
+// RUN: ld.lld %t -o /dev/null
.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
index 03af02e5805e..7af6a403ac6c 100644
--- a/test/ELF/global_offset_table_shared.s
+++ b/test/ELF/global_offset_table_shared.s
@@ -1,14 +1,15 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
// RUN: ld.lld --hash-style=sysv -shared %t -o %t2
// RUN: llvm-readobj -t %t2 | FileCheck %s
.long _GLOBAL_OFFSET_TABLE_ - .
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
-// CHECK-NEXT: Value: 0x2060
+// CHECK-NEXT: Value: 0x2000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
// CHECK-NEXT: Other [ (0x2)
// CHECK-NEXT: STV_HIDDEN (0x2)
// CHECK-NEXT: ]
-// CHECK-NEXT: Section: .got
+// CHECK-NEXT: Section: .got.plt
diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s
index fa68ba250131..ffbf19fb5c6f 100644
--- a/test/ELF/gnu-hash-table.s
+++ b/test/ELF/gnu-hash-table.s
@@ -4,30 +4,36 @@
# 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: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t-ppc64.o
# RUN: echo ".global zed; zed:" > %t2.s
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t2.s -o %t2-i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2-x86_64.o
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t2.s -o %t2-ppc64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t2.s -o %t2-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t2.s -o %t2-ppc64.o
# RUN: rm -f %t2-i386.a %t2-x86_64.a %t2-ppc64.a
# RUN: llvm-ar rc %t2-i386.a %t2-i386.o
# RUN: llvm-ar rc %t2-x86_64.a %t2-x86_64.o
+# RUN: llvm-ar rc %t2-ppc64le.a %t2-ppc64le.o
# RUN: llvm-ar rc %t2-ppc64.a %t2-ppc64.o
# RUN: echo ".global xyz; xyz:" > %t3.s
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t3.s -o %t3-i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t3.s -o %t3-x86_64.o
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t3.s -o %t3-ppc64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t3.s -o %t3-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t3.s -o %t3-ppc64.o
# RUN: ld.lld -shared %t3-i386.o -o %t3-i386.so
# RUN: ld.lld -shared %t3-x86_64.o -o %t3-x86_64.so
+# RUN: ld.lld -shared %t3-ppc64le.o -o %t3-ppc64le.so
# RUN: ld.lld -shared %t3-ppc64.o -o %t3-ppc64.so
# 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 %t2-i386.a %t3-i386.so
# RUN: ld.lld -shared -hash-style=gnu -o %t-x86_64.so %t-x86_64.o %t2-x86_64.a %t3-x86_64.so
+# RUN: ld.lld -shared --hash-style both -o %t-ppc64le.so %t-ppc64le.o %t2-ppc64le.a %t3-ppc64le.so
# RUN: ld.lld -shared --hash-style both -o %t-ppc64.so %t-ppc64.o %t2-ppc64.a %t3-ppc64.so
# RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \
@@ -36,6 +42,8 @@
# 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-ppc64le.so \
+# RUN: | FileCheck %s -check-prefix=PPC64
# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \
# RUN: | FileCheck %s -check-prefix=PPC64
@@ -51,12 +59,12 @@
# EMPTY-NEXT: }
# EMPTY-NEXT: ]
# EMPTY: GnuHashTable {
-# EMPTY-NEXT: Num Buckets: 0
+# EMPTY-NEXT: Num Buckets: 1
# EMPTY-NEXT: First Hashed Symbol Index: 2
# EMPTY-NEXT: Num Mask Words: 1
-# EMPTY-NEXT: Shift Count: 5
+# EMPTY-NEXT: Shift Count: 6
# EMPTY-NEXT: Bloom Filter: [0x0]
-# EMPTY-NEXT: Buckets: []
+# EMPTY-NEXT: Buckets: [0]
# EMPTY-NEXT: Values: []
# EMPTY-NEXT: }
@@ -113,8 +121,8 @@
# I386-NEXT: Num Buckets: 1
# I386-NEXT: First Hashed Symbol Index: 4
# I386-NEXT: Num Mask Words: 1
-# I386-NEXT: Shift Count: 5
-# I386-NEXT: Bloom Filter: [0x14000220]
+# I386-NEXT: Shift Count: 6
+# I386-NEXT: Bloom Filter: [0x4004204]
# I386-NEXT: Buckets: [4]
# I386-NEXT: Values: [0xB8860BA, 0xB887389]
# I386-NEXT: }
diff --git a/test/ELF/gnu-ifunc-dynsym.s b/test/ELF/gnu-ifunc-dynsym.s
index fca15462dcb1..3d98ac3a4cfc 100644
--- a/test/ELF/gnu-ifunc-dynsym.s
+++ b/test/ELF/gnu-ifunc-dynsym.s
@@ -1,7 +1,11 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
// RUN: ld.lld -static -export-dynamic %t.o -o %tout
// RUN: llvm-nm -U %tout | FileCheck %s
-// REQUIRES: x86
+
+// RUN: ld.lld -export-dynamic %t.o -o %tout
+// RUN: llvm-nm -U %tout | FileCheck %s
// CHECK: __rela_iplt_end
// CHECK: __rela_iplt_start
diff --git a/test/ELF/gnu-ifunc-dyntags.s b/test/ELF/gnu-ifunc-dyntags.s
new file mode 100644
index 000000000000..81bd338d088d
--- /dev/null
+++ b/test/ELF/gnu-ifunc-dyntags.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %tout
+# RUN: llvm-objdump -section-headers %tout | FileCheck %s
+# RUN: llvm-readobj -dynamic-table -r %tout | FileCheck %s --check-prefix=TAGS
+
+## Check we produce DT_PLTREL/DT_JMPREL/DT_PLTGOT and DT_PLTRELSZ tags
+## when there are no other relocations except R_*_IRELATIVE.
+
+# CHECK: Name Size Address
+# CHECK: .rela.plt 00000030 0000000000000210
+# CHECK: .got.plt 00000010 0000000000002000
+
+# TAGS: Relocations [
+# TAGS-NEXT: Section {{.*}} .rela.plt {
+# TAGS-NEXT: R_X86_64_IRELATIVE
+# TAGS-NEXT: R_X86_64_IRELATIVE
+# TAGS-NEXT: }
+# TAGS-NEXT: ]
+
+# TAGS: Tag Type Name/Value
+# TAGS: 0x0000000000000017 JMPREL 0x210
+# TAGS: 0x0000000000000002 PLTRELSZ 48
+# TAGS: 0x0000000000000003 PLTGOT 0x2000
+# TAGS: 0x0000000000000014 PLTREL RELA
+
+.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-i386.s b/test/ELF/gnu-ifunc-i386.s
index 4eda32f378d9..f379bf1b28e8 100644
--- a/test/ELF/gnu-ifunc-i386.s
+++ b/test/ELF/gnu-ifunc-i386.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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 {
diff --git a/test/ELF/gnu-ifunc-nosym-i386.s b/test/ELF/gnu-ifunc-nosym-i386.s
index d22cedbfe6de..564b87e23b32 100644
--- a/test/ELF/gnu-ifunc-nosym-i386.s
+++ b/test/ELF/gnu-ifunc-nosym-i386.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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.
diff --git a/test/ELF/gnu-ifunc-nosym.s b/test/ELF/gnu-ifunc-nosym.s
index 08e498e97c19..4206f57d1363 100644
--- a/test/ELF/gnu-ifunc-nosym.s
+++ b/test/ELF/gnu-ifunc-nosym.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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.
diff --git a/test/ELF/gnu-ifunc-plt-i386.s b/test/ELF/gnu-ifunc-plt-i386.s
index 243eff62fcbf..14369bf6388b 100644
--- a/test/ELF/gnu-ifunc-plt-i386.s
+++ b/test/ELF/gnu-ifunc-plt-i386.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
// RUN: ld.lld %t1.o --shared -o %t.so
// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
@@ -5,7 +6,6 @@
// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
-// REQUIRES: x86
// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
// CHECK: Relocations [
@@ -70,7 +70,7 @@ bar:
.globl _start
_start:
- call foo
- call bar
- call bar2
- call zed2
+ call foo@plt
+ call bar@plt
+ call bar2@plt
+ call zed2@plt
diff --git a/test/ELF/gnu-ifunc-plt.s b/test/ELF/gnu-ifunc-plt.s
index 88a09931853c..b88f32cb7306 100644
--- a/test/ELF/gnu-ifunc-plt.s
+++ b/test/ELF/gnu-ifunc-plt.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
// RUN: ld.lld %t1.o --shared -o %t.so
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
@@ -5,7 +6,6 @@
// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
-// REQUIRES: x86
// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
// CHECK: Relocations [
diff --git a/test/ELF/gnu-ifunc-relative.s b/test/ELF/gnu-ifunc-relative.s
index dc35102c5787..d797301d03ad 100644
--- a/test/ELF/gnu-ifunc-relative.s
+++ b/test/ELF/gnu-ifunc-relative.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s
index 4911da6bce00..faf51b4b6216 100644
--- a/test/ELF/gnu-ifunc.s
+++ b/test/ELF/gnu-ifunc.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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 {
diff --git a/test/ELF/gnu-unique.s b/test/ELF/gnu-unique.s
index afc0da27063d..06f370434cd8 100644
--- a/test/ELF/gnu-unique.s
+++ b/test/ELF/gnu-unique.s
@@ -3,6 +3,8 @@
//
// 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 --gnu-unique
+// 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
diff --git a/test/ELF/gnustack.s b/test/ELF/gnustack.s
index c506fb807c62..3ab6f16ac7bd 100644
--- a/test/ELF/gnustack.s
+++ b/test/ELF/gnustack.s
@@ -1,10 +1,15 @@
# 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
+# RUN: ld.lld %t1 -o %t -z noexecstack
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s
+
# RW: Type: PT_GNU_STACK
# RW-NEXT: Offset: 0x0
# RW-NEXT: VirtualAddress: 0x0
diff --git a/test/ELF/got-aarch64.s b/test/ELF/got-aarch64.s
index f46946c9f4aa..c9e20276472f 100644
--- a/test/ELF/got-aarch64.s
+++ b/test/ELF/got-aarch64.s
@@ -1,8 +1,8 @@
+// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o
// RUN: ld.lld --hash-style=sysv -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
diff --git a/test/ELF/got-i386.s b/test/ELF/got-i386.s
index 679eb2e4f5ca..7fb87e0dadbd 100644
--- a/test/ELF/got-i386.s
+++ b/test/ELF/got-i386.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/got-plt-header.s b/test/ELF/got-plt-header.s
index a6b10fa3a0a0..f8412e13c41d 100644
--- a/test/ELF/got-plt-header.s
+++ b/test/ELF/got-plt-header.s
@@ -1,3 +1,4 @@
+// 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 -s -section-data %t.so | FileCheck %s
diff --git a/test/ELF/got.s b/test/ELF/got.s
index f67ea13d3f4e..9d2d804454bf 100644
--- a/test/ELF/got.s
+++ b/test/ELF/got.s
@@ -1,10 +1,10 @@
+// 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/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
// RUN: ld.lld --hash-style=sysv %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
diff --git a/test/ELF/got32-i386-pie-rw.s b/test/ELF/got32-i386-pie-rw.s
index 18b019c2cc9d..45d2ec154675 100644
--- a/test/ELF/got32-i386-pie-rw.s
+++ b/test/ELF/got32-i386-pie-rw.s
@@ -7,8 +7,8 @@
# CHECK: .foobar PROGBITS 00001000
# CHECK: .got PROGBITS [[GOT:[0-9a-z]*]]
-# CHECK: [[GOT]] 00000008 R_386_RELATIVE
-# CHECK: 00001002 00000008 R_386_RELATIVE
+# CHECK-DAG: 00001002 00000008 R_386_RELATIVE
+# CHECK-DAG: [[GOT]] 00000008 R_386_RELATIVE
foo:
.section .foobar, "awx"
diff --git a/test/ELF/got32-i386.s b/test/ELF/got32-i386.s
index 00c7c0d6d553..dce50d0afc2e 100644
--- a/test/ELF/got32-i386.s
+++ b/test/ELF/got32-i386.s
@@ -20,4 +20,4 @@ _start:
# CHECK: .got 00000004 0000000000012000
# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR
-# ERR: error: can't create dynamic relocation R_386_GOT32 against symbol: foo in readonly segment; recompile object files with -fPIC
+# ERR: error: can't create dynamic relocation R_386_GOT32 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
diff --git a/test/ELF/got32x-i386.s b/test/ELF/got32x-i386.s
index 1311472cc061..610051e8a962 100644
--- a/test/ELF/got32x-i386.s
+++ b/test/ELF/got32x-i386.s
@@ -33,15 +33,15 @@
## 73728 == 0x12000 == ADDR(.got)
# CHECK: _start:
-# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 73728, %eax
-# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 73728, %ebx
+# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 77824, %eax
+# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 77824, %ebx
# CHECK-NEXT: 1100d: 8b 80 {{.*}} movl -4(%eax), %eax
# CHECK-NEXT: 11013: 8b 83 {{.*}} movl -4(%ebx), %eax
# CHECK: Sections:
# CHECK: Name Size Address
-# CHECK: .got 00000004 0000000000012000
+# CHECK: .got 00000004 0000000000013000
# RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \
# RUN: FileCheck %s --check-prefix=ERR
-# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC
-# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC
+# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
+# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
diff --git a/test/ELF/gotpcrelx.s b/test/ELF/gotpcrelx.s
index 3ccbc56aba94..d9a7b8e048c3 100644
--- a/test/ELF/gotpcrelx.s
+++ b/test/ELF/gotpcrelx.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/help.s b/test/ELF/help.s
index 2554531532b3..aca2ceb76ee1 100644
--- a/test/ELF/help.s
+++ b/test/ELF/help.s
@@ -1,5 +1,5 @@
# RUN: ld.lld --help 2>&1 | FileCheck %s
# CHECK: OPTIONS:
-# CHECK: --output=<value> Path to file to write output
-# CHECK: --output <value> Path to file to write output
+# CHECK: --output=<value> Alias for -o
+# CHECK: --output <value> Alias for -o
# CHECK: -o <path> Path to file to write output
diff --git a/test/ELF/hexagon.s b/test/ELF/hexagon.s
new file mode 100644
index 000000000000..8c824ea3c78a
--- /dev/null
+++ b/test/ELF/hexagon.s
@@ -0,0 +1,24 @@
+# REQUIRES: hexagon
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %S/Inputs/hexagon.s -o %t2
+# RUN: ld.lld %t2 %t -o %t3
+# RUN: llvm-objdump -d %t3 | FileCheck %s
+
+# R_HEX_B15_PCREL
+if (p0) jump:nt #_start
+# CHECK: if (p0) jump:nt 0x11000
+
+# R_HEX_B32_PCREL_X
+# R_HEX_B15_PCREL_X
+if (p0) jump:nt ##_start
+# CHECK: if (p0) jump:nt 0x11000
+
+# R_HEX_B22_PCREL
+call #_start
+# CHECK: call 0x11000
+
+# R_HEX_B32_PCREL_X
+# R_HEX_B22_PCREL_X
+call ##_start
+# CHECK: immext(#4294967232)
+# CHECK: call 0x11000
diff --git a/test/ELF/hidden-shared-err.s b/test/ELF/hidden-shared-err.s
new file mode 100644
index 000000000000..e6d424c24824
--- /dev/null
+++ b/test/ELF/hidden-shared-err.s
@@ -0,0 +1,19 @@
+# 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/hidden-shared-err.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/hidden-shared-err2.s -o %t3.o
+
+# RUN: ld.lld -shared -o %t2.so %t2.o
+# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t2.so %t.o -o %t 2>&1 | FileCheck %s
+
+# RUN: not ld.lld %t.o %t3.o %t2.so -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t3.o %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# CHECK: undefined symbol: foo
+
+.global _start
+_start:
+.quad foo
+.hidden foo
diff --git a/test/ELF/i386-debug-noabs.test b/test/ELF/i386-debug-noabs.test
index 712d0a59cecc..dbc7a57f8f7a 100644
--- a/test/ELF/i386-debug-noabs.test
+++ b/test/ELF/i386-debug-noabs.test
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: yaml2obj %s -o %t.o
-# RUN: ld.lld %t.o -o %t.exe
+# RUN: ld.lld %t.o -o /dev/null --entry 0 --fatal-warnings
## This is for https://bugs.llvm.org//show_bug.cgi?id=34852. GCC 8.0 or
## earlier have a bug which creates non-absolute R_386_GOTPC relocations
diff --git a/test/ELF/i386-got-and-copy.s b/test/ELF/i386-got-and-copy.s
index 81bac22fd66a..78788a55f23c 100644
--- a/test/ELF/i386-got-and-copy.s
+++ b/test/ELF/i386-got-and-copy.s
@@ -15,6 +15,7 @@
# CHECK: Relocations [
# CHECK-NEXT: Section (4) .rel.dyn {
# CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_COPY foo
+# CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_GLOB_DAT foo
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/i386-got-value.s b/test/ELF/i386-got-value.s
index 8803fcffb312..2d7bd6804d6a 100644
--- a/test/ELF/i386-got-value.s
+++ b/test/ELF/i386-got-value.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux
# RUN: ld.lld %t.o -o %t.so -shared
# RUN: llvm-readobj --relocations --sections --section-data %t.so | FileCheck %s
diff --git a/test/ELF/i386-gotpc.s b/test/ELF/i386-gotpc.s
index d2c5ef3d469c..af8380b91153 100644
--- a/test/ELF/i386-gotpc.s
+++ b/test/ELF/i386-gotpc.s
@@ -6,15 +6,23 @@
movl $_GLOBAL_OFFSET_TABLE_, %eax
+// 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: 0x2000
+
// CHECK: Name: .got
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x2030
+// CHECK-NEXT: Address: 0x3030
// DISASM: Disassembly of section .text:
// DISASM-NEXT: .text:
-// DISASM-NEXT: 1000: {{.*}} movl $4144, %eax
-// 0x2030 - 0x1000 = 4144
+// DISASM-NEXT: 1000: {{.*}} movl $8240, %eax
+// 0x3030 - 0x1000 = 0x2030
diff --git a/test/ELF/i386-merge.s b/test/ELF/i386-merge.s
index 00c954945a0f..d895c7327000 100644
--- a/test/ELF/i386-merge.s
+++ b/test/ELF/i386-merge.s
@@ -9,7 +9,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x114
+// CHECK-NEXT: Address: 0x158
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size:
// CHECK-NEXT: Link:
@@ -35,11 +35,10 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 14010000 |
+// CHECK-NEXT: 0000: 58010000 |
// CHECK-NEXT: )
-// The content of .data should be the address of .mysec. 14010000 is 0x114 in
-// little endian.
+// The content of .data should be the address of .mysec.
.data
.long .mysec+4
diff --git a/test/ELF/i386-pic-plt.s b/test/ELF/i386-pic-plt.s
new file mode 100644
index 000000000000..0d32436899a5
--- /dev/null
+++ b/test/ELF/i386-pic-plt.s
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %p/Inputs/i386-pic-plt.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: not ld.lld %t.o %t2.so -o %t -pie 2>&1 | FileCheck %s
+
+// CHECK: error: symbol 'foo' cannot be preempted; recompile with -fPIE
+
+.global _start
+_start:
+ call foo
diff --git a/test/ELF/i386-reloc-16-large-addend.s b/test/ELF/i386-reloc-16-large-addend.s
new file mode 100644
index 000000000000..ceb4862d7935
--- /dev/null
+++ b/test/ELF/i386-reloc-16-large-addend.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+# RUN: ld.lld -Ttext 0x7c00 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 7c00 b800ff
+
+.code16
+.global _start
+_start:
+ movw $_start+0x8300,%ax
diff --git a/test/ELF/i386-reloc-16.s b/test/ELF/i386-reloc-16.s
index d69e6fbc49a7..9a099a6ba3ed 100644
--- a/test/ELF/i386-reloc-16.s
+++ b/test/ELF/i386-reloc-16.s
@@ -4,11 +4,12 @@
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
// RUN: ld.lld -shared %t %t1 -o %t3
+// RUN: llvm-objdump -s %t3 | FileCheck %s
// CHECK: Contents of section .text:
-// CHECK-NEXT: 200000 42
+// CHECK-NEXT: 1000 42
-// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
-// ERROR: relocation R_386_16 out of range: 65536 is not in [0, 65535]
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_386_16 out of range: 65536 is not in [-32768, 32767]
.short foo
diff --git a/test/ELF/i386-reloc-8-large-addend.s b/test/ELF/i386-reloc-8-large-addend.s
new file mode 100644
index 000000000000..61d638040847
--- /dev/null
+++ b/test/ELF/i386-reloc-8-large-addend.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+# RUN: ld.lld -Ttext 0x7c %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 007c b4ff
+
+.code16
+.global _start
+_start:
+ movb $_start+0x83,%ah
diff --git a/test/ELF/i386-reloc-8.s b/test/ELF/i386-reloc-8.s
index c6ae67120e22..b46aaa688261 100644
--- a/test/ELF/i386-reloc-8.s
+++ b/test/ELF/i386-reloc-8.s
@@ -4,11 +4,12 @@
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8-error.s -o %t2
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
// RUN: ld.lld -shared %t %t1 -o %t3
+// RUN: llvm-objdump -s %t3 | FileCheck %s
// CHECK: Contents of section .text:
-// CHECK-NEXT: 200000 42
+// CHECK-NEXT: 1000 ff
-// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
-// ERROR: relocation R_386_8 out of range: 256 is not in [0, 255]
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_386_8 out of range: 256 is not in [-128, 127]
.byte foo
diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s
index 6f72f7af73c7..4378bb6f9d18 100644
--- a/test/ELF/i386-reloc-range.s
+++ b/test/ELF/i386-reloc-range.s
@@ -14,7 +14,7 @@
// CHECK-NEXT: 200: {{.*}} jmp -1
// 0x10202 - 0x203 == 0xffff
-// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s
+// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
// ERR: {{.*}}:(.text+0x1): relocation R_386_PC16 out of range: 65536 is not in [-65536, 65535]
diff --git a/test/ELF/i386-retpoline-nopic-linkerscript.s b/test/ELF/i386-retpoline-nopic-linkerscript.s
new file mode 100644
index 000000000000..4243761d23e4
--- /dev/null
+++ b/test/ELF/i386-retpoline-nopic-linkerscript.s
@@ -0,0 +1,67 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .plt : { *(.plt) } \
+// RUN: .got.plt : { *(.got.plt) } \
+// RUN: .dynstr : { *(.dynstr) } \
+// RUN: }" > %t.script
+// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt --script %t.script
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 10: ff 35 84 00 00 00 pushl 132
+// CHECK-NEXT: 16: 50 pushl %eax
+// CHECK-NEXT: 17: a1 88 00 00 00 movl 136, %eax
+// CHECK-NEXT: 1c: e8 0f 00 00 00 calll 15 <.plt+0x20>
+// CHECK-NEXT: 21: f3 90 pause
+// CHECK-NEXT: 23: 0f ae e8 lfence
+// CHECK-NEXT: 26: eb f9 jmp -7 <.plt+0x11>
+// CHECK-NEXT: 28: cc int3
+// CHECK-NEXT: 29: cc int3
+// CHECK-NEXT: 2a: cc int3
+// CHECK-NEXT: 2b: cc int3
+// CHECK-NEXT: 2c: cc int3
+// CHECK-NEXT: 2d: cc int3
+// CHECK-NEXT: 2e: cc int3
+// CHECK-NEXT: 2f: cc int3
+// CHECK-NEXT: 30: 89 0c 24 movl %ecx, (%esp)
+// CHECK-NEXT: 33: 8b 4c 24 04 movl 4(%esp), %ecx
+// CHECK-NEXT: 37: 89 44 24 04 movl %eax, 4(%esp)
+// CHECK-NEXT: 3b: 89 c8 movl %ecx, %eax
+// CHECK-NEXT: 3d: 59 popl %ecx
+// CHECK-NEXT: 3e: c3 retl
+// CHECK-NEXT: 3f: cc int3
+// CHECK-NEXT: 40: 50 pushl %eax
+// CHECK-NEXT: 41: a1 8c 00 00 00 movl 140, %eax
+// CHECK-NEXT: 46: e8 e5 ff ff ff calll -27 <.plt+0x20>
+// CHECK-NEXT: 4b: e9 d1 ff ff ff jmp -47 <.plt+0x11>
+// CHECK-NEXT: 50: 68 00 00 00 00 pushl $0
+// CHECK-NEXT: 55: e9 b6 ff ff ff jmp -74 <.plt>
+// CHECK-NEXT: 5a: cc int3
+// CHECK-NEXT: 5b: cc int3
+// CHECK-NEXT: 5c: cc int3
+// CHECK-NEXT: 5d: cc int3
+// CHECK-NEXT: 5e: cc int3
+// CHECK-NEXT: 5f: cc int3
+// CHECK-NEXT: 60: 50 pushl %eax
+// CHECK-NEXT: 61: a1 90 00 00 00 movl 144, %eax
+// CHECK-NEXT: 66: e8 c5 ff ff ff calll -59 <.plt+0x20>
+// CHECK-NEXT: 6b: e9 b1 ff ff ff jmp -79 <.plt+0x11>
+// CHECK-NEXT: 70: 68 08 00 00 00 pushl $8
+// CHECK-NEXT: 75: e9 96 ff ff ff jmp -106 <.plt>
+// CHECK-NEXT: 7a: cc int3
+// CHECK-NEXT: 7b: cc int3
+// CHECK-NEXT: 7c: cc int3
+// CHECK-NEXT: 7d: cc int3
+// CHECK-NEXT: 7e: cc int3
+// CHECK-NEXT: 7f: cc int3
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/i386-retpoline-nopic.s b/test/ELF/i386-retpoline-nopic.s
new file mode 100644
index 000000000000..79dd5a63cd69
--- /dev/null
+++ b/test/ELF/i386-retpoline-nopic.s
@@ -0,0 +1,65 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=i386-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.exe -z retpolineplt
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 11010: ff 35 04 20 01 00 pushl 73732
+// CHECK-NEXT: 11016: 50 pushl %eax
+// CHECK-NEXT: 11017: a1 08 20 01 00 movl 73736, %eax
+// CHECK-NEXT: 1101c: e8 0f 00 00 00 calll 15 <.plt+0x20>
+// CHECK-NEXT: 11021: f3 90 pause
+// CHECK-NEXT: 11023: 0f ae e8 lfence
+// CHECK-NEXT: 11026: eb f9 jmp -7 <.plt+0x11>
+// CHECK-NEXT: 11028: cc int3
+// CHECK-NEXT: 11029: cc int3
+// CHECK-NEXT: 1102a: cc int3
+// CHECK-NEXT: 1102b: cc int3
+// CHECK-NEXT: 1102c: cc int3
+// CHECK-NEXT: 1102d: cc int3
+// CHECK-NEXT: 1102e: cc int3
+// CHECK-NEXT: 1102f: cc int3
+// CHECK-NEXT: 11030: 89 0c 24 movl %ecx, (%esp)
+// CHECK-NEXT: 11033: 8b 4c 24 04 movl 4(%esp), %ecx
+// CHECK-NEXT: 11037: 89 44 24 04 movl %eax, 4(%esp)
+// CHECK-NEXT: 1103b: 89 c8 movl %ecx, %eax
+// CHECK-NEXT: 1103d: 59 popl %ecx
+// CHECK-NEXT: 1103e: c3 retl
+// CHECK-NEXT: 1103f: cc int3
+// CHECK-NEXT: 11040: 50 pushl %eax
+// CHECK-NEXT: 11041: a1 0c 20 01 00 movl 73740, %eax
+// CHECK-NEXT: 11046: e8 e5 ff ff ff calll -27 <.plt+0x20>
+// CHECK-NEXT: 1104b: e9 d1 ff ff ff jmp -47 <.plt+0x11>
+// CHECK-NEXT: 11050: 68 00 00 00 00 pushl $0
+// CHECK-NEXT: 11055: e9 b6 ff ff ff jmp -74 <.plt>
+// CHECK-NEXT: 1105a: cc int3
+// CHECK-NEXT: 1105b: cc int3
+// CHECK-NEXT: 1105c: cc int3
+// CHECK-NEXT: 1105d: cc int3
+// CHECK-NEXT: 1105e: cc int3
+// CHECK-NEXT: 1105f: cc int3
+// CHECK-NEXT: 11060: 50 pushl %eax
+// CHECK-NEXT: 11061: a1 10 20 01 00 movl 73744, %eax
+// CHECK-NEXT: 11066: e8 c5 ff ff ff calll -59 <.plt+0x20>
+// CHECK-NEXT: 1106b: e9 b1 ff ff ff jmp -79 <.plt+0x11>
+// CHECK-NEXT: 11070: 68 08 00 00 00 pushl $8
+// CHECK-NEXT: 11075: e9 96 ff ff ff jmp -106 <.plt>
+// CHECK-NEXT: 1107a: cc int3
+// CHECK-NEXT: 1107b: cc int3
+// CHECK-NEXT: 1107c: cc int3
+// CHECK-NEXT: 1107d: cc int3
+// CHECK-NEXT: 1107e: cc int3
+// CHECK-NEXT: 1107f: cc int3
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: 00300100 00000000 00000000 50100100
+// CHECK-NEXT: 70100100
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/i386-retpoline-pic-linkerscript.s b/test/ELF/i386-retpoline-pic-linkerscript.s
new file mode 100644
index 000000000000..6220332f91d1
--- /dev/null
+++ b/test/ELF/i386-retpoline-pic-linkerscript.s
@@ -0,0 +1,64 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .plt : { *(.plt) } \
+// RUN: .got.plt : { *(.got.plt) } \
+// RUN: .dynstr : { *(.dynstr) } \
+// RUN: }" > %t.script
+// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt -pie --script %t.script
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 10: ff b3 84 00 00 00 pushl 132(%ebx)
+// CHECK-NEXT: 16: 50 pushl %eax
+// CHECK-NEXT: 17: 8b 83 88 00 00 00 movl 136(%ebx), %eax
+// CHECK-NEXT: 1d: e8 0e 00 00 00 calll 14 <.plt+0x20>
+// CHECK-NEXT: 22: f3 90 pause
+// CHECK-NEXT: 24: 0f ae e8 lfence
+// CHECK-NEXT: 27: eb f9 jmp -7 <.plt+0x12>
+// CHECK-NEXT: 29: cc int3
+// CHECK-NEXT: 2a: cc int3
+// CHECK-NEXT: 2b: cc int3
+// CHECK-NEXT: 2c: cc int3
+// CHECK-NEXT: 2d: cc int3
+// CHECK-NEXT: 2e: cc int3
+// CHECK-NEXT: 2f: cc int3
+// CHECK-NEXT: 30: 89 0c 24 movl %ecx, (%esp)
+// CHECK-NEXT: 33: 8b 4c 24 04 movl 4(%esp), %ecx
+// CHECK-NEXT: 37: 89 44 24 04 movl %eax, 4(%esp)
+// CHECK-NEXT: 3b: 89 c8 movl %ecx, %eax
+// CHECK-NEXT: 3d: 59 popl %ecx
+// CHECK-NEXT: 3e: c3 retl
+// CHECK-NEXT: 3f: cc int3
+// CHECK-NEXT: 40: 50 pushl %eax
+// CHECK-NEXT: 41: 8b 83 8c 00 00 00 movl 140(%ebx), %eax
+// CHECK-NEXT: 47: e8 e4 ff ff ff calll -28 <.plt+0x20>
+// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
+// CHECK-NEXT: 51: 68 00 00 00 00 pushl $0
+// CHECK-NEXT: 56: e9 b5 ff ff ff jmp -75 <.plt>
+// CHECK-NEXT: 5b: cc int3
+// CHECK-NEXT: 5c: cc int3
+// CHECK-NEXT: 5d: cc int3
+// CHECK-NEXT: 5e: cc int3
+// CHECK-NEXT: 5f: cc int3
+// CHECK-NEXT: 60: 50 pushl %eax
+// CHECK-NEXT: 61: 8b 83 90 00 00 00 movl 144(%ebx), %eax
+// CHECK-NEXT: 67: e8 c4 ff ff ff calll -60 <.plt+0x20>
+// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
+// CHECK-NEXT: 71: 68 08 00 00 00 pushl $8
+// CHECK-NEXT: 76: e9 95 ff ff ff jmp -107 <.plt>
+// CHECK-NEXT: 7b: cc int3
+// CHECK-NEXT: 7c: cc int3
+// CHECK-NEXT: 7d: cc int3
+// CHECK-NEXT: 7e: cc int3
+// CHECK-NEXT: 7f: cc int3
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/i386-retpoline-pic.s b/test/ELF/i386-retpoline-pic.s
new file mode 100644
index 000000000000..3555950b168a
--- /dev/null
+++ b/test/ELF/i386-retpoline-pic.s
@@ -0,0 +1,62 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %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.exe -z retpolineplt -pie
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 1010: ff b3 04 20 00 00 pushl 8196(%ebx)
+// CHECK-NEXT: 1016: 50 pushl %eax
+// CHECK-NEXT: 1017: 8b 83 08 20 00 00 movl 8200(%ebx), %eax
+// CHECK-NEXT: 101d: e8 0e 00 00 00 calll 14 <.plt+0x20>
+// CHECK-NEXT: 1022: f3 90 pause
+// CHECK-NEXT: 1024: 0f ae e8 lfence
+// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12>
+// CHECK-NEXT: 1029: cc int3
+// CHECK-NEXT: 102a: cc int3
+// CHECK-NEXT: 102b: cc int3
+// CHECK-NEXT: 102c: cc int3
+// CHECK-NEXT: 102d: cc int3
+// CHECK-NEXT: 102e: cc int3
+// CHECK-NEXT: 102f: cc int3
+// CHECK-NEXT: 1030: 89 0c 24 movl %ecx, (%esp)
+// CHECK-NEXT: 1033: 8b 4c 24 04 movl 4(%esp), %ecx
+// CHECK-NEXT: 1037: 89 44 24 04 movl %eax, 4(%esp)
+// CHECK-NEXT: 103b: 89 c8 movl %ecx, %eax
+// CHECK-NEXT: 103d: 59 popl %ecx
+// CHECK-NEXT: 103e: c3 retl
+// CHECK-NEXT: 103f: cc int3
+// CHECK-NEXT: 1040: 50 pushl %eax
+// CHECK-NEXT: 1041: 8b 83 0c 20 00 00 movl 8204(%ebx), %eax
+// CHECK-NEXT: 1047: e8 e4 ff ff ff calll -28 <.plt+0x20>
+// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
+// CHECK-NEXT: 1051: 68 00 00 00 00 pushl $0
+// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt>
+// CHECK-NEXT: 105b: cc int3
+// CHECK-NEXT: 105c: cc int3
+// CHECK-NEXT: 105d: cc int3
+// CHECK-NEXT: 105e: cc int3
+// CHECK-NEXT: 105f: cc int3
+// CHECK-NEXT: 1060: 50 pushl %eax
+// CHECK-NEXT: 1061: 8b 83 10 20 00 00 movl 8208(%ebx), %eax
+// CHECK-NEXT: 1067: e8 c4 ff ff ff calll -60 <.plt+0x20>
+// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
+// CHECK-NEXT: 1071: 68 08 00 00 00 pushl $8
+// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt>
+// CHECK-NEXT: 107b: cc int3
+// CHECK-NEXT: 107c: cc int3
+// CHECK-NEXT: 107d: cc int3
+// CHECK-NEXT: 107e: cc int3
+// CHECK-NEXT: 107f: cc int3
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: 2000 00300000 00000000 00000000 51100000
+// CHECK-NEXT: 2010 71100000
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/i386-tls-got.s b/test/ELF/i386-tls-got.s
index 56be4a138d9b..efd45152164f 100644
--- a/test/ELF/i386-tls-got.s
+++ b/test/ELF/i386-tls-got.s
@@ -2,6 +2,6 @@
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-tls-got.s -o %t1.o
# RUN: ld.lld %t1.o -o %t1.so -shared
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t2.o
-# RUN: ld.lld %t2.o %t1.so -o %t
+# RUN: ld.lld %t2.o %t1.so -o /dev/null
addl foobar@INDNTPOFF, %eax
diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s
index 2b842a86eb0f..9e5ed1bcc462 100644
--- a/test/ELF/i386-tls-ie-shared.s
+++ b/test/ELF/i386-tls-ie-shared.s
@@ -1,3 +1,4 @@
+// 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/tls-opt-iele-i686-nopic.s -o %tso.o
// RUN: ld.lld -shared %tso.o -o %tso
diff --git a/test/ELF/icf-absolute.s b/test/ELF/icf-absolute.s
index 09f6790907a1..3eef7a2d7e28 100644
--- a/test/ELF/icf-absolute.s
+++ b/test/ELF/icf-absolute.s
@@ -2,10 +2,10 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-absolute.s -o %t2
-# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t %t2 -o /dev/null --icf=all --print-icf-sections | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf-c-identifier.s b/test/ELF/icf-c-identifier.s
new file mode 100644
index 000000000000..cd11b98b57a6
--- /dev/null
+++ b/test/ELF/icf-c-identifier.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | count 0
+
+.section foo,"ax",@progbits,unique,0
+.byte 42
+
+.section foo,"ax",@progbits,unique,1
+.byte 42
diff --git a/test/ELF/icf-comdat.s b/test/ELF/icf-comdat.s
index aab6a00f484d..761dd2ecdc96 100644
--- a/test/ELF/icf-comdat.s
+++ b/test/ELF/icf-comdat.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf-different-output-sections.s b/test/ELF/icf-different-output-sections.s
new file mode 100644
index 000000000000..085573120e4e
--- /dev/null
+++ b/test/ELF/icf-different-output-sections.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | count 0
+
+.section .foo,"ax"
+.byte 42
+
+.section .bar,"ax"
+.byte 42
diff --git a/test/ELF/icf-i386.s b/test/ELF/icf-i386.s
index b01e0503d405..67c7262dadde 100644
--- a/test/ELF/icf-i386.s
+++ b/test/ELF/icf-i386.s
@@ -2,11 +2,11 @@
# This test is to make sure that we can handle implicit addends properly.
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
-# CHECK-NOT: removed .text.f3
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
+# CHECK-NOT: removing identical section {{.*}}:(.text.f3)
.globl _start, f1, f2, f3
_start:
diff --git a/test/ELF/icf-keep-unique.s b/test/ELF/icf-keep-unique.s
new file mode 100644
index 000000000000..a6f883fc7b2a
--- /dev/null
+++ b/test/ELF/icf-keep-unique.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t -o %t2 --keep-unique f2 --keep-unique f4 --keep-unique f5 --icf=all --print-icf-sections 2>&1 | FileCheck %s -check-prefix=CHECK-KEEP
+
+// Base case, expect only .text.f1 to be kept
+// CHECK: selected section {{.*}}:(.text.f1)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f2)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f3)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f4)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f5)
+
+// With --keep-unique f2, f4 and f5 we expect only f3 and f5 to be removed.
+// f5 is not matched by --keep-unique as it is a local symbol.
+// CHECK-KEEP: warning: could not find symbol f5 to keep unique
+// CHECK-KEEP: selected section {{.*}}:(.text.f1)
+// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f3)
+// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f5)
+ .globl _start, f1, f2, f3, f4
+_start:
+ ret
+
+ .section .text.f1, "ax"
+f1:
+ nop
+
+ .section .text.f2, "ax"
+f2:
+ nop
+
+.section .text.f3, "ax"
+f3:
+ nop
+
+.section .text.f4, "ax"
+f4:
+ nop
+
+# f5 is local, not found by --keep-unique f5
+.section .text.f5, "ax"
+f5:
+ nop
diff --git a/test/ELF/icf-link-order.s b/test/ELF/icf-link-order.s
new file mode 100644
index 000000000000..440971de0f03
--- /dev/null
+++ b/test/ELF/icf-link-order.s
@@ -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 --icf=all --print-icf-sections | count 0
+
+.section .foo,"a",@progbits,unique,1
+foo1:
+.byte 1
+
+.section .foo,"a",@progbits,unique,2
+foo2:
+.byte 2
+
+.section .bar,"ao",@progbits,foo1,unique,1
+.byte 3
+
+.section .bar,"ao",@progbits,foo2,unique,2
+.byte 3
diff --git a/test/ELF/icf-many-sections.s b/test/ELF/icf-many-sections.s
new file mode 100644
index 000000000000..766a003dd77d
--- /dev/null
+++ b/test/ELF/icf-many-sections.s
@@ -0,0 +1,62 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
+# RUN: ld.lld --icf=all --print-icf-sections %t -o /dev/null | FileCheck %s -allow-empty
+
+# CHECK-NOT: selected
+
+.macro gen_sections4 z
+ .section .a\z,"ax"
+ .section .b\z,"ax"
+ .section .c\z,"ax"
+ .section .d\z,"ax"
+.endm
+
+.macro gen_sections8 z
+ gen_sections4 a\z
+ gen_sections4 b\z
+.endm
+
+.macro gen_sections16 z
+ gen_sections8 a\z
+ gen_sections8 b\z
+.endm
+
+.macro gen_sections32 x
+ gen_sections16 a\x
+ gen_sections16 b\x
+.endm
+
+.macro gen_sections64 z
+ gen_sections32 a\z
+ gen_sections32 b\z
+.endm
+
+.macro gen_sections128 z
+ gen_sections64 a\z
+ gen_sections64 b\z
+.endm
+
+.macro gen_sections256 z
+ gen_sections128 a\z
+ gen_sections128 b\z
+.endm
+
+.macro gen_sections512 z
+ gen_sections256 a\z
+ gen_sections256 b\z
+.endm
+
+.macro gen_sections1024 z
+ gen_sections512 a\z
+ gen_sections512 b\z
+.endm
+
+.macro gen_sections2048 z
+ gen_sections1024 a\z
+ gen_sections1024 b\z
+.endm
+
+gen_sections2048 a
+
+.global _start
+_start:
diff --git a/test/ELF/icf-merge-sec.s b/test/ELF/icf-merge-sec.s
index 1e866a0caa49..060f19d34694 100644
--- a/test/ELF/icf-merge-sec.s
+++ b/test/ELF/icf-merge-sec.s
@@ -2,10 +2,10 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge-sec.s -o %t2
-# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t %t2 -o /dev/null --icf=all --print-icf-sections | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
.section .rodata.str,"aMS",@progbits,1
.asciz "foo"
diff --git a/test/ELF/icf-merge.s b/test/ELF/icf-merge.s
index 06e852fe9dd5..5aa79f9d14ec 100644
--- a/test/ELF/icf-merge.s
+++ b/test/ELF/icf-merge.s
@@ -2,18 +2,18 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge.s -o %t1
-# RUN: ld.lld %t %t1 -o %t1.out --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t %t1 -o /dev/null --icf=all --print-icf-sections | FileCheck %s
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge2.s -o %t2
-# RUN: ld.lld %t %t2 -o %t3.out --icf=all --verbose 2>&1 | FileCheck --check-prefix=NOMERGE %s
+# RUN: ld.lld %t %t2 -o %t3.out --icf=all --print-icf-sections | FileCheck --check-prefix=NOMERGE %s
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge3.s -o %t3
-# RUN: ld.lld %t %t3 -o %t3.out --icf=all --verbose 2>&1 | FileCheck --check-prefix=NOMERGE %s
+# RUN: ld.lld %t %t3 -o %t3.out --icf=all --print-icf-sections | FileCheck --check-prefix=NOMERGE %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
-# NOMERGE-NOT: selected .text.f
+# NOMERGE-NOT: selected section {{.*}}:(.text.f)
.section .rodata.str,"aMS",@progbits,1
foo:
diff --git a/test/ELF/icf-merge2.s b/test/ELF/icf-merge2.s
new file mode 100644
index 000000000000..47c4c88d449a
--- /dev/null
+++ b/test/ELF/icf-merge2.s
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t --icf=all
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# Test that we don't merge these.
+# CHECK: leaq
+# CHECK: leaq
+
+ .section .merge1, "aM", @progbits, 8
+.Lfoo:
+ .quad 42
+
+ .section .merge2, "aM", @progbits, 4
+.Lbar:
+ .long 41
+
+ .section .text.foo, "ax", @progbits
+ leaq .Lfoo(%rip), %rax
+
+ .section .text.bar, "ax", @progbits
+ leaq .Lbar(%rip), %rax
diff --git a/test/ELF/icf-merged-sections.s b/test/ELF/icf-merged-sections.s
new file mode 100644
index 000000000000..1f6e77ec5353
--- /dev/null
+++ b/test/ELF/icf-merged-sections.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck -allow-empty --check-prefix=NOICF %s
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# Check that merge synthetic sections are not merged by ICF.
+
+# NOICF-NOT: selected section <internal>:(.rodata)
+
+# CHECK: Name: .rodata
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment: 8
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 67452301 10325476 67452301 10325476
+
+.section .rodata.cst4,"aM",@progbits,4
+rodata4:
+ .long 0x01234567
+ .long 0x76543210
+ .long 0x01234567
+ .long 0x76543210
+
+.section .rodata.cst8,"aM",@progbits,8
+rodata8:
+ .long 0x01234567
+ .long 0x76543210
diff --git a/test/ELF/icf-non-mergeable.s b/test/ELF/icf-non-mergeable.s
index 48ba2008cacc..978ac156b70e 100644
--- a/test/ELF/icf-non-mergeable.s
+++ b/test/ELF/icf-non-mergeable.s
@@ -8,10 +8,10 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
// RUN: %p/Inputs/icf-non-mergeable.s -o %t2
-// RUN: ld.lld %t1 %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s
+// RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --verbose 2>&1 | FileCheck %s
-// CHECK-NOT: selected .text.f1
-// CHECK-NOT: removed .text.f2
+// CHECK-NOT: selected section '.text.f1'
+// CHECK-NOT: removing identical section '.text.f2'
.globl _start, f1, f2, d1, d2
_start:
diff --git a/test/ELF/icf-none.s b/test/ELF/icf-none.s
index 9ec1406de8a4..7c73361c2ce3 100644
--- a/test/ELF/icf-none.s
+++ b/test/ELF/icf-none.s
@@ -1,9 +1,9 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --icf=none --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --icf=none --verbose 2>&1 | FileCheck %s
-# CHECK-NOT: selected .text.f1
+# CHECK-NOT: selected section '.text.f1'
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf-relro.s b/test/ELF/icf-relro.s
new file mode 100644
index 000000000000..874fa7b19f97
--- /dev/null
+++ b/test/ELF/icf-relro.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o /dev/null --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck %s
+
+# CHECK: selected section {{.*}}:(.data.rel.ro)
+# CHECK: removing identical section {{.*}}:(.data.rel.ro.foo)
+
+.section .data.rel.ro,"aw"
+.quad foo
+
+.section .data.rel.ro.foo,"aw"
+foo:
+.quad foo
diff --git a/test/ELF/icf-safe.s b/test/ELF/icf-safe.s
new file mode 100644
index 000000000000..b001fcc82ce4
--- /dev/null
+++ b/test/ELF/icf-safe.s
@@ -0,0 +1,182 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-objcopy %t1.o %t1copy.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-safe.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections -shared | FileCheck --check-prefix=EXPORT %s
+# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
+# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections | FileCheck --check-prefix=ALL %s
+# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
+# RUN: ld.lld %t1copy.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=OBJCOPY %s
+
+# CHECK-NOT: selected section {{.*}}:(.rodata.l1)
+# CHECK: selected section {{.*}}:(.rodata.l3)
+# CHECK: removing identical section {{.*}}:(.rodata.l4)
+
+# CHECK-NOT: selected section {{.*}}:(.text.f1)
+# CHECK: selected section {{.*}}:(.text.f3)
+# CHECK: removing identical section {{.*}}:(.text.f4)
+
+# CHECK-NOT: selected section {{.*}}:(.rodata.h1)
+# CHECK: selected section {{.*}}:(.rodata.h3)
+# CHECK: removing identical section {{.*}}:(.rodata.h4)
+
+# CHECK-NOT: selected section {{.*}}:(.rodata.g1)
+# CHECK: selected section {{.*}}:(.rodata.g3)
+# CHECK: removing identical section {{.*}}:(.rodata.g4)
+
+# CHECK-NOT: selected section {{.*}}:(.text.non_addrsig{{.}})
+
+# With --icf=all address-significance implies keep-unique only for rodata, not
+# text.
+# ALL-NOT: selected section {{.*}}:(.rodata.l1)
+# ALL: selected section {{.*}}:(.rodata.l3)
+# ALL: removing identical section {{.*}}:(.rodata.l4)
+
+# ALL: selected section {{.*}}:(.text.f3)
+# ALL: removing identical section {{.*}}:(.text.f4)
+
+# ALL: selected section {{.*}}:(.text.f1)
+# ALL: removing identical section {{.*}}:(.text.f2)
+# ALL: removing identical section {{.*}}:(.text.non_addrsig1)
+# ALL: removing identical section {{.*}}:(.text.non_addrsig2)
+
+# ALL-NOT: selected section {{.*}}:(.rodata.h1)
+# ALL: selected section {{.*}}:(.rodata.h3)
+# ALL: removing identical section {{.*}}:(.rodata.h4)
+
+# ALL-NOT: selected section {{.*}}:(.rodata.g1)
+# ALL: selected section {{.*}}:(.rodata.g3)
+# ALL: removing identical section {{.*}}:(.rodata.g4)
+
+# llvm-mc normally emits an empty .text section into every object file. Since
+# nothing actually refers to it via a relocation, it doesn't have any associated
+# symbols (thus nor can anything refer to it via a relocation, making it safe to
+# merge with the empty section in the other input file). Here we check that the
+# only two sections merged are the two empty sections and the sections with only
+# STB_LOCAL or STV_HIDDEN symbols. The dynsym entries should have prevented
+# anything else from being merged.
+# EXPORT-NOT: selected section
+# EXPORT: selected section {{.*}}:(.rodata.l3)
+# EXPORT: removing identical section {{.*}}:(.rodata.l4)
+# EXPORT-NOT: selected section
+# EXPORT: selected section {{.*}}:(.rodata.h3)
+# EXPORT: removing identical section {{.*}}:(.rodata.h4)
+# EXPORT-NOT: selected section
+# EXPORT: selected section {{.*}}:(.text)
+# EXPORT: removing identical section {{.*}}:(.text)
+# EXPORT-NOT: selected section
+
+# If --icf=all is specified when exporting we can also merge the exported text
+# sections, but not the exported rodata.
+# ALL-EXPORT-NOT: selected section
+# ALL-EXPORT: selected section {{.*}}:(.rodata.l3)
+# ALL-EXPORT: removing identical section {{.*}}:(.rodata.l4)
+# ALL-EXPORT-NOT: selected section
+# ALL-EXPORT: selected section {{.*}}:(.text.f3)
+# ALL-EXPORT: removing identical section {{.*}}:(.text.f4)
+# ALL-EXPORT-NOT: selected section
+# ALL-EXPORT: selected section {{.*}}:(.text.f1)
+# ALL-EXPORT: removing identical section {{.*}}:(.text.f2)
+# ALL-EXPORT: removing identical section {{.*}}:(.text.non_addrsig1)
+# ALL-EXPORT: removing identical section {{.*}}:(.text.non_addrsig2)
+# ALL-EXPORT-NOT: selected section
+# ALL-EXPORT: selected section {{.*}}:(.rodata.h3)
+# ALL-EXPORT: removing identical section {{.*}}:(.rodata.h4)
+# ALL-EXPORT-NOT: selected section
+# ALL-EXPORT: selected section {{.*}}:(.text)
+# ALL-EXPORT: removing identical section {{.*}}:(.text)
+# ALL-EXPORT-NOT: selected section
+
+# OBJCOPY: --icf=safe is incompatible with object files created using objcopy or ld -r
+
+.section .text.f1,"ax",@progbits
+.globl f1
+f1:
+ret
+
+.section .text.f2,"ax",@progbits
+.globl f2
+f2:
+ret
+
+.section .text.f3,"ax",@progbits
+.globl f3
+f3:
+ud2
+
+.section .text.f4,"ax",@progbits
+.globl f4
+f4:
+ud2
+
+.section .rodata.g1,"a",@progbits
+.globl g1
+g1:
+.byte 1
+
+.section .rodata.g2,"a",@progbits
+.globl g2
+g2:
+.byte 1
+
+.section .rodata.g3,"a",@progbits
+.globl g3
+g3:
+.byte 2
+
+.section .rodata.g4,"a",@progbits
+.globl g4
+g4:
+.byte 2
+
+.section .rodata.l1,"a",@progbits
+l1:
+.byte 3
+
+.section .rodata.l2,"a",@progbits
+l2:
+.byte 3
+
+.section .rodata.l3,"a",@progbits
+l3:
+.byte 4
+
+.section .rodata.l4,"a",@progbits
+l4:
+.byte 4
+
+.section .rodata.h1,"a",@progbits
+.globl h1
+.hidden h1
+h1:
+.byte 5
+
+.section .rodata.h2,"a",@progbits
+.globl h2
+.hidden h2
+h2:
+.byte 5
+
+.section .rodata.h3,"a",@progbits
+.globl h3
+.hidden h3
+h3:
+.byte 6
+
+.section .rodata.h4,"a",@progbits
+.globl h4
+.hidden h4
+h4:
+.byte 6
+
+.addrsig
+.addrsig_sym f1
+.addrsig_sym f2
+.addrsig_sym g1
+.addrsig_sym g2
+.addrsig_sym l1
+.addrsig_sym l2
+.addrsig_sym h1
+.addrsig_sym h2
diff --git a/test/ELF/icf1.s b/test/ELF/icf1.s
index e2562b5a83e7..5c6e667d53c7 100644
--- a/test/ELF/icf1.s
+++ b/test/ELF/icf1.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf10.test b/test/ELF/icf10.test
new file mode 100644
index 000000000000..96b4caf2f2e5
--- /dev/null
+++ b/test/ELF/icf10.test
@@ -0,0 +1,40 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s
+
+# Checks that ICF does not merge 2 sections the offset of
+# the relocations of which differ.
+
+# CHECK-NOT: selected
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR]
+ Content: "FFFFFFFFFFFFFFFF"
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR]
+ Content: "FFFFFFFFFFFFFFFF"
+ - Name: .rela.text.foo
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text.foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: ''
+ Type: R_X86_64_NONE
+ - Name: .rela.text.bar
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text.bar
+ Relocations:
+ - Offset: 0x0000000000000001
+ Symbol: ''
+ Type: R_X86_64_NONE
diff --git a/test/ELF/icf11.test b/test/ELF/icf11.test
new file mode 100644
index 000000000000..8c3aa93568d7
--- /dev/null
+++ b/test/ELF/icf11.test
@@ -0,0 +1,52 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s
+
+# Checks that ICF does not merge 2 sections the type of
+# the relocations of which differ.
+
+# CHECK-NOT: selected
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: "0000000000000000"
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR]
+ Content: "FFFFFFFFFFFFFFFF"
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR]
+ Content: "FFFFFFFFFFFFFFFF"
+ - Name: .rela.text.foo
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text.foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: ''
+ Type: R_X86_64_NONE
+ - Name: .rela.text.bar
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text.bar
+ Relocations:
+ - Offset: 0
+ Symbol: zed
+ Type: R_X86_64_64
+Symbols:
+ Global:
+ - Name: zed
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0
+ Size: 8
diff --git a/test/ELF/icf12.s b/test/ELF/icf12.s
new file mode 100644
index 000000000000..aa1e8af9ebd6
--- /dev/null
+++ b/test/ELF/icf12.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
+
+# Check that ICF does not merge 2 sections which relocations
+# differs in addend only.
+
+# CHECK-NOT: selected
+
+.section .text
+.globl _start
+_start:
+ ret
+
+.section .text.foo, "ax"
+.quad _start + 1
+
+.section .text.bar, "ax"
+.quad _start + 2
diff --git a/test/ELF/icf13.s b/test/ELF/icf13.s
new file mode 100644
index 000000000000..2fe707f11c76
--- /dev/null
+++ b/test/ELF/icf13.s
@@ -0,0 +1,20 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld -shared -z notext %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
+
+## Check that ICF does not merge sections which relocations point to symbols
+## that are not of the regular defined kind.
+
+# CHECK-NOT: selected
+
+.globl und
+
+.section .text
+.globl _start
+_start:
+ ret
+
+.section .text.foo, "ax"
+.quad _start
+
+.section .text.bar, "ax"
+.quad und
diff --git a/test/ELF/icf14.s b/test/ELF/icf14.s
new file mode 100644
index 000000000000..caa33e4d14bc
--- /dev/null
+++ b/test/ELF/icf14.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
+
+# Check that ICF does not merge 2 sections which relocations
+# refer to symbols that live in sections of the different types
+# (regular input section and mergeable input sections in this case).
+
+# CHECK-NOT: selected
+
+.section .text
+.globl _start
+_start:
+ ret
+
+.section .rodata.str,"aMS",@progbits,1
+.globl rodata
+rodata:
+.asciz "foo"
+
+.section .text.foo, "ax"
+.quad rodata
+
+.section .text.bar, "ax"
+.quad _start
diff --git a/test/ELF/icf15.s b/test/ELF/icf15.s
new file mode 100644
index 000000000000..57c1735e1518
--- /dev/null
+++ b/test/ELF/icf15.s
@@ -0,0 +1,23 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
+
+## Check that ICF does not merge sections which relocations have equal addends,
+## but different target values.
+
+# CHECK-NOT: selected
+
+.globl und
+
+.section .text
+.globl foo
+foo:
+ .byte 0
+.globl bar
+bar:
+ .byte 0
+
+.section .text.foo, "ax"
+.quad foo
+
+.section .text.bar, "ax"
+.quad bar
diff --git a/test/ELF/icf16.s b/test/ELF/icf16.s
new file mode 100644
index 000000000000..e7650af37c3b
--- /dev/null
+++ b/test/ELF/icf16.s
@@ -0,0 +1,23 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld -shared -z notext %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
+
+## ICF is able to merge sections which relocations referring regular input sections
+## or mergeable sections. .eh_frame is represented with a different kind of section,
+## here we check that ICF code is able to handle and will not merge sections which
+## relocations referring .eh_frame.
+
+# CHECK-NOT: selected
+
+.section ".eh_frame", "a", @progbits
+.globl foo
+foo:
+ .quad 0
+.globl bar
+bar:
+ .quad 0
+
+.section .text.foo, "ax"
+.quad foo
+
+.section .text.bar, "ax"
+.quad bar
diff --git a/test/ELF/icf2.s b/test/ELF/icf2.s
index fd0a311cbd1d..8a456c7ee018 100644
--- a/test/ELF/icf2.s
+++ b/test/ELF/icf2.s
@@ -2,10 +2,10 @@
# 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 2>&1 | FileCheck %s
+# RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf3.s b/test/ELF/icf3.s
index 40067cefb200..7ae4acfb131c 100644
--- a/test/ELF/icf3.s
+++ b/test/ELF/icf3.s
@@ -2,10 +2,10 @@
# 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 2>&1 | FileCheck %s
+# RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
-# CHECK-NOT: Selected .text.f1
-# CHECK-NOT: Selected .text.f2
+# CHECK-NOT: selected section '.text.f1' from file
+# CHECK-NOT: selected section '.text.f2' from file
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf4.s b/test/ELF/icf4.s
index b7f40e805733..2b047968181c 100644
--- a/test/ELF/icf4.s
+++ b/test/ELF/icf4.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
-# CHECK-NOT: Selected .text.f1
-# CHECK-NOT: Selected .text.f2
+# CHECK-NOT: selected section '.text.f1'
+# CHECK-NOT: selected section '.text.f2'
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf5.s b/test/ELF/icf5.s
index 749cc5e923a0..86c0bc4b9e40 100644
--- a/test/ELF/icf5.s
+++ b/test/ELF/icf5.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
-# CHECK-NOT: Selected .text.f1
-# CHECK-NOT: Selected .text.f2
+# CHECK-NOT: selected section '.text.f1'
+# CHECK-NOT: selected section '.text.f2'
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf6.s b/test/ELF/icf6.s
index 6420868523bf..0819d51f1844 100644
--- a/test/ELF/icf6.s
+++ b/test/ELF/icf6.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
-# CHECK-NOT: Selected .text.f1
-# CHECK-NOT: Selected .text.f2
+# CHECK-NOT: selected section '.text.f1'
+# CHECK-NOT: selected section '.text.f2'
.globl _start, f1, f2
_start:
diff --git a/test/ELF/icf7.s b/test/ELF/icf7.s
index 00fca793aeea..00383adbc0eb 100644
--- a/test/ELF/icf7.s
+++ b/test/ELF/icf7.s
@@ -1,11 +1,11 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s
# RUN: llvm-objdump -t %t2 | FileCheck -check-prefix=ALIGN %s
-# CHECK: selected .text.f1
-# CHECK: removed .text.f2
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f2)
# ALIGN: 0000000000201000 .text 00000000 _start
# ALIGN: 0000000000201100 .text 00000000 f1
diff --git a/test/ELF/icf9.s b/test/ELF/icf9.s
index de6db60f9684..809267700497 100644
--- a/test/ELF/icf9.s
+++ b/test/ELF/icf9.s
@@ -2,20 +2,21 @@
### Make sure that we do not merge data.
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s
# RUN: llvm-readelf -S -W %t2 | FileCheck --check-prefix=SEC %s
# SEC: .rodata PROGBITS 0000000000200120 000120 000002 00 A 0 0 1
-# CHECK-NOT: selected .rodata.d1
-# CHECK-NOT: selected .rodata.d2
+# CHECK-NOT: selected section {{.*}}:(.rodata.d1)
+# CHECK-NOT: selected section {{.*}}:(.rodata.d2)
# We do merge rodata if passed --icf-data
-# RUN: ld.lld %t -o %t2 --icf=all --verbose --icf-data 2>&1 | FileCheck --check-prefix=DATA %s
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections --ignore-data-address-equality | \
+# RUN: FileCheck --check-prefix=DATA %s
# RUN: llvm-readelf -S -W %t2 | FileCheck --check-prefix=DATA-SEC %s
-# DATA: selected .rodata.d1
-# DATA: removed .rodata.d2
+# DATA: selected section {{.*}}:(.rodata.d1)
+# DATA: removing identical section {{.*}}:(.rodata.d2)
# DATA-SEC: .rodata PROGBITS 0000000000200120 000120 000001 00 A 0 0 1
diff --git a/test/ELF/ignore-plugin.test b/test/ELF/ignore-plugin.test
new file mode 100644
index 000000000000..fcd3fa64195c
--- /dev/null
+++ b/test/ELF/ignore-plugin.test
@@ -0,0 +1,2 @@
+RUN: not ld.lld --plugin foo 2>&1 | FileCheck %s
+CHECK: no input files
diff --git a/test/ELF/incompatible-ar-first.s b/test/ELF/incompatible-ar-first.s
index e076561d11ae..fbbe9de761ec 100644
--- a/test/ELF/incompatible-ar-first.s
+++ b/test/ELF/incompatible-ar-first.s
@@ -1,11 +1,11 @@
+// REQUIRES: x86
// 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
+// RUN: not ld.lld %t.a %tb.o -o /dev/null 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({{.*}}a.o) is incompatible with {{.*}}b.o
-// REQUIRES: x86
diff --git a/test/ELF/incompatible-section-flags.s b/test/ELF/incompatible-section-flags.s
index 25d99945e009..30bbe75d766a 100644
--- a/test/ELF/incompatible-section-flags.s
+++ b/test/ELF/incompatible-section-flags.s
@@ -1,5 +1,6 @@
+// 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 2>&1 | FileCheck %s
+// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
// CHECK: error: incompatible section flags for .foo
// CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.foo): 0x3
diff --git a/test/ELF/incompatible-section-types2.s b/test/ELF/incompatible-section-types2.s
index 146e680ab271..3e281ce6c5da 100644
--- a/test/ELF/incompatible-section-types2.s
+++ b/test/ELF/incompatible-section-types2.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
// CHECK: error: section type mismatch for .shstrtab
// CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB
diff --git a/test/ELF/incompatible.s b/test/ELF/incompatible.s
index ce84606ad7e2..44c5b4bfcbf7 100644
--- a/test/ELF/incompatible.s
+++ b/test/ELF/incompatible.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86,aarch64
// 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
@@ -49,11 +50,10 @@
// 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
+// RUN: not ld.lld %t.a %tb.o 2>&1 -o %t | FileCheck --check-prefix=ARCHIVE %s
// ARCHIVE: .a({{.*}}a.o) is incompatible with {{.*}}b.o
.global _start
_start:
.data
.long foo
-// REQUIRES: x86,aarch64
diff --git a/test/ELF/init_fini_priority.s b/test/ELF/init_fini_priority.s
index b10b925063e5..17003ce30dfe 100644
--- a/test/ELF/init_fini_priority.s
+++ b/test/ELF/init_fini_priority.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
// RUN: llvm-objdump -section-headers %t | FileCheck %s --check-prefix=OBJ
// RUN: ld.lld %t -o %t.exe
// RUN: llvm-objdump -s %t.exe | FileCheck %s
-// REQUIRES: x86
// OBJ: 3 .init_array
// OBJ-NEXT: 4 .init_array.100
diff --git a/test/ELF/invalid-cie-length.s b/test/ELF/invalid-cie-length.s
index c6da95e609d6..7e73dd8aa5d3 100644
--- a/test/ELF/invalid-cie-length.s
+++ b/test/ELF/invalid-cie-length.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.byte 0
diff --git a/test/ELF/invalid-cie-length2.s b/test/ELF/invalid-cie-length2.s
index 9140280ba5a7..a43491c17790 100644
--- a/test/ELF/invalid-cie-length2.s
+++ b/test/ELF/invalid-cie-length2.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.long 42
diff --git a/test/ELF/invalid-cie-length3.s b/test/ELF/invalid-cie-length3.s
index fcbfa7f52ba8..3417efcba8fa 100644
--- a/test/ELF/invalid-cie-length3.s
+++ b/test/ELF/invalid-cie-length3.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.long 0xFFFFFFFC
diff --git a/test/ELF/invalid-cie-length4.s b/test/ELF/invalid-cie-length4.s
index 04f8eb2cca6b..cf3a6f513747 100644
--- a/test/ELF/invalid-cie-length4.s
+++ b/test/ELF/invalid-cie-length4.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.long 0xFFFFFFFF
diff --git a/test/ELF/invalid-cie-length5.s b/test/ELF/invalid-cie-length5.s
index bfa35edf7db5..223ce125853b 100644
--- a/test/ELF/invalid-cie-length5.s
+++ b/test/ELF/invalid-cie-length5.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.long 0xFFFFFFFF
diff --git a/test/ELF/invalid-cie-reference.s b/test/ELF/invalid-cie-reference.s
index fba2467e216a..0f64c4a429b4 100644
--- a/test/ELF/invalid-cie-reference.s
+++ b/test/ELF/invalid-cie-reference.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
.section .eh_frame
.long 0x14
diff --git a/test/ELF/invalid-eh-frame.s b/test/ELF/invalid-eh-frame.s
new file mode 100644
index 000000000000..533442872346
--- /dev/null
+++ b/test/ELF/invalid-eh-frame.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: unexpected end of CIE
+# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x8)
+
+.section .eh_frame
+ .byte 0x04
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
diff --git a/test/ELF/invalid-eh-frame2.s b/test/ELF/invalid-eh-frame2.s
new file mode 100644
index 000000000000..c8995cbe1c81
--- /dev/null
+++ b/test/ELF/invalid-eh-frame2.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read string)
+# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x9)
+
+.section .eh_frame
+.align 1
+ .byte 0x08
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame3.s b/test/ELF/invalid-eh-frame3.s
new file mode 100644
index 000000000000..44592cbe3c89
--- /dev/null
+++ b/test/ELF/invalid-eh-frame3.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read LEB128)
+# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xC)
+
+.section .eh_frame
+ .byte 0x08
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x00
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame4.s b/test/ELF/invalid-eh-frame4.s
new file mode 100644
index 000000000000..4022c04476dc
--- /dev/null
+++ b/test/ELF/invalid-eh-frame4.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string:
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame5.s b/test/ELF/invalid-eh-frame5.s
new file mode 100644
index 000000000000..eb153fa92c49
--- /dev/null
+++ b/test/ELF/invalid-eh-frame5.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string:
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x03
+ .byte 0x01
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame6.s b/test/ELF/invalid-eh-frame6.s
new file mode 100644
index 000000000000..9b6b7f8bf87a
--- /dev/null
+++ b/test/ELF/invalid-eh-frame6.s
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: unknown FDE encoding
+# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xE)
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame7.s b/test/ELF/invalid-eh-frame7.s
new file mode 100644
index 000000000000..81a0014049e0
--- /dev/null
+++ b/test/ELF/invalid-eh-frame7.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: DW_EH_PE_aligned encoding is not supported
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x51
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame8.s b/test/ELF/invalid-eh-frame8.s
new file mode 100644
index 000000000000..484fef29f8b3
--- /dev/null
+++ b/test/ELF/invalid-eh-frame8.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: corrupted CIE
+
+.section .eh_frame
+ .byte 0x0E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+
+ .byte 0x50 # Augmentation string: 'P','\0'
+ .byte 0x00
+
+ .byte 0x01
+
+ .byte 0x01 # LEB128
+ .byte 0x01 # LEB128
+
+ .byte 0x03
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
diff --git a/test/ELF/invalid-eh-frame9.s b/test/ELF/invalid-eh-frame9.s
new file mode 100644
index 000000000000..73a102b4f90d
--- /dev/null
+++ b/test/ELF/invalid-eh-frame9.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: corrupted .eh_frame: CIE is too small
+
+.section .eh_frame
+ .byte 0x03
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
diff --git a/test/ELF/invalid-fde-rel.s b/test/ELF/invalid-fde-rel.s
index f43b9da30033..f6513225b533 100644
--- a/test/ELF/invalid-fde-rel.s
+++ b/test/ELF/invalid-fde-rel.s
@@ -33,4 +33,4 @@
.long 0x0
.long 0x0
-// CHECK: 1 .eh_frame 00000018
+// CHECK: 1 .eh_frame 0000001c
diff --git a/test/ELF/invalid-relocations.test b/test/ELF/invalid-relocations.test
index cfeb44b03c67..7c32058c4353 100644
--- a/test/ELF/invalid-relocations.test
+++ b/test/ELF/invalid-relocations.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t
-# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+# RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
!ELF
FileHeader:
diff --git a/test/ELF/invalid-undef-section-symbol.test b/test/ELF/invalid-undef-section-symbol.test
index f634d6ad8c63..cb89306b781e 100644
--- a/test/ELF/invalid-undef-section-symbol.test
+++ b/test/ELF/invalid-undef-section-symbol.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t.o
-# RUN: not ld.lld -r %t.o -o %2.o 2>&1 | FileCheck %s
+# RUN: not ld.lld -r %t.o -o /dev/null 2>&1 | FileCheck %s
# We used to crash at this.
# CHECK: STT_SECTION symbol should be defined
diff --git a/test/ELF/invalid-z.s b/test/ELF/invalid-z.s
deleted file mode 100644
index a5343c93e677..000000000000
--- a/test/ELF/invalid-z.s
+++ /dev/null
@@ -1,9 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: not ld.lld %t.o -o %t -z max-page-size 2>&1 | FileCheck %s
-# CHECK: invalid max-page-size
-# CHECK-NOT: error
-
-.global _start
-_start:
- nop
diff --git a/test/ELF/invalid/Inputs/cie-version2.elf b/test/ELF/invalid/Inputs/cie-version2.elf
deleted file mode 100644
index 87f8a5be76f4..000000000000
--- a/test/ELF/invalid/Inputs/cie-version2.elf
+++ /dev/null
Binary files differ
diff --git a/test/ELF/invalid/Inputs/too-short.elf b/test/ELF/invalid/Inputs/too-short.elf
deleted file mode 100644
index 077f392f1dc4..000000000000
--- a/test/ELF/invalid/Inputs/too-short.elf
+++ /dev/null
Binary files differ
diff --git a/test/ELF/invalid/dynamic-section-size.s b/test/ELF/invalid/dynamic-section-size.s
index 323dabaa9016..58a7d0688c25 100644
--- a/test/ELF/invalid/dynamic-section-size.s
+++ b/test/ELF/invalid/dynamic-section-size.s
@@ -1,4 +1,4 @@
## dynamic-section-sh_size.elf has incorrect sh_size of dynamic section.
-# RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o %t2 2>&1 | \
+# RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o /dev/null 2>&1 | \
# RUN: FileCheck %s
# CHECK: error: {{.*}}: invalid sh_entsize
diff --git a/test/ELF/invalid/eh-frame-hdr-no-out.s b/test/ELF/invalid/eh-frame-hdr-no-out.s
index 8379253d9fd0..221ca205e591 100644
--- a/test/ELF/invalid/eh-frame-hdr-no-out.s
+++ b/test/ELF/invalid/eh-frame-hdr-no-out.s
@@ -1,6 +1,19 @@
// REQUIRES: x86
-// RUN: not ld.lld --eh-frame-hdr %p/Inputs/cie-version2.elf -o %t >& %t.log
-// RUN: FileCheck %s < %t.log
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s
-// cie-version2.elf contains unsupported version of CIE = 2.
-// CHECK: FDE version 1 or 3 expected, but got 2
+// CHECK: error: corrupted .eh_frame: FDE version 1 or 3 expected, but got 2
+
+.section .eh_frame
+ .byte 0x08
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x02
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
diff --git a/test/ELF/invalid/executable.s b/test/ELF/invalid/executable.s
new file mode 100644
index 000000000000..254075146e15
--- /dev/null
+++ b/test/ELF/invalid/executable.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -o %t1.exe %t.o
+# RUN: not ld.lld -o /dev/null %t1.exe 2>&1 | FileCheck %s
+# CHECK: unknown file type
+
+.global _start
+_start:
+ ret
diff --git a/test/ELF/invalid/invalid-e_shnum.s b/test/ELF/invalid/invalid-e_shnum.s
index 0c720ffa1713..34a742e18072 100644
--- a/test/ELF/invalid/invalid-e_shnum.s
+++ b/test/ELF/invalid/invalid-e_shnum.s
@@ -1,3 +1,3 @@
## Spec says that "If a file has no section header table, e_shnum holds the value zero.", though
## in this test case it holds non-zero and lld used to crash.
-# RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o %t2
+# RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o /dev/null
diff --git a/test/ELF/invalid/invalid-elf.test b/test/ELF/invalid/invalid-elf.test
index 8be0437c0680..80c8f41eb61d 100644
--- a/test/ELF/invalid/invalid-elf.test
+++ b/test/ELF/invalid/invalid-elf.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -o %t -filetype=obj -triple x86_64-pc-linux
# RUN: not ld.lld %t %p/Inputs/data-encoding.a -o %t2 2>&1 | \
diff --git a/test/ELF/invalid/merge-invalid-size.s b/test/ELF/invalid/merge-invalid-size.s
index 1dbd7cf95b7d..cc2566d0ee87 100644
--- a/test/ELF/invalid/merge-invalid-size.s
+++ b/test/ELF/invalid/merge-invalid-size.s
@@ -1,10 +1,10 @@
// 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
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
// CHECK: SHF_MERGE section size must be a multiple of sh_entsize
// Test that we accept a zero sh_entsize.
-// RUN: ld.lld %p/Inputs/shentsize-zero.elf -o %t2
+// RUN: ld.lld %p/Inputs/shentsize-zero.elf -o /dev/null
.section .foo,"aM",@progbits,4
.short 42
diff --git a/test/ELF/invalid/mips-invalid-options-descriptor.s b/test/ELF/invalid/mips-invalid-options-descriptor.s
index b23ecee6d0d2..c05e34785299 100644
--- a/test/ELF/invalid/mips-invalid-options-descriptor.s
+++ b/test/ELF/invalid/mips-invalid-options-descriptor.s
@@ -1,5 +1,5 @@
## mips-invalid-options-descriptor.elf has option descriptor in
## .MIPS.options with size of zero.
-# RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o %t2 2>&1 | \
+# RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o /dev/null 2>&1 | \
# RUN: FileCheck %s
# CHECK: error: {{.*}}: invalid section offset
diff --git a/test/ELF/invalid/reloc-section-reordered.test b/test/ELF/invalid/reloc-section-reordered.test
new file mode 100644
index 000000000000..7ff4ed6e8ade
--- /dev/null
+++ b/test/ELF/invalid/reloc-section-reordered.test
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: unsupported relocation reference
+
+## YAML below lists .rela.text before .text, we do not support it.
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_REL
+ Name: .rela.text
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: .text
+ Type: R_X86_64_NONE
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: "FFFFFFFFFFFFFFFF"
diff --git a/test/ELF/invalid/section-alignment2.s b/test/ELF/invalid/section-alignment2.s
index aaef9f8bff5d..879ba8c03c14 100644
--- a/test/ELF/invalid/section-alignment2.s
+++ b/test/ELF/invalid/section-alignment2.s
@@ -1,5 +1,5 @@
## section-alignment-notpow2.elf has section alignment
## 0xFFFFFFFF which is not a power of 2.
-# RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o %t2 2>&1 | \
+# RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o /dev/null 2>&1 | \
# RUN: FileCheck %s
# CHECK: section sh_addralign is not a power of 2
diff --git a/test/ELF/invalid/sht-group.s b/test/ELF/invalid/sht-group.s
index f28035f0dac9..a4b684c83fd3 100644
--- a/test/ELF/invalid/sht-group.s
+++ b/test/ELF/invalid/sht-group.s
@@ -1,3 +1,3 @@
## sht-group.elf contains SHT_GROUP section with invalid sh_info.
-# RUN: not ld.lld %p/Inputs/sht-group.elf -o %t2 2>&1 | FileCheck %s
+# RUN: not ld.lld %p/Inputs/sht-group.elf -o /dev/null 2>&1 | FileCheck %s
# CHECK: invalid symbol index
diff --git a/test/ELF/invalid/symbol-index.s b/test/ELF/invalid/symbol-index.s
index 4ad1d6cb232c..e3989b4e1adc 100644
--- a/test/ELF/invalid/symbol-index.s
+++ b/test/ELF/invalid/symbol-index.s
@@ -5,6 +5,6 @@
## [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
## ...
## [ 4] .symtab RELA 0000000000000000 000048 000030 18 1 2 8
-# RUN: not ld.lld %p/Inputs/symbol-index.elf -o %t2 2>&1 | \
+# RUN: not ld.lld %p/Inputs/symbol-index.elf -o /dev/null 2>&1 | \
# RUN: FileCheck --check-prefix=INVALID-SYMBOL-INDEX %s
# INVALID-SYMBOL-INDEX: invalid symbol index
diff --git a/test/ELF/invalid/symbol-name.s b/test/ELF/invalid/symbol-name.s
index 8daee1a3fa78..53a20ef6af9c 100644
--- a/test/ELF/invalid/symbol-name.s
+++ b/test/ELF/invalid/symbol-name.s
@@ -3,5 +3,5 @@
## symbol-name-offset.elf contains symbol with invalid (too large)
## st_name value.
# RUN: not ld.lld %S/Inputs/symbol-name-offset.elf \
-# RUN: -o %t 2>&1 | FileCheck %s
+# RUN: -o /dev/null 2>&1 | FileCheck %s
# CHECK: invalid symbol name offset
diff --git a/test/ELF/invalid/tls-symbol.s b/test/ELF/invalid/tls-symbol.s
index 354ca573d5c0..99c47dc13023 100644
--- a/test/ELF/invalid/tls-symbol.s
+++ b/test/ELF/invalid/tls-symbol.s
@@ -1,5 +1,5 @@
# REQUIRES: x86
## The test file contains an STT_TLS symbol but has no TLS section.
-# RUN: not ld.lld %S/Inputs/tls-symbol.elf -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %S/Inputs/tls-symbol.elf -o /dev/null 2>&1 | FileCheck %s
# CHECK: has an STT_TLS symbol but doesn't have an SHF_TLS section
diff --git a/test/ELF/invalid/too-short.s b/test/ELF/invalid/too-short.s
deleted file mode 100644
index deaf8218d6e0..000000000000
--- a/test/ELF/invalid/too-short.s
+++ /dev/null
@@ -1,5 +0,0 @@
-# REQUIRES: x86
-
-## too-short.elf file is a truncated ELF.
-# RUN: not ld.lld %S/Inputs/too-short.elf -o %t 2>&1 | FileCheck %s
-# CHECK: file is too short
diff --git a/test/ELF/just-symbols-cref.s b/test/ELF/just-symbols-cref.s
new file mode 100644
index 000000000000..8581c53eb5df
--- /dev/null
+++ b/test/ELF/just-symbols-cref.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1.exe -Ttext=0x10000
+
+# RUN: ld.lld -just-symbols=%t1.exe -o %t2.exe -cref | FileCheck %s
+
+# CHECK: Symbol File
+# CHECK-NEXT: bar {{.*exe}}
+# CHECK-NEXT: foo {{.*exe}}
+
+.globl foo, bar
+foo:
+ ret
+
+.section .data
+.type bar, @object
+.size bar, 40
+bar:
+ .zero 40
diff --git a/test/ELF/just-symbols.s b/test/ELF/just-symbols.s
new file mode 100644
index 000000000000..856cf8c581ec
--- /dev/null
+++ b/test/ELF/just-symbols.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1.exe -Ttext=0x10000
+
+# RUN: ld.lld -just-symbols=%t1.exe -o %t2.exe
+# RUN: llvm-readelf -symbols %t2.exe | FileCheck %s
+
+# CHECK: 0000000000011000 40 OBJECT GLOBAL DEFAULT ABS bar
+# CHECK: 0000000000010000 0 NOTYPE GLOBAL DEFAULT ABS foo
+
+.globl foo, bar
+foo:
+ ret
+
+.section .data
+.type bar, @object
+.size bar, 40
+bar:
+ .zero 40
diff --git a/test/ELF/libsearch.s b/test/ELF/libsearch.s
index d21baf9dd95f..246a5d13951e 100644
--- a/test/ELF/libsearch.s
+++ b/test/ELF/libsearch.s
@@ -1,3 +1,4 @@
+// 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/libsearch-dyn.s -o %tdyn.o
@@ -10,7 +11,6 @@
// 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 \
diff --git a/test/ELF/linkerscript/Inputs/addr.s b/test/ELF/linkerscript/Inputs/addr.s
new file mode 100644
index 000000000000..65d99dcf99cd
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/addr.s
@@ -0,0 +1,12 @@
+.text
+.globl _start
+_start:
+
+.section .foo.1,"a"
+.quad 1
+
+.section .foo.2,"a"
+.quad 2
+
+.section .foo.3,"a"
+.quad 3
diff --git a/test/ELF/linkerscript/Inputs/align.s b/test/ELF/linkerscript/Inputs/align.s
new file mode 100644
index 000000000000..c804536aa543
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/align.s
@@ -0,0 +1,13 @@
+.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/Inputs/alignof.s b/test/ELF/linkerscript/Inputs/alignof.s
new file mode 100644
index 000000000000..b288f94a12c9
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/alignof.s
@@ -0,0 +1,15 @@
+.global _start
+_start:
+ nop
+
+.section .aaa,"a"
+ .align 8
+ .quad 0
+
+.section .bbb,"a"
+ .align 16
+ .quad 0
+
+.section .ccc,"a"
+ .align 32
+ .quad 0
diff --git a/test/ELF/linkerscript/Inputs/at2.s b/test/ELF/linkerscript/Inputs/at2.s
new file mode 100644
index 000000000000..8c6548b53f69
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/at2.s
@@ -0,0 +1,14 @@
+.section .foo1, "ax"
+.quad 0
+
+.section .foo2, "ax"
+.quad 0
+
+.section .bar1, "aw"
+.quad 0
+
+.section .bar2, "aw"
+.quad 0
+
+.section .bar3, "aw"
+.quad 0
diff --git a/test/ELF/linkerscript/Inputs/at3.s b/test/ELF/linkerscript/Inputs/at3.s
new file mode 100644
index 000000000000..8005c75723dd
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/at3.s
@@ -0,0 +1,8 @@
+.section .foo1, "a"
+.quad 0
+
+.section .foo2, "ax"
+.quad 0
+
+.section .foo3, "ax"
+.quad 0
diff --git a/test/ELF/linkerscript/Inputs/data-commands.s b/test/ELF/linkerscript/Inputs/data-commands.s
new file mode 100644
index 000000000000..d5d78cfd9beb
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/data-commands.s
@@ -0,0 +1,35 @@
+.global a
+a = 0x11
+
+.global b
+b = 0x1122
+
+.global c
+c = 0x11223344
+
+.global d
+d = 0x1122334455667788
+
+.section .foo.1, "a"
+ .byte 0xFF
+
+.section .foo.2, "a"
+ .byte 0xFF
+
+.section .foo.3, "a"
+ .byte 0xFF
+
+.section .foo.4, "a"
+ .byte 0xFF
+
+.section .bar.1, "a"
+ .byte 0xFF
+
+.section .bar.2, "a"
+ .byte 0xFF
+
+.section .bar.3, "a"
+ .byte 0xFF
+
+.section .bar.4, "a"
+ .byte 0xFF
diff --git a/test/ELF/linkerscript/Inputs/data-segment-relro.s b/test/ELF/linkerscript/Inputs/data-segment-relro.s
new file mode 100644
index 000000000000..668a2e2ca2a4
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/data-segment-relro.s
@@ -0,0 +1,11 @@
+.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/linkerscript/Inputs/define.s b/test/ELF/linkerscript/Inputs/define.s
new file mode 100644
index 000000000000..bc60a233dcb4
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/define.s
@@ -0,0 +1,8 @@
+.global defined
+defined = 0
+
+.section .foo,"a"
+.quad 1
+
+.section .bar,"a"
+.quad 1
diff --git a/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s b/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s
new file mode 100644
index 000000000000..19e50488050e
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s
@@ -0,0 +1,11 @@
+.text
+.globl _start
+_start:
+ .cfi_startproc
+ .cfi_lsda 0, _ex
+ nop
+ .cfi_endproc
+
+.data
+_ex:
+ .word 0
diff --git a/test/ELF/linkerscript/Inputs/extend-pt-load.s b/test/ELF/linkerscript/Inputs/extend-pt-load.s
new file mode 100644
index 000000000000..8993fb163346
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/extend-pt-load.s
@@ -0,0 +1,3 @@
+nop
+.section .data.rel.ro, "aw"
+.byte 0
diff --git a/test/ELF/linkerscript/Inputs/fill.s b/test/ELF/linkerscript/Inputs/fill.s
new file mode 100644
index 000000000000..b8eed890601b
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/fill.s
@@ -0,0 +1,11 @@
+.text
+.globl _start
+_start:
+
+.section .aaa, "a"
+.align 1
+.byte 0xAA
+
+.section .bbb, "a"
+.align 1
+.byte 0xBB
diff --git a/test/ELF/linkerscript/Inputs/implicit-program-header.script b/test/ELF/linkerscript/Inputs/implicit-program-header.script
deleted file mode 100644
index 27dbea84c4e4..000000000000
--- a/test/ELF/linkerscript/Inputs/implicit-program-header.script
+++ /dev/null
@@ -1,12 +0,0 @@
-PHDRS
-{
- ph_write PT_LOAD FLAGS(2);
- ph_exec PT_LOAD FLAGS(1);
-}
-
-SECTIONS
-{
- .bar : { *(.bar) } : ph_exec
- .foo : { *(.foo) }
- .text : { *(.text) } : ph_write
-}
diff --git a/test/ELF/linkerscript/Inputs/insert-after.s b/test/ELF/linkerscript/Inputs/insert-after.s
new file mode 100644
index 000000000000..88a6044cc968
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/insert-after.s
@@ -0,0 +1,11 @@
+.section .foo.text,"ax"
+.quad 0
+
+.section .foo.data,"aw"
+.quad 0
+
+.section .text.1,"ax"
+.quad 0
+
+.section .data.1,"aw"
+.quad 0
diff --git a/test/ELF/linkerscript/Inputs/insert-after.script b/test/ELF/linkerscript/Inputs/insert-after.script
new file mode 100644
index 000000000000..cb95878bc5cf
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/insert-after.script
@@ -0,0 +1,4 @@
+SECTIONS {
+ .text : { *(.text.*) }
+ .data : { *(.data.*) }
+}
diff --git a/test/ELF/linkerscript/Inputs/map-file2.s b/test/ELF/linkerscript/Inputs/map-file2.s
new file mode 100644
index 000000000000..daf994eca172
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/map-file2.s
@@ -0,0 +1,19 @@
+.global _start
+_start:
+.global _Z1fi
+_Z1fi:
+.cfi_startproc
+nop
+.cfi_endproc
+
+.section .aaa, "a";
+.quad 1;
+
+.section .bbb, "a";
+.quad 2;
+
+.section .ccc, "a";
+.quad 3;
+
+.section .ddd, "a";
+.quad 4
diff --git a/test/ELF/linkerscript/Inputs/provide-shared2.s b/test/ELF/linkerscript/Inputs/provide-shared2.s
new file mode 100644
index 000000000000..f02fd650106a
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/provide-shared2.s
@@ -0,0 +1,3 @@
+.global foo
+.data
+.dc.a foo
diff --git a/test/ELF/linkerscript/Inputs/sections-va-overflow.s b/test/ELF/linkerscript/Inputs/sections-va-overflow.s
new file mode 100644
index 000000000000..6bb049031c7d
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/sections-va-overflow.s
@@ -0,0 +1,6 @@
+.global _start
+_start:
+ retq
+
+.bss
+.space 0x2000
diff --git a/test/ELF/linkerscript/Inputs/synthetic-symbols.s b/test/ELF/linkerscript/Inputs/synthetic-symbols.s
new file mode 100644
index 000000000000..670e65cb80f4
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/synthetic-symbols.s
@@ -0,0 +1,16 @@
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 0
+
+.section .bar,"a"
+ .long 0
+
+.section .dah,"ax",@progbits
+ .cfi_startproc
+ nop
+ .cfi_endproc
+
+.global _begin_sec, _end_sec, _end_sec_abs
diff --git a/test/ELF/linkerscript/absolute-expr.s b/test/ELF/linkerscript/absolute-expr.test
index a9a674b859f4..9e8f517d0ac4 100644
--- a/test/ELF/linkerscript/absolute-expr.s
+++ b/test/ELF/linkerscript/absolute-expr.test
@@ -1,21 +1,19 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { \
-# RUN: .text : { \
-# RUN: bar1 = ALIGNOF(.text); \
-# RUN: bar2 = CONSTANT (MAXPAGESIZE); \
-# RUN: bar3 = SIZEOF (.text); \
-# RUN: bar4 = SIZEOF_HEADERS; \
-# RUN: bar5 = 0x42; \
-# RUN: bar6 = foo + 1; \
-# RUN: *(.text) \
-# RUN: } \
-# RUN: };" > %t.script
-# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: echo ".global foo; foo = 0x123" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o -shared
# RUN: llvm-readobj -t %t.so | FileCheck %s
-.global foo
-foo = 0x123
+SECTIONS {
+ .text : {
+ bar1 = ALIGNOF(.text);
+ bar2 = CONSTANT (MAXPAGESIZE);
+ bar3 = SIZEOF (.text);
+ bar4 = SIZEOF_HEADERS;
+ bar5 = 0x42;
+ bar6 = foo + 1;
+ *(.text)
+ }
+}
# CHECK: Symbol {
# CHECK: Name: foo
diff --git a/test/ELF/linkerscript/addr-zero.s b/test/ELF/linkerscript/addr-zero.test
index 71251d3acfff..6253f619381b 100644
--- a/test/ELF/linkerscript/addr-zero.s
+++ b/test/ELF/linkerscript/addr-zero.test
@@ -1,7 +1,6 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { foo = ADDR(.text) - ABSOLUTE(ADDR(.text)); };" > %t.script
-# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o -shared
# RUN: llvm-readobj --symbols %t.so | FileCheck %s
# Test that the script creates a non absolute symbol with value
@@ -9,10 +8,14 @@
# CHECK: Symbol {
# CHECK: Name: foo
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x70
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
+
+SECTIONS {
+ foo = ADDR(.text) - ABSOLUTE(ADDR(.text));
+};
diff --git a/test/ELF/linkerscript/addr.s b/test/ELF/linkerscript/addr.s
deleted file mode 100644
index 2d3a7ab35767..000000000000
--- a/test/ELF/linkerscript/addr.s
+++ /dev/null
@@ -1,32 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { \
-# RUN: . = 0x1000; \
-# RUN: .text : { *(.text*) } \
-# RUN: .foo.1 : { *(.foo.1) } \
-# RUN: .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } \
-# RUN: .foo.3 : { *(.foo.3) } \
-# RUN: }" > %t.script
-# RUN: ld.lld %t --script %t.script -o %t1
-# 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 .text 00000000 0000000000001000 TEXT DATA
-# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA
-# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA
-# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA
-
-.text
-.globl _start
-_start:
-
-.section .foo.1,"a"
- .quad 1
-
-.section .foo.2,"a"
- .quad 2
-
-.section .foo.3,"a"
- .quad 3
diff --git a/test/ELF/linkerscript/addr.test b/test/ELF/linkerscript/addr.test
new file mode 100644
index 000000000000..db0568e56c76
--- /dev/null
+++ b/test/ELF/linkerscript/addr.test
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/addr.s -o %t
+# RUN: ld.lld %t --script %s -o %t1
+# 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 .text 00000000 0000000000001000 TEXT
+# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA
+# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA
+# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA
+
+SECTIONS {
+ . = 0x1000;
+ .text : { *(.text*) }
+ .foo.1 : { *(.foo.1) }
+ .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) }
+ .foo.3 : { *(.foo.3) }
+}
diff --git a/test/ELF/linkerscript/address-expr-symbols.s b/test/ELF/linkerscript/address-expr-symbols.s
new file mode 100644
index 000000000000..0b76c91a5c8b
--- /dev/null
+++ b/test/ELF/linkerscript/address-expr-symbols.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { .bar (foo) : { } };" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s
+# CHECK: symbol not found: foo
+
+# RUN: echo "SECTIONS { .bar : AT(foo) { } };" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s
+
+# RUN: echo "SECTIONS { .bar : ALIGN(foo) { } };" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s
+
+# RUN: echo "SECTIONS { .bar : SUBALIGN(foo) { } };" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s
diff --git a/test/ELF/linkerscript/align-empty.s b/test/ELF/linkerscript/align-empty.s
deleted file mode 100644
index 3ff71578410a..000000000000
--- a/test/ELF/linkerscript/align-empty.s
+++ /dev/null
@@ -1,18 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: abc : { } \
-# RUN: . = ALIGN(0x1000); \
-# RUN: foo : { *(foo) } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t -shared
-# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
-# CHECK: Sections:
-# CHECK-NEXT: Idx Name Size Address
-# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 foo 00000001 0000000000001000
-
- .section foo, "a"
- .byte 0
diff --git a/test/ELF/linkerscript/align-empty.test b/test/ELF/linkerscript/align-empty.test
new file mode 100644
index 000000000000..63fe32882c0b
--- /dev/null
+++ b/test/ELF/linkerscript/align-empty.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: echo '.section foo, "a"; .byte 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+
+# RUN: ld.lld -o %t1 --script %s %t.o -shared
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ abc : {}
+ . = ALIGN(0x1000);
+ foo : { *(foo) }
+}
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .dynsym 00000018 0000000000000190
+# CHECK-NEXT: 2 .gnu.hash 0000001c 00000000000001a8
+# CHECK-NEXT: 3 .hash 00000010 00000000000001c4
+# CHECK-NEXT: 4 .dynstr 00000001 00000000000001d4
+# CHECK-NEXT: 5 foo 00000001 0000000000001000
diff --git a/test/ELF/linkerscript/align-r.test b/test/ELF/linkerscript/align-r.test
new file mode 100644
index 000000000000..684ac1e92328
--- /dev/null
+++ b/test/ELF/linkerscript/align-r.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+## Check output section ALIGN modifier with -r
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t1.o
+# RUN: ld.lld -r -o %t2.o --script %s %t1.o
+# RUN: llvm-readelf -s %t2.o | FileCheck %s
+
+# CHECK: Section Headers:
+# CHECK-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
+# CHECK-NEXT: NULL 0000000000000000 000000 000000 00
+# CHECK-NEXT: .aaa PROGBITS 0000000000000000 000040 000008 00 A 0 0 1
+# CHECK-NEXT: .bbb PROGBITS 0000000000000000 001000 000008 00 A 0 0 4096
+# CHECK-NEXT: .ccc PROGBITS 0000000000000000 004000 000008 00 A 0 0 16384
+
+SECTIONS {
+ . = 0x10000;
+ .aaa : { *(.aaa) }
+ .bbb : ALIGN(4096) { *(.bbb) }
+ .ccc : ALIGN(4096 * 4) { *(.ccc) }
+}
diff --git a/test/ELF/linkerscript/align-section-offset.s b/test/ELF/linkerscript/align-section-offset.s
deleted file mode 100644
index 9c1603a19853..000000000000
--- a/test/ELF/linkerscript/align-section-offset.s
+++ /dev/null
@@ -1,11 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { .foo : ALIGN(2M) { *(.foo) } }" > %t.script
-# RUN: ld.lld -o %t --script %t.script %t.o -shared
-# RUN: llvm-readelf -S -l %t | FileCheck %s
-
-# CHECK: .foo PROGBITS 0000000000200000 200000 000008 00 WA 0 0 2097152
-# CHECK: LOAD 0x200000 0x0000000000200000 0x0000000000200000 {{.*}} RW 0x200000
-
- .section .foo, "aw"
- .quad 42
diff --git a/test/ELF/linkerscript/align-section-offset.test b/test/ELF/linkerscript/align-section-offset.test
new file mode 100644
index 000000000000..66508c472e94
--- /dev/null
+++ b/test/ELF/linkerscript/align-section-offset.test
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: echo '.section .foo, "aw"; .quad 42' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o -shared
+# RUN: llvm-readelf -S -l %t | FileCheck %s
+
+SECTIONS {
+ .foo : ALIGN(2M) { *(.foo) }
+}
+
+# CHECK: .foo PROGBITS 0000000000200000 200000 000008 00 WA 0 0 2097152
+# CHECK: LOAD 0x200000 0x0000000000200000 0x0000000000200000 {{.*}} RW 0x200000
diff --git a/test/ELF/linkerscript/align-section.s b/test/ELF/linkerscript/align-section.s
deleted file mode 100644
index d26f15c87329..000000000000
--- a/test/ELF/linkerscript/align-section.s
+++ /dev/null
@@ -1,6 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { .foo : ALIGN(2M) { } }" > %t.script
-# RUN: ld.lld -o %t --script %t.script %t.o -shared
-
-# We would crash if an empty section had an ALIGN.
diff --git a/test/ELF/linkerscript/align-section.test b/test/ELF/linkerscript/align-section.test
new file mode 100644
index 000000000000..7a28fef2076e
--- /dev/null
+++ b/test/ELF/linkerscript/align-section.test
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o -shared
+
+# lld shouldn't crash.
+
+SECTIONS { .foo : ALIGN(2M) {} }
diff --git a/test/ELF/linkerscript/align.s b/test/ELF/linkerscript/align.s
deleted file mode 100644
index 99e7382daa59..000000000000
--- a/test/ELF/linkerscript/align.s
+++ /dev/null
@@ -1,125 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-## Check that ALIGN command workable using location counter
-# RUN: echo "SECTIONS { \
-# RUN: . = 0x10000; \
-# RUN: .aaa : { *(.aaa) } \
-# RUN: . = ALIGN(4096); \
-# RUN: .bbb : { *(.bbb) } \
-# RUN: . = ALIGN(4096 * 4); \
-# RUN: .ccc : { *(.ccc) } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
-
-## Check that the two argument version of ALIGN command works
-# RUN: echo "SECTIONS { \
-# RUN: . = ALIGN(0x1234, 0x10000); \
-# RUN: .aaa : { *(.aaa) } \
-# RUN: . = ALIGN(., 4096); \
-# RUN: .bbb : { *(.bbb) } \
-# RUN: . = ALIGN(., 4096 * 4); \
-# RUN: .ccc : { *(.ccc) } \
-# 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
-
-## Check output sections ALIGN modificator
-# RUN: echo "SECTIONS { \
-# RUN: . = 0x10000; \
-# RUN: .aaa : { *(.aaa) } \
-# RUN: .bbb : ALIGN(4096) { *(.bbb) } \
-# RUN: .ccc : ALIGN(4096 * 4) { *(.ccc) } \
-# RUN: }" > %t2.script
-# RUN: ld.lld -o %t2 --script %t2.script %t
-# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
-
-## Check use of variables in align expressions:
-# RUN: echo "VAR = 0x1000; \
-# RUN: __code_base__ = 0x10000; \
-# RUN: SECTIONS { \
-# RUN: . = __code_base__; \
-# RUN: .aaa : { *(.aaa) } \
-# RUN: .bbb : ALIGN(VAR) { *(.bbb) } \
-# RUN: . = ALIGN(., VAR * 4); \
-# RUN: .ccc : { *(.ccc) } \
-# RUN: __start_bbb = ADDR(.bbb); \
-# RUN: __end_bbb = ALIGN(__start_bbb + SIZEOF(.bbb), VAR); \
-# RUN: }" > %t3.script
-# RUN: ld.lld -o %t3 --script %t3.script %t
-# RUN: llvm-objdump -section-headers %t3 | FileCheck %s
-# RUN: llvm-objdump -t %t3 | FileCheck -check-prefix SYMBOLS %s
-
-# SYMBOLS-LABEL: SYMBOL TABLE:
-# SYMBOLS-NEXT: 0000000000000000 *UND* 00000000
-# SYMBOLS-NEXT: 0000000000014008 .text 00000000 _start
-# SYMBOLS-NEXT: 0000000000010000 *ABS* 00000000 __code_base__
-# SYMBOLS-NEXT: 0000000000001000 *ABS* 00000000 VAR
-# SYMBOLS-NEXT: 0000000000011000 .bbb 00000000 __start_bbb
-# SYMBOLS-NEXT: 0000000000012000 .bbb 00000000 __end_bbb
-
-## Check that ALIGN zero do nothing and does not crash #1.
-# RUN: echo "SECTIONS { . = ALIGN(0x123, 0); .aaa : { *(.aaa) } }" > %t.script
-# RUN: ld.lld -o %t4 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t4 | FileCheck %s -check-prefix=ZERO
-
-# ZERO: Sections:
-# ZERO-NEXT: Idx Name Size Address Type
-# ZERO-NEXT: 0 00000000 0000000000000000
-# ZERO-NEXT: 1 .aaa 00000008 0000000000000123 DATA
-
-## Check that ALIGN zero do nothing and does not crash #2.
-# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0); .aaa : { *(.aaa) } }" > %t.script
-# RUN: ld.lld -o %t5 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t5 | FileCheck %s -check-prefix=ZERO
-
-## Test we fail gracefuly when alignment value is not a power of 2 (#1).
-# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0x123, 3); .aaa : { *(.aaa) } }" > %t.script
-# RUN: not ld.lld -o %t6 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s
-# ERR: {{.*}}.script:1: alignment must be power of 2
-
-## Test we fail gracefuly when alignment value is not a power of 2 (#2).
-# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(3); .aaa : { *(.aaa) } }" > %t.script
-# RUN: not ld.lld -o %t7 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s
-
-# RUN: echo "SECTIONS { \
-# RUN: . = 0xff8; \
-# RUN: .aaa : { \
-# RUN: *(.aaa) \
-# RUN: foo = ALIGN(., 0x100); \
-# RUN: bar = .; \
-# RUN: zed1 = ALIGN(., 0x100) + 1; \
-# RUN: zed2 = ALIGN(., 0x100) - 1; \
-# RUN: } \
-# RUN: .bbb : { *(.bbb); } \
-# RUN: .ccc : { *(.ccc); } \
-# RUN: .text : { *(.text); } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=OFFSET %s
-
-# OFFSET: 0000000000001000 .aaa 00000000 foo
-# OFFSET: 0000000000001000 .aaa 00000000 bar
-# OFFSET: 0000000000001001 .aaa 00000000 zed1
-# OFFSET: 0000000000000fff .aaa 00000000 zed2
-
-.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/align1.test b/test/ELF/linkerscript/align1.test
new file mode 100644
index 000000000000..5804bf933740
--- /dev/null
+++ b/test/ELF/linkerscript/align1.test
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+SECTIONS {
+ . = 0x10000;
+ .aaa : { *(.aaa) }
+ . = ALIGN(4096);
+ .bbb : { *(.bbb) }
+ . = ALIGN(4096 * 4);
+ .ccc : { *(.ccc) }
+}
+
+# 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
+
+## Check that ALIGN zero do nothing and does not crash #1.
+# RUN: echo "SECTIONS { . = ALIGN(0x123, 0); .aaa : { *(.aaa) } }" > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t4 | FileCheck %s -check-prefix=ZERO
+
+# ZERO: Sections:
+# ZERO-NEXT: Idx Name Size Address Type
+# ZERO-NEXT: 0 00000000 0000000000000000
+# ZERO-NEXT: 1 .aaa 00000008 0000000000000123 DATA
+
+## Check that ALIGN zero do nothing and does not crash #2.
+# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0); .aaa : { *(.aaa) } }" > %t.script
+# RUN: ld.lld -o %t5 --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t5 | FileCheck %s -check-prefix=ZERO
+
+## Test we fail gracefuly when alignment value is not a power of 2 (#1).
+# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0x123, 3); .aaa : { *(.aaa) } }" > %t.script
+# RUN: not ld.lld -o %t6 --script %t.script %t.o 2>&1 | FileCheck -check-prefix=ERR %s
+
+# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(3); .aaa : { *(.aaa) } }" > %t.script
+# RUN: not ld.lld -o %t7 --script %t.script %t.o 2>&1 | FileCheck -check-prefix=ERR %s
+
+# ERR: {{.*}}.script:1: alignment must be power of 2
diff --git a/test/ELF/linkerscript/align2.test b/test/ELF/linkerscript/align2.test
new file mode 100644
index 000000000000..a9003a403d75
--- /dev/null
+++ b/test/ELF/linkerscript/align2.test
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+SECTIONS {
+ . = ALIGN(0x1234, 0x10000);
+ .aaa : { *(.aaa) }
+ . = ALIGN(., 4096);
+ .bbb : { *(.bbb) }
+ . = ALIGN(., 4096 * 4);
+ .ccc : { *(.ccc) }
+}
+
+# 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
diff --git a/test/ELF/linkerscript/align3.test b/test/ELF/linkerscript/align3.test
new file mode 100644
index 000000000000..2a091fcbd6bd
--- /dev/null
+++ b/test/ELF/linkerscript/align3.test
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+SECTIONS {
+ . = 0x10000;
+ .aaa : { *(.aaa) }
+ .bbb : ALIGN(4096) { *(.bbb) }
+ .ccc : ALIGN(4096 * 4) { *(.ccc) }
+}
+
+# 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
diff --git a/test/ELF/linkerscript/align4.test b/test/ELF/linkerscript/align4.test
new file mode 100644
index 000000000000..9440d60f6385
--- /dev/null
+++ b/test/ELF/linkerscript/align4.test
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -t %t | FileCheck %s
+
+# CHECK-LABEL: SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: 0000000000014008 .text 00000000 _start
+# CHECK-NEXT: 0000000000010000 *ABS* 00000000 __code_base__
+# CHECK-NEXT: 0000000000001000 *ABS* 00000000 VAR
+# CHECK-NEXT: 0000000000011000 .bbb 00000000 __start_bbb
+# CHECK-NEXT: 0000000000012000 .bbb 00000000 __end_bbb
+
+VAR = 0x1000;
+__code_base__ = 0x10000;
+
+SECTIONS {
+ . = __code_base__;
+ .aaa : { *(.aaa) }
+ .bbb : ALIGN(VAR) { *(.bbb) }
+ . = ALIGN(., VAR * 4);
+ .ccc : { *(.ccc) }
+ __start_bbb = ADDR(.bbb);
+ __end_bbb = ALIGN(__start_bbb + SIZEOF(.bbb), VAR);
+}
diff --git a/test/ELF/linkerscript/align5.test b/test/ELF/linkerscript/align5.test
new file mode 100644
index 000000000000..47b5c8c03490
--- /dev/null
+++ b/test/ELF/linkerscript/align5.test
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -t %t | FileCheck %s
+
+SECTIONS {
+ . = 0xff8;
+ .aaa : {
+ *(.aaa)
+ foo = ALIGN(., 0x100);
+ bar = .;
+ zed1 = ALIGN(., 0x100) + 1;
+ zed2 = ALIGN(., 0x100) - 1;
+ }
+ .bbb : { *(.bbb); }
+ .ccc : { *(.ccc); }
+ .text : { *(.text); }
+}
+
+# CHECK: 0000000000001000 .aaa 00000000 foo
+# CHECK: 0000000000001000 .aaa 00000000 bar
+# CHECK: 0000000000001001 .aaa 00000000 zed1
+# CHECK: 0000000000000fff .aaa 00000000 zed2
diff --git a/test/ELF/linkerscript/alignof.s b/test/ELF/linkerscript/alignof.s
deleted file mode 100644
index 8880634df243..000000000000
--- a/test/ELF/linkerscript/alignof.s
+++ /dev/null
@@ -1,41 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS { \
-# RUN: .aaa : { *(.aaa) } \
-# RUN: .bbb : { *(.bbb) } \
-# RUN: .ccc : { *(.ccc) } \
-# RUN: _aaa = ALIGNOF(.aaa); \
-# RUN: _bbb = ALIGNOF(.bbb); \
-# RUN: _ccc = ALIGNOF(.ccc); \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck %s
-# CHECK: SYMBOL TABLE:
-# CHECK: 0000000000000008 *ABS* 00000000 _aaa
-# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb
-# CHECK-NEXT: 0000000000000020 *ABS* 00000000 _ccc
-
-## Check that we error out if trying to get alignment of
-## section that does not exist.
-# RUN: echo "SECTIONS { \
-# RUN: _aaa = ALIGNOF(.foo); \
-# RUN: }" > %t.script
-# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \
-# RUN: | FileCheck -check-prefix=ERR %s
-# ERR: {{.*}}.script:1: undefined section .foo
-.global _start
-_start:
- nop
-
-.section .aaa,"a"
- .align 8
- .quad 0
-
-.section .bbb,"a"
- .align 16
- .quad 0
-
-.section .ccc,"a"
- .align 32
- .quad 0
diff --git a/test/ELF/linkerscript/alignof.test b/test/ELF/linkerscript/alignof.test
new file mode 100644
index 000000000000..0e3abf6133c9
--- /dev/null
+++ b/test/ELF/linkerscript/alignof.test
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/alignof.s -o %t
+# RUN: ld.lld -o %t1 --script %s %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: SYMBOL TABLE:
+# CHECK: 0000000000000008 *ABS* 00000000 _aaa
+# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb
+# CHECK-NEXT: 0000000000000020 *ABS* 00000000 _ccc
+
+SECTIONS {
+ .aaa : { *(.aaa) }
+ .bbb : { *(.bbb) }
+ .ccc : { *(.ccc) }
+ _aaa = ALIGNOF(.aaa);
+ _bbb = ALIGNOF(.bbb);
+ _ccc = ALIGNOF(.ccc);
+}
+
+## Check that we error out if trying to get alignment of
+## section that does not exist.
+# RUN: echo "SECTIONS { _aaa = ALIGNOF(.foo); }" > %t.script
+# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: undefined section .foo
diff --git a/test/ELF/linkerscript/arm-exidx-order.s b/test/ELF/linkerscript/arm-exidx-order.s
deleted file mode 100644
index 1ff1711e60be..000000000000
--- a/test/ELF/linkerscript/arm-exidx-order.s
+++ /dev/null
@@ -1,19 +0,0 @@
-# REQUIRES: arm
-# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
-# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \
-# RUN: .ARM.exidx : { *(.ARM.exidx*) } \
-# RUN: .foo : { _foo = 0; } }" > %t.script
-# RUN: ld.lld -T %t.script %t.o -shared -o %t.so
-# RUN: llvm-readobj -s %t.so | FileCheck %s
-
-# CHECK: Section {
-# CHECK: Index:
-# CHECK: Name: .foo
-# CHECK-NEXT: Type: SHT_NOBITS
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: SHF_ALLOC
-# CHECK-NEXT: ]
-
-.fnstart
-.cantunwind
-.fnend
diff --git a/test/ELF/linkerscript/arm-exidx-order.test b/test/ELF/linkerscript/arm-exidx-order.test
new file mode 100644
index 000000000000..60abddfd77da
--- /dev/null
+++ b/test/ELF/linkerscript/arm-exidx-order.test
@@ -0,0 +1,19 @@
+# REQUIRES: arm
+# RUN: echo ".fnstart; .cantunwind; .fnend" \
+# RUN: | llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi - -o %t.o
+# RUN: ld.lld -T %s %t.o -shared -o %t.so
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .ARM.exidx : { *(.ARM.exidx*) }
+ .foo : { _foo = 0; }
+}
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_NOBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.s b/test/ELF/linkerscript/arm-exidx-phdrs.s
deleted file mode 100644
index 971702f55d7b..000000000000
--- a/test/ELF/linkerscript/arm-exidx-phdrs.s
+++ /dev/null
@@ -1,16 +0,0 @@
-// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
-// RUN: echo "PHDRS { ph_text PT_LOAD; } \
-// RUN: SECTIONS { \
-// RUN: . = SIZEOF_HEADERS; \
-// RUN: .text : { *(.text) } : ph_text \
-// RUN: }" > %t.script
-// RUN: ld.lld -T %t.script %t.o -shared -o %t.so
-// RUN: llvm-readobj --program-headers %t.so | FileCheck %s
-
-// CHECK: Type: PT_ARM_EXIDX
-
-.fnstart
-bx lr
-.cantunwind
-.fnend
diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.test b/test/ELF/linkerscript/arm-exidx-phdrs.test
new file mode 100644
index 000000000000..208d4d72ad43
--- /dev/null
+++ b/test/ELF/linkerscript/arm-exidx-phdrs.test
@@ -0,0 +1,13 @@
+# REQUIRES: arm
+# RUN: echo ".fnstart; bx lr; .cantunwind; .fnend" \
+# RUN: | llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi - -o %t.o
+# RUN: ld.lld -T %s %t.o -shared -o %t.so
+# RUN: llvm-readobj --program-headers %t.so | FileCheck %s
+
+# CHECK: Type: PT_ARM_EXIDX
+
+PHDRS { ph_text PT_LOAD; }
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .text : { *(.text) } : ph_text
+}
diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s
deleted file mode 100644
index c377764e9776..000000000000
--- a/test/ELF/linkerscript/arm-lscript.s
+++ /dev/null
@@ -1,9 +0,0 @@
-// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
-// RUN: echo "SECTIONS { \
-// RUN: .rel.dyn : { } \
-// RUN: .zed : { PROVIDE_HIDDEN (foobar = .); } \
-// RUN: }" > %t.script
-// This is a test case for PR33029. Making sure that linker can digest
-// the above script without dumping core.
-// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so
diff --git a/test/ELF/linkerscript/arm-lscript.test b/test/ELF/linkerscript/arm-lscript.test
new file mode 100644
index 000000000000..af2e6316ea43
--- /dev/null
+++ b/test/ELF/linkerscript/arm-lscript.test
@@ -0,0 +1,11 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi /dev/null -o %t.o
+
+# This is a test case for PR33029. Making sure that linker can digest
+# the above script without dumping core.
+# RUN: ld.lld -emit-relocs -T %s %t.o -shared -o %t.so
+
+SECTIONS {
+ .rel.dyn : {}
+ .zed : { PROVIDE_HIDDEN (foobar = .); }
+}
diff --git a/test/ELF/linkerscript/assert.s b/test/ELF/linkerscript/assert.s
index 73cc940669b9..f7113e5b25f0 100644
--- a/test/ELF/linkerscript/assert.s
+++ b/test/ELF/linkerscript/assert.s
@@ -6,7 +6,7 @@
# RUN: llvm-readobj %t1 > /dev/null
# RUN: echo "SECTIONS { ASSERT(0, fail) }" > %t3.script
-# RUN: not ld.lld -shared -o %t3 --script %t3.script %t1.o > %t.log 2>&1
+# RUN: not ld.lld -shared -o /dev/null --script %t3.script %t1.o > %t.log 2>&1
# RUN: FileCheck %s -check-prefix=FAIL < %t.log
# FAIL: fail
@@ -30,10 +30,11 @@
# RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o
# RUN: llvm-readobj %t6 > /dev/null
+## Unlike the GNU ld, we accept the ASSERT without the semicolon.
+## It is consistent with how ASSERT can be written outside of the
+## output section declaration.
# RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script
-# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1
-# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log
-# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got }
+# RUN: ld.lld -shared -o /dev/null --script %t7.script %t1.o
.section .foo, "a"
.quad 0
diff --git a/test/ELF/linkerscript/at-self-reference.s b/test/ELF/linkerscript/at-self-reference.s
new file mode 100644
index 000000000000..7208a4b9fcd4
--- /dev/null
+++ b/test/ELF/linkerscript/at-self-reference.s
@@ -0,0 +1,63 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1000; \
+# RUN: .aaa : AT(ADDR(.aaa)) { *(.aaa) } \
+# RUN: .bbb : AT(ADDR(.bbb)) { *(.bbb) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x1000
+# CHECK-NEXT: PhysicalAddress: 0x1000
+# CHECK-NEXT: FileSize: 3
+# CHECK-NEXT: MemSize: 3
+# 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: 0x1008
+# CHECK-NEXT: VirtualAddress: 0x1008
+# CHECK-NEXT: PhysicalAddress: 0x1008
+# CHECK-NEXT: FileSize: 9
+# CHECK-NEXT: MemSize: 9
+# 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: }
+# CHECK-NEXT:]
+
+.global _start
+_start:
+ nop
+
+
+.section .aaa, "a"
+.asciz "aa"
+
+.section .bbb, "a"
+.align 8
+.quad 0
diff --git a/test/ELF/linkerscript/at2.test b/test/ELF/linkerscript/at2.test
new file mode 100644
index 000000000000..82c9ae1d2252
--- /dev/null
+++ b/test/ELF/linkerscript/at2.test
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/at2.s -o %t.o
+# RUN: ld.lld -o %t.exe %t.o --script %s
+# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
+# RUN: llvm-objdump -section-headers %t.exe | FileCheck %s --check-prefix=SECTIONS
+
+MEMORY {
+ AX (ax) : ORIGIN = 0x2000, LENGTH = 0x100
+ AW (aw) : ORIGIN = 0x3000, LENGTH = 0x100
+ FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x100
+ RAM (aw) : ORIGIN = 0x7000, LENGTH = 0x100
+}
+
+SECTIONS {
+ .foo1 : { *(.foo1) } > AX AT>FLASH
+ .foo2 : { *(.foo2) } > AX
+ .bar1 : { *(.bar1) } > AW AT> RAM
+ .bar2 : { *(.bar2) } > AW AT > RAM
+ .bar3 : { *(.bar3) } > AW AT >RAM
+}
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x2000
+# CHECK-NEXT: PhysicalAddress: 0x6000
+# CHECK-NEXT: FileSize: 16
+# CHECK-NEXT: MemSize: 16
+# 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: 0x2000
+# CHECK-NEXT: VirtualAddress: 0x3000
+# CHECK-NEXT: PhysicalAddress: 0x7000
+# CHECK-NEXT: FileSize: 24
+# CHECK-NEXT: MemSize: 24
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_W
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 4096
+# CHECK-NEXT: }
+
+# SECTIONS: Sections:
+# SECTIONS-NEXT: Idx Name Size Address
+# SECTIONS-NEXT: 0 00000000 0000000000000000
+# SECTIONS-NEXT: 1 .foo1 00000008 0000000000002000
+# SECTIONS-NEXT: 2 .foo2 00000008 0000000000002008
+# SECTIONS-NEXT: 3 .text 00000000 0000000000002010
+# SECTIONS-NEXT: 4 .bar1 00000008 0000000000003000
+# SECTIONS-NEXT: 5 .bar2 00000008 0000000000003008
+# SECTIONS-NEXT: 6 .bar3 00000008 0000000000003010
diff --git a/test/ELF/linkerscript/at3.test b/test/ELF/linkerscript/at3.test
new file mode 100644
index 000000000000..6344f38b304d
--- /dev/null
+++ b/test/ELF/linkerscript/at3.test
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at3.s -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t
+# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s
+
+MEMORY {
+ FOO (ax) : ORIGIN = 0x1000, LENGTH = 0x100
+ BAR (ax) : ORIGIN = 0x2000, LENGTH = 0x100
+ ZED (ax) : ORIGIN = 0x3000, LENGTH = 0x100
+ FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x200
+}
+
+SECTIONS {
+ .foo1 : { *(.foo1) } > FOO AT>FLASH
+ .foo2 : { *(.foo2) BYTE(0x42) } > BAR AT>FLASH
+ .foo3 : { *(.foo3) } > ZED AT>FLASH
+}
+
+# CHECK: .foo1 PROGBITS 0000000000001000 001000
+# CHECK: .foo2 PROGBITS 0000000000002000 002000
+# CHECK: .foo3 PROGBITS 0000000000003000 003000
+
+# CHECK: Program Headers:
+# CHECK-NOT: LOAD
+
+# CHECK: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000006000
+# CHECK-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000006008
+# CHECK-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000006011
+
+# CHECK-NOT: LOAD
diff --git a/test/ELF/linkerscript/at4.s b/test/ELF/linkerscript/at4.s
new file mode 100644
index 000000000000..a6fa50820376
--- /dev/null
+++ b/test/ELF/linkerscript/at4.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1000; \
+# RUN: .aaa : { *(.aaa) } \
+# RUN: .bbb : AT(0x2008) { *(.bbb) } \
+# RUN: .ccc : { *(.ccc) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x1000
+# CHECK-NEXT: PhysicalAddress: 0x1000
+# CHECK-NEXT: FileSize: 8
+# CHECK-NEXT: MemSize: 8
+# CHECK: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1008
+# CHECK-NEXT: VirtualAddress: 0x1008
+# CHECK-NEXT: PhysicalAddress: 0x2008
+# CHECK-NEXT: FileSize: 17
+# CHECK-NEXT: MemSize: 17
+
+.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/at5.test b/test/ELF/linkerscript/at5.test
new file mode 100644
index 000000000000..8e1ed93bcad9
--- /dev/null
+++ b/test/ELF/linkerscript/at5.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -o %t.exe %t.o --script %s 2>&1 | FileCheck %s
+
+MEMORY {
+ FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100
+ RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100
+}
+
+SECTIONS {
+ .foo1 : AT(0x500) { *(.foo1) } > FLASH AT>FLASH
+}
+
+# CHECK: error: section can't have both LMA and a load region
diff --git a/test/ELF/linkerscript/broken-memory-declaration.s b/test/ELF/linkerscript/broken-memory-declaration.s
new file mode 100644
index 000000000000..197c9cd22b6d
--- /dev/null
+++ b/test/ELF/linkerscript/broken-memory-declaration.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+
+## Check we do not crash.
+
+# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000< LENGTH" > %t.script
+# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s
+# CHECK: unexpected EOF
+
+# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000< ORIGIN" > %t.script
+# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s
+
+# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000, LENGTH = CONSTANT" > %t.script
+# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s
diff --git a/test/ELF/linkerscript/bss-fill.s b/test/ELF/linkerscript/bss-fill.s
deleted file mode 100644
index 92f9fdf56190..000000000000
--- a/test/ELF/linkerscript/bss-fill.s
+++ /dev/null
@@ -1,7 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { .bss : { . += 0x10000; *(.bss) } =0xFF };" > %t.script
-# RUN: ld.lld -o %t --script %t.script %t.o
-
-.section .bss,"",@nobits
-.short 0
diff --git a/test/ELF/linkerscript/bss-fill.test b/test/ELF/linkerscript/bss-fill.test
new file mode 100644
index 000000000000..b7ed47656172
--- /dev/null
+++ b/test/ELF/linkerscript/bss-fill.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: echo '.section .bss,"",@nobits; .short 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+
+## Check we do not crash.
+
+SECTIONS {
+ .bss : {
+ . += 0x10000;
+ *(.bss)
+ } =0xFF
+}
diff --git a/test/ELF/linkerscript/common-filespec.s b/test/ELF/linkerscript/common-filespec.test
index 25bb486ed445..2afd91d3d5b7 100644
--- a/test/ELF/linkerscript/common-filespec.s
+++ b/test/ELF/linkerscript/common-filespec.test
@@ -1,11 +1,17 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile0.o
+# RUN: echo '.long 0; .comm common_uniq_0,4,4; .comm common_multiple,8,8' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tfile0.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec1.s -o %tfile1.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o
-# RUN: echo "SECTIONS { .common_0 : { *file0.o(COMMON) } .common_1 : { *file1.o(COMMON) } .common_2 : { *file2.o(COMMON) } }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %tfile0.o %tfile1.o %tfile2.o
+# RUN: ld.lld -o %t1 --script %s %tfile0.o %tfile1.o %tfile2.o
# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+SECTIONS {
+ .common_0 : { *file0.o(COMMON) }
+ .common_1 : { *file1.o(COMMON) }
+ .common_2 : { *file2.o(COMMON) }
+}
+
# Make sure all 3 sections are allocated and they have sizes and alignments
# corresponding to the commons assigned to them
# CHECK: Section {
@@ -96,10 +102,3 @@
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: .common_2
# CHECK-NEXT: }
-
-.globl _start
-_start:
- jmp _start
-
-.comm common_uniq_0,4,4
-.comm common_multiple,8,8
diff --git a/test/ELF/linkerscript/compress-debug-sections-custom.s b/test/ELF/linkerscript/compress-debug-sections-custom.s
new file mode 100644
index 000000000000..31fdd56381b0
--- /dev/null
+++ b/test/ELF/linkerscript/compress-debug-sections-custom.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86, zlib
+
+# RUN: echo "SECTIONS { \
+# RUN: .text : { . += 0x10; *(.text) } \
+# RUN: .debug_str : { . += 0x10; *(.debug_str) } \
+# RUN: .debug_info : { . += 0x10; *(.debug_info) } \
+# RUN: }" > %t.script
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/../Inputs/compress-debug.s -o %t2.o
+# RUN: ld.lld %t2.o %t.o -o %t1 --compress-debug-sections=zlib -T %t.script
+# RUN: llvm-dwarfdump %t1 -debug-str | FileCheck %s
+# These two checks correspond to the patched values of a_sym and a_debug_sym.
+# T = 0x54 - address of .text input section for this file (the start address of
+# .text is 0 by default, the size of the preceding .text in the other input
+# file is 0x44, and the linker script adds an additional 0x10).
+# S = 0x53 - offset of .debug_info section for this file (the size of
+# the preceding .debug_info from the other input file is 0x43, and the
+# linker script adds an additional 0x10).
+# Also note that the .debug_str offsets are also offset by 0x10, as directed by
+# the linker script.
+# CHECK: 0x00000010: "T"
+# CHECK: 0x00000014: "S"
+
+.text
+a_sym:
+nop
+
+.section .debug_str,"",@progbits
+.long a_sym
+.long a_debug_sym
+
+.section .debug_info,"",@progbits
+a_debug_sym:
+.long 0x88776655
diff --git a/test/ELF/linkerscript/constructor.s b/test/ELF/linkerscript/constructor.test
index acb86fd88e27..edd2cd297997 100644
--- a/test/ELF/linkerscript/constructor.s
+++ b/test/ELF/linkerscript/constructor.test
@@ -1,7 +1,7 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { foo : { *(.foo) CONSTRUCTORS } }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t.o
+# RUN: echo '.section foo, "a"; .byte 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld -o %t1 --script %s %t.o
# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
# CHECK: Sections:
@@ -9,5 +9,9 @@
# CHECK-NEXT: 0 00000000
# CHECK-NEXT: 1 foo 00000001
-.section foo, "a"
-.byte 0
+SECTIONS {
+ foo : {
+ *(.foo)
+ CONSTRUCTORS
+ }
+}
diff --git a/test/ELF/linkerscript/copy-rel-symbol-value-err.s b/test/ELF/linkerscript/copy-rel-symbol-value-err.s
index f134edbb1d0c..cd5262b142f5 100644
--- a/test/ELF/linkerscript/copy-rel-symbol-value-err.s
+++ b/test/ELF/linkerscript/copy-rel-symbol-value-err.s
@@ -3,7 +3,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-rel-symbol-value.s -o %t2.o
# RUN: ld.lld %t2.o -o %t2.so -shared
# RUN: echo "SECTIONS { . = . + SIZEOF_HEADERS; foo = bar; }" > %t.script
-# RUN: not ld.lld %t.o %t2.so --script %t.script -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o %t2.so --script %t.script -o /dev/null 2>&1 | FileCheck %s
# CHECK: symbol not found: bar
diff --git a/test/ELF/linkerscript/data-commands-gc.s b/test/ELF/linkerscript/data-commands-gc.s
index 1afcc9a3bb81..6d5ae8c9ef9d 100644
--- a/test/ELF/linkerscript/data-commands-gc.s
+++ b/test/ELF/linkerscript/data-commands-gc.s
@@ -4,7 +4,7 @@
# RUN: ld.lld --gc-sections -o %t %t.o --script %t.script
# RUN: llvm-objdump -t %t | FileCheck %s
-# CHECK: 0000000000000011 .rodata 00000000 bar
+# CHECK: 0000000000000008 .rodata 00000000 bar
.section .rodata.bar
.quad 0x1122334455667788
diff --git a/test/ELF/linkerscript/data-commands.s b/test/ELF/linkerscript/data-commands.s
deleted file mode 100644
index 5a5655620dd9..000000000000
--- a/test/ELF/linkerscript/data-commands.s
+++ /dev/null
@@ -1,117 +0,0 @@
-# REQUIRES: x86,mips
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS \
-# RUN: { \
-# RUN: .foo : { \
-# RUN: *(.foo.1) \
-# RUN: BYTE(0x11) \
-# RUN: *(.foo.2) \
-# RUN: SHORT(0x1122) \
-# RUN: *(.foo.3) \
-# RUN: LONG(0x11223344) \
-# RUN: *(.foo.4) \
-# RUN: QUAD(0x1122334455667788) \
-# RUN: } \
-# RUN: .bar : { \
-# RUN: *(.bar.1) \
-# RUN: BYTE(a + 1) \
-# RUN: *(.bar.2) \
-# RUN: SHORT(b) \
-# RUN: *(.bar.3) \
-# RUN: LONG(c + 2) \
-# RUN: *(.bar.4) \
-# RUN: QUAD(d) \
-# RUN: } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t %t.o --script %t.script
-# RUN: llvm-objdump -s %t | FileCheck %s
-
-# CHECK: Contents of section .foo:
-# CHECK-NEXT: ff11ff22 11ff4433 2211ff88 77665544
-# CHECK-NEXT: 332211
-
-# CHECK: Contents of section .bar:
-# CHECK-NEXT: ff12ff22 11ff4633 2211ff88 77665544
-# CHECK-NEXT: 332211
-
-# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %tmips64be
-# RUN: ld.lld --script %t.script %tmips64be -o %t2
-# RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=BE
-# BE: Contents of section .foo:
-# BE-NEXT: ff11ff11 22ff1122 3344ff11 22334455
-# BE-NEXT: 667788
-# BE-NEXT: Contents of section .bar:
-# BE-NEXT: ff12ff11 22ff1122 3346ff11 22334455
-# BE-NEXT: 667788
-
-# RUN: echo "MEMORY { \
-# RUN: rom (rwx) : ORIGIN = 0x00, LENGTH = 2K \
-# RUN: } \
-# RUN: SECTIONS { \
-# RUN: .foo : { \
-# RUN: *(.foo.1) \
-# RUN: BYTE(0x11) \
-# RUN: *(.foo.2) \
-# RUN: SHORT(0x1122) \
-# RUN: *(.foo.3) \
-# RUN: LONG(0x11223344) \
-# RUN: *(.foo.4) \
-# RUN: QUAD(0x1122334455667788) \
-# RUN: } > rom \
-# RUN: .bar : { \
-# RUN: *(.bar.1) \
-# RUN: BYTE(a + 1) \
-# RUN: *(.bar.2) \
-# RUN: SHORT(b) \
-# RUN: *(.bar.3) \
-# RUN: LONG(c + 2) \
-# RUN: *(.bar.4) \
-# RUN: QUAD(d) \
-# RUN: } > rom \
-# RUN: }" > %t-memory.script
-# RUN: ld.lld -o %t-memory %t.o --script %t-memory.script
-# RUN: llvm-objdump -s %t-memory | FileCheck %s --check-prefix=MEM
-
-# MEM: Contents of section .foo:
-# MEM-NEXT: 0000 ff11ff22 11ff4433 2211ff88 77665544
-# MEM-NEXT: 0010 332211
-
-# MEM: Contents of section .bar:
-# MEM-NEXT: 0013 ff12ff22 11ff4633 2211ff88 77665544
-# MEM-NEXT: 0023 332211
-
-.global a
-a = 0x11
-
-.global b
-b = 0x1122
-
-.global c
-c = 0x11223344
-
-.global d
-d = 0x1122334455667788
-
-.section .foo.1, "a"
- .byte 0xFF
-
-.section .foo.2, "a"
- .byte 0xFF
-
-.section .foo.3, "a"
- .byte 0xFF
-
-.section .foo.4, "a"
- .byte 0xFF
-
-.section .bar.1, "a"
- .byte 0xFF
-
-.section .bar.2, "a"
- .byte 0xFF
-
-.section .bar.3, "a"
- .byte 0xFF
-
-.section .bar.4, "a"
- .byte 0xFF
diff --git a/test/ELF/linkerscript/data-commands1.test b/test/ELF/linkerscript/data-commands1.test
new file mode 100644
index 000000000000..32c5978c30a8
--- /dev/null
+++ b/test/ELF/linkerscript/data-commands1.test
@@ -0,0 +1,45 @@
+# REQUIRES: x86,mips
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/data-commands.s -o %t.o
+# RUN: ld.lld -o %t %t.o --script %s
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+SECTIONS {
+ .foo : {
+ *(.foo.1)
+ BYTE(0x11)
+ *(.foo.2)
+ SHORT(0x1122)
+ *(.foo.3)
+ LONG(0x11223344)
+ *(.foo.4)
+ QUAD(0x1122334455667788)
+ }
+ .bar : {
+ *(.bar.1)
+ BYTE(a + 1)
+ *(.bar.2)
+ SHORT(b)
+ *(.bar.3)
+ LONG(c + 2)
+ *(.bar.4)
+ QUAD(d)
+ }
+}
+
+# CHECK: Contents of section .foo:
+# CHECK-NEXT: ff11ff22 11ff4433 2211ff88 77665544
+# CHECK-NEXT: 332211
+
+# CHECK: Contents of section .bar:
+# CHECK-NEXT: ff12ff22 11ff4633 2211ff88 77665544
+# CHECK-NEXT: 332211
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %p/Inputs/data-commands.s -o %t2.o
+# RUN: ld.lld --script %s %t2.o -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=BIGENDIAN %s
+# BIGENDIAN: Contents of section .foo:
+# BIGENDIAN-NEXT: ff11ff11 22ff1122 3344ff11 22334455
+# BIGENDIAN-NEXT: 667788
+# BIGENDIAN-NEXT: Contents of section .bar:
+# BIGENDIAN-NEXT: ff12ff11 22ff1122 3346ff11 22334455
+# BIGENDIAN-NEXT: 667788
diff --git a/test/ELF/linkerscript/data-commands2.test b/test/ELF/linkerscript/data-commands2.test
new file mode 100644
index 000000000000..e1efa35965cb
--- /dev/null
+++ b/test/ELF/linkerscript/data-commands2.test
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/data-commands.s -o %t.o
+# RUN: ld.lld -o %t %t.o --script %s
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+MEMORY {
+ rom (rwx) : ORIGIN = 0x00, LENGTH = 2K
+}
+
+SECTIONS {
+ .foo : {
+ *(.foo.1)
+ BYTE(0x11)
+ *(.foo.2)
+ SHORT(0x1122)
+ *(.foo.3)
+ LONG(0x11223344)
+ *(.foo.4)
+ QUAD(0x1122334455667788)
+ } > rom
+
+ .bar : {
+ *(.bar.1)
+ BYTE(a + 1)
+ *(.bar.2)
+ SHORT(b)
+ *(.bar.3)
+ LONG(c + 2)
+ *(.bar.4)
+ QUAD(d)
+ } > rom
+}
+
+# CHECK: Contents of section .foo:
+# CHECK-NEXT: 0000 ff11ff22 11ff4433 2211ff88 77665544
+# CHECK-NEXT: 0010 332211
+
+# CHECK: Contents of section .bar:
+# CHECK-NEXT: 0013 ff12ff22 11ff4633 2211ff88 77665544
+# CHECK-NEXT: 0023 332211
diff --git a/test/ELF/linkerscript/data-segment-relro.s b/test/ELF/linkerscript/data-segment-relro.test
index e835f42e22c6..aeaf08540871 100644
--- a/test/ELF/linkerscript/data-segment-relro.s
+++ b/test/ELF/linkerscript/data-segment-relro.test
@@ -1,29 +1,37 @@
# 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/data-segment-relro.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: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .plt : { *(.plt) } \
-# RUN: .text : { *(.text) } \
-# RUN: . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \
-# RUN: .dynamic : { *(.dynamic) } \
-# RUN: .got : { *(.got) } \
-# RUN: . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .); \
-# RUN: .got.plt : { *(.got.plt) } \
-# RUN: .data : { *(.data) } \
-# RUN: .bss : { *(.bss) } \
-# RUN: . = DATA_SEGMENT_END (.); \
-# RUN: }" > %t.script
-
## With relro or without DATA_SEGMENT_RELRO_END just aligns to
## page boundary.
-# RUN: ld.lld --hash-style=sysv -z norelro %t1.o %t2.so --script %t.script -o %t
+
+# RUN: ld.lld --hash-style=sysv -z norelro %t1.o %t2.so --script %s -o %t
# RUN: llvm-readobj -s %t | FileCheck %s
-# RUN: ld.lld --hash-style=sysv -z relro %t1.o %t2.so --script %t.script -o %t2
+
+# RUN: ld.lld --hash-style=sysv -z relro %t1.o %t2.so --script %s -o %t2
# RUN: llvm-readobj -s %t2 | FileCheck %s
+SECTIONS {
+ . = SIZEOF_HEADERS;
+
+ .plt : { *(.plt) }
+ .text : { *(.text) }
+
+ . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) }
+
+ . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .);
+
+ .got.plt : { *(.got.plt) }
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+
+ . = DATA_SEGMENT_END (.);
+}
+
# CHECK: Section {
# CHECK: Index:
# CHECK: Name: .got
@@ -56,15 +64,3 @@
# CHECK-NEXT: AddressAlignment:
# CHECK-NEXT: EntrySize:
# CHECK-NEXT: }
-
-.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/linkerscript/define.s b/test/ELF/linkerscript/define.s
deleted file mode 100644
index b5f0b76e9e6b..000000000000
--- a/test/ELF/linkerscript/define.s
+++ /dev/null
@@ -1,25 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS \
-# RUN: { \
-# RUN: . = DEFINED(defined) ? 0x11000 : .; \
-# RUN: .foo : { *(.foo*) } \
-# RUN: . = DEFINED(notdefined) ? 0x12000 : 0x13000; \
-# RUN: .bar : { *(.bar*) } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
-
-# CHECK: 1 .foo 00000008 0000000000011000 DATA
-# CHECK: 2 .bar 00000008 0000000000013000 DATA
-# CHECK: 3 .text 00000000 0000000000013008 TEXT DATA
-
-.global defined
-defined = 0
-
-.section .foo,"a"
-.quad 1
-
-.section .bar,"a"
-.quad 1
diff --git a/test/ELF/linkerscript/define.test b/test/ELF/linkerscript/define.test
new file mode 100644
index 000000000000..3a2e242e015c
--- /dev/null
+++ b/test/ELF/linkerscript/define.test
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/define.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+SECTIONS {
+ . = DEFINED(defined) ? 0x11000 : .;
+ .foo : { *(.foo*) }
+ . = DEFINED(notdefined) ? 0x12000 : 0x13000;
+ .bar : { *(.bar*) }
+}
+
+# CHECK: 1 .foo 00000008 0000000000011000 DATA
+# CHECK: 2 .bar 00000008 0000000000013000 DATA
+# CHECK: 3 .text 00000000 0000000000013008 TEXT
diff --git a/test/ELF/linkerscript/defsym.s b/test/ELF/linkerscript/defsym.s
new file mode 100644
index 000000000000..467adaeea2f8
--- /dev/null
+++ b/test/ELF/linkerscript/defsym.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "foo = 0x22;" > %t.script
+
+## This testcase checks that we apply -defsym and linker script
+## in the same order are they specified in a command line.
+
+## Check that linker script can override -defsym assignments.
+# RUN: ld.lld %t.o -defsym=foo=0x11 -script %t.script -o %t
+# RUN: llvm-readobj -t %t | FileCheck %s
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x22
+
+## Check that -defsym can override linker script. Check that multiple
+## -defsym commands for the same symbol are allowed.
+# RUN: ld.lld %t.o -script %t.script -defsym=foo=0x11 -defsym=foo=0x33 -o %t
+# RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=REORDER
+# REORDER: Name: foo
+# REORDER-NEXT: Value: 0x33
diff --git a/test/ELF/linkerscript/diag1.test b/test/ELF/linkerscript/diag1.test
new file mode 100644
index 000000000000..73a627ff4ef5
--- /dev/null
+++ b/test/ELF/linkerscript/diag1.test
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s
+
+SECTIONS {
+ .text + { *(.text) }
+ .keep : { *(.keep) } /*
+ comment line 1
+ comment line 2 */
+ .temp : { *(.temp) }
+}
+
+CHECK: 6: malformed number: +
+CHECK-NEXT: >>> .text + { *(.text) }
+CHECK-NEXT: >>> ^
diff --git a/test/ELF/linkerscript/diag2.test b/test/ELF/linkerscript/diag2.test
new file mode 100644
index 000000000000..05cd4c3a752a
--- /dev/null
+++ b/test/ELF/linkerscript/diag2.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s
+
+UNKNOWN_TAG {
+ .text : { *(.text) }
+ .keep : { *(.keep) }
+ .temp : { *(.temp) }
+}
+
+CHECK: 5: unknown directive: UNKNOWN_TAG
+CHECK-NEXT: >>> UNKNOWN_TAG {
+CHECK-NEXT: >>> ^
diff --git a/test/ELF/linkerscript/diag3.test b/test/ELF/linkerscript/diag3.test
new file mode 100644
index 000000000000..8ffc9d4d864c
--- /dev/null
+++ b/test/ELF/linkerscript/diag3.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s
+
+SECTIONS {
+ .text : { *(.text) }
+ .keep : { *(.keep) }
+ boom .temp : { *(.temp) }
+}
+
+# CHECK: 8: malformed number: .temp
+# CHECK-NEXT: >>> boom .temp : { *(.temp) }
+# CHECK-NEXT: >>> ^
diff --git a/test/ELF/linkerscript/diag4.test b/test/ELF/linkerscript/diag4.test
new file mode 100644
index 000000000000..484bdf26fe72
--- /dev/null
+++ b/test/ELF/linkerscript/diag4.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: echo "INCLUDE \"%s\"" > %t.script
+# RUN: not ld.lld -shared %t.o -o %t --script %t.script 2>&1 | FileCheck -strict-whitespace %s
+
+SECTIONS {
+ .text : { *(.text) }
+ .keep : { *(.keep) }
+ boom .temp : { *(.temp) }
+}
+
+# CHECK: 9: malformed number: .temp
+# CHECK-NEXT: >>> boom .temp : { *(.temp) }
+# CHECK-NEXT: >>> ^ \ No newline at end of file
diff --git a/test/ELF/linkerscript/diag5.test b/test/ELF/linkerscript/diag5.test
new file mode 100644
index 000000000000..38a774e747ab
--- /dev/null
+++ b/test/ELF/linkerscript/diag5.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: echo "INCLUDE \"%s\"" > %t.script
+# RUN: not ld.lld -shared %t.o -o %t --script %t.script 2>&1 | FileCheck -strict-whitespace %s
+
+SECTIONS {
+ .text : { *(.text) }
+ .keep : { *(.keep) }
+ boom .temp : { *(.temp) }
+}
+
+# CHECK: 9: malformed number: .temp
+# CHECK-NEXT: >>> boom .temp : { *(.temp) }
+# CHECK-NEXT: >>> ^
diff --git a/test/ELF/linkerscript/diag6.test b/test/ELF/linkerscript/diag6.test
new file mode 100644
index 000000000000..e4ad4d96d1dd
--- /dev/null
+++ b/test/ELF/linkerscript/diag6.test
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck %s
+
+SECTIONS /*
+
+CHECK: error: unclosed comment in a linker script
diff --git a/test/ELF/linkerscript/diagnostic.s b/test/ELF/linkerscript/diagnostic.s
deleted file mode 100644
index af185729c430..000000000000
--- a/test/ELF/linkerscript/diagnostic.s
+++ /dev/null
@@ -1,106 +0,0 @@
-# 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: {{.*}}.script: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: {{.*}}.script: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: {{.*}}.script: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 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR6 -strict-whitespace %s
-# ERR6: error: {{.*}}.script:1: unknown directive: UNKNOWN_TAG
-# ERR6-NEXT: >>> UNKNOWN_TAG {
-# ERR6-NEXT: >>> ^
-
-## 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 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR7 -strict-whitespace %s
-# ERR7: error: {{.*}}.script:4: malformed number: .temp
-# ERR7-NEXT: >>> boom .temp : { *(.temp) } }
-# ERR7-NEXT: >>> ^
-
-## Check tokenize() error
-# RUN: echo "SECTIONS {}" > %t.script
-# RUN: echo "\"" >> %t.script
-# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR8 -strict-whitespace %s
-# ERR8: {{.*}}.script:2: unclosed quote
-
-## Check tokenize() error in included script file
-# RUN: echo "SECTIONS {}" > %t.script.inc
-# RUN: echo "\"" >> %t.script.inc
-# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
-# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR9 -strict-whitespace %s
-# ERR9: {{.*}}.script.inc:2: unclosed quote
-
-## Check error reporting correctness for included files.
-# RUN: echo "SECTIONS {" > %t.script.inc
-# RUN: echo ".text : { *(.text) }" >> %t.script.inc
-# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
-# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script.inc
-# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
-# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR10 -strict-whitespace %s
-# ERR10: error: {{.*}}.script.inc:4: malformed number: .temp
-# ERR10-NEXT: >>> boom .temp : { *(.temp) } }
-# ERR10-NEXT: >>> ^
-
-## Check error reporting in script with INCLUDE directive.
-# RUN: echo "SECTIONS {" > %t.script.inc
-# RUN: echo ".text : { *(.text) }" >> %t.script.inc
-# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
-# RUN: echo ".temp : { *(.temp) } }" >> %t.script.inc
-# RUN: echo "/* One line before INCLUDE */" > %t.script
-# RUN: echo "INCLUDE \"%t.script.inc\"" >> %t.script
-# RUN: echo "/* One line ater INCLUDE */" >> %t.script
-# RUN: echo "Error" >> %t.script
-# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
-# RUN: FileCheck -check-prefix=ERR11 -strict-whitespace %s
-# ERR11: error: {{.*}}.script:4: unexpected EOF
diff --git a/test/ELF/linkerscript/discard-gnu-hash.s b/test/ELF/linkerscript/discard-gnu-hash.s
new file mode 100644
index 000000000000..77f168de9caf
--- /dev/null
+++ b/test/ELF/linkerscript/discard-gnu-hash.s
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld --hash-style both -shared -o %t1 %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: .gnu.hash
+# CHECK: .hash
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.hash) } }" > %t.script
+# RUN: ld.lld --hash-style both -shared -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 \
+# RUN: | FileCheck %s --check-prefix=HASH
+# HASH-NOT: .hash
+# HASH: .gnu.hash
+# HASH-NOT: .hash
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.gnu.hash) } }" > %t.script
+# RUN: ld.lld --hash-style both -shared -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 \
+# RUN: | FileCheck %s --check-prefix=GNUHASH
+# GNUHASH-NOT: .gnu.hash
+# GNUHASH: .hash
+# GNUHASH-NOT: .gnu.hash
diff --git a/test/ELF/linkerscript/discard-interp.s b/test/ELF/linkerscript/discard-interp.s
deleted file mode 100644
index 261509e2e76b..000000000000
--- a/test/ELF/linkerscript/discard-interp.s
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; } \
-// RUN: SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } : text }" > %t.script
-// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --script %t.script --export-dynamic %t.o %t2.so -o %t
-// RUN: llvm-readobj -s %t | FileCheck %s
-
-// CHECK-NOT: Name: .interp
-
-.global _start
-_start:
diff --git a/test/ELF/linkerscript/discard-interp.test b/test/ELF/linkerscript/discard-interp.test
new file mode 100644
index 000000000000..02e97b99958c
--- /dev/null
+++ b/test/ELF/linkerscript/discard-interp.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -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 -dynamic-linker foo -rpath bar -rpath baz --script %s --export-dynamic %t.o %t2.so -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK-NOT: Name: .interp
+
+PHDRS { text PT_LOAD FILEHDR PHDRS; }
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .text : { *(.text) } : text
+}
diff --git a/test/ELF/linkerscript/discard-print-gc.s b/test/ELF/linkerscript/discard-print-gc.s
index 2a230e53dc2b..c9233ce7b0eb 100644
--- a/test/ELF/linkerscript/discard-print-gc.s
+++ b/test/ELF/linkerscript/discard-print-gc.s
@@ -15,5 +15,5 @@
.section .foo,"a"
.quad 0
-# CHECK: removing unused section from '.foo'
-# QUIET-NOT: removing unused section from '.foo'
+# CHECK: removing unused section {{.*}}:(.foo)
+# QUIET-NOT: removing unused section {{.*}}:(.foo)
diff --git a/test/ELF/linkerscript/discard-section-err.s b/test/ELF/linkerscript/discard-section-err.s
index 8ad5b486cb39..f1d3b96691ba 100644
--- a/test/ELF/linkerscript/discard-section-err.s
+++ b/test/ELF/linkerscript/discard-section-err.s
@@ -22,4 +22,14 @@
# RUN: FileCheck -check-prefix=DYNSTR %s
# DYNSTR: discarding .dynstr section is not allowed
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.rela.plt) } }" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=RELAPLT %s
+# RELAPLT: discarding .rela.plt section is not allowed
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.rela.dyn) } }" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=RELADYN %s
+# RELADYN: discarding .rela.dyn section is not allowed
+
.comm foo,4,4
diff --git a/test/ELF/linkerscript/dot-is-not-abs.s b/test/ELF/linkerscript/dot-is-not-abs.s
index 4532cd59f2a1..a93d1c8b4344 100644
--- a/test/ELF/linkerscript/dot-is-not-abs.s
+++ b/test/ELF/linkerscript/dot-is-not-abs.s
@@ -1,9 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { .text : { *(.text) } \
-# RUN: foo = .; \
-# RUN: .bar : { *(.bar) } }" > %t1.script
+# RUN: echo "SECTIONS { .text : { *(.text) } foo = .; .bar : { *(.bar) } }" > %t1.script
# RUN: ld.lld -o %t1 --script %t1.script %t.o -shared
# RUN: llvm-readobj -t -s -section-data %t1 | FileCheck %s
diff --git a/test/ELF/linkerscript/double-bss.s b/test/ELF/linkerscript/double-bss.s
deleted file mode 100644
index c24332f5e5a6..000000000000
--- a/test/ELF/linkerscript/double-bss.s
+++ /dev/null
@@ -1,21 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; " > %t.script
-# RUN: echo ".text : { *(.text*) }" >> %t.script
-# RUN: echo ".bss1 : { *(.bss) }" >> %t.script
-# RUN: echo ".bss2 : { *(COMMON) }" >> %t.script
-# RUN: echo "}" >> %t.script
-
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
-# CHECK: .bss1 00000004 0000000000000122 BSS
-# CHECK-NEXT: .bss2 00000080 0000000000000128 BSS
-
-.globl _start
-_start:
- jmp _start
-
-.bss
-.zero 4
-
-.comm q,128,8
diff --git a/test/ELF/linkerscript/double-bss.test b/test/ELF/linkerscript/double-bss.test
new file mode 100644
index 000000000000..32b796d01c2e
--- /dev/null
+++ b/test/ELF/linkerscript/double-bss.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: echo '.short 0; .bss; .zero 4; .comm q,128,8' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t
+# RUN: ld.lld -o %t1 --script %s %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: .bss1 00000004 0000000000000122 BSS
+# CHECK-NEXT: .bss2 00000080 0000000000000128 BSS
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .text : { *(.text*) }
+ .bss1 : { *(.bss) }
+ .bss2 : { *(COMMON) }
+}
diff --git a/test/ELF/linkerscript/edata-etext.s b/test/ELF/linkerscript/edata-etext.s
index ab723ce1316e..c15cf4c865c0 100644
--- a/test/ELF/linkerscript/edata-etext.s
+++ b/test/ELF/linkerscript/edata-etext.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "SECTIONS { }" > %t.script
-# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o -script %t.script -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: undefined symbol: _edata
# CHECK: >>> referenced by {{.*}}:(.text+0x0)
# CHECK: error: undefined symbol: _etext
diff --git a/test/ELF/linkerscript/eh-frame-emit-relocs.s b/test/ELF/linkerscript/eh-frame-emit-relocs.s
new file mode 100644
index 000000000000..d951cbc261b9
--- /dev/null
+++ b/test/ELF/linkerscript/eh-frame-emit-relocs.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: echo "SECTIONS { .foo : { *(.eh_frame) } }" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --emit-relocs %t.o -T %t.script -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# CHECK-NOT: eh_frame
+# CHECK: .rela.foo
+# CHECK-NOT: eh_frame
+
+.text
+ .cfi_startproc
+ .cfi_endproc
diff --git a/test/ELF/linkerscript/eh-frame-hdr.s b/test/ELF/linkerscript/eh-frame-hdr.s
index d1545be632a3..a7892b2259e0 100644
--- a/test/ELF/linkerscript/eh-frame-hdr.s
+++ b/test/ELF/linkerscript/eh-frame-hdr.s
@@ -1,13 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { \
-# RUN: .eh_frame_hdr : {} \
-# RUN: .eh_frame : {} \
-# RUN: }" > %t.script
+# RUN: echo "SECTIONS { .eh_frame_hdr : {} .eh_frame : {} }" > %t.script
# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
# RUN: llvm-objdump -s -section=".eh_frame_hdr" %t1 | FileCheck %s
-# CHECK: 011b033b 14000000 01000000 49000000
+# CHECK: 011b033b 14000000 01000000 4d000000
# CHECK-NEXT: 30000000
.global _start
diff --git a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s
deleted file mode 100644
index 817e458fa5ef..000000000000
--- a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s
+++ /dev/null
@@ -1,27 +0,0 @@
-## Check that error is correctly reported when .eh_frame reloc
-## is out of range
-
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "PHDRS { eh PT_LOAD; text PT_LOAD; } \
-# RUN: SECTIONS { . = 0x10000; \
-# RUN: .eh_frame_hdr : { *(.eh_frame_hdr*) } : eh \
-# RUN: .eh_frame : { *(.eh_frame) } : eh \
-# RUN: . = 0xF00000000; \
-# RUN: .text : { *(.text*) } : text \
-# RUN: }" > %t.script
-# RUN: not ld.lld %t.o -T %t.script -o %t 2>&1 | FileCheck %s
-
-# CHECK: error: {{.*}}:(.eh_frame+0x20): relocation R_X86_64_PC32 out of range: 64424443872 is not in [-2147483648, 2147483647]
-
- .text
- .globl _start
-_start:
- .cfi_startproc
- .cfi_lsda 0, _ex
- nop
- .cfi_endproc
-
- .data
-_ex:
- .word 0
diff --git a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test
new file mode 100644
index 000000000000..7f4df21fd4c4
--- /dev/null
+++ b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/eh-frame-reloc-out-of-range.s -o %t.o
+# RUN: not ld.lld %t.o -T %s -o %t 2>&1 | FileCheck %s
+
+PHDRS { eh PT_LOAD; text PT_LOAD; }
+SECTIONS { . = 0x10000;
+ .eh_frame_hdr : { *(.eh_frame_hdr*) } : eh
+ .eh_frame : { *(.eh_frame) } : eh
+ . = 0xF00000000;
+ .text : { *(.text*) } : text
+}
+
+# CHECK: error: {{.*}}:(.eh_frame+0x20): relocation R_X86_64_PC32 out of range: 64424443872 is not in [-2147483648, 2147483647]
diff --git a/test/ELF/linkerscript/eh-frame.s b/test/ELF/linkerscript/eh-frame.s
index 750f74eb36c6..5e43ec738f7b 100644
--- a/test/ELF/linkerscript/eh-frame.s
+++ b/test/ELF/linkerscript/eh-frame.s
@@ -1,8 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { \
-# RUN: .eh_frame : { *(.eh_frame) } \
-# RUN: }" > %t.script
+# RUN: echo "SECTIONS { .eh_frame : { *(.eh_frame) } }" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump -s -section=".eh_frame" %t1 | FileCheck %s
diff --git a/test/ELF/linkerscript/emit-reloc-section-names.s b/test/ELF/linkerscript/emit-reloc-section-names.s
index 8661ff060a79..7f76057322e8 100644
--- a/test/ELF/linkerscript/emit-reloc-section-names.s
+++ b/test/ELF/linkerscript/emit-reloc-section-names.s
@@ -1,7 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { .text.zed : { *(.text.foo) } \
-# RUN: .text.qux : { *(.text.bar) } }" > %t.script
+# RUN: echo "SECTIONS { .text.zed : { *(.text.foo) } .text.qux : { *(.text.bar) } }" > %t.script
# RUN: ld.lld -T %t.script --emit-relocs %t.o -o %t
# RUN: llvm-objdump -section-headers %t | FileCheck %s
diff --git a/test/ELF/linkerscript/emit-reloc.s b/test/ELF/linkerscript/emit-reloc.s
index 2fe127af8590..43ab4e8e47d8 100644
--- a/test/ELF/linkerscript/emit-reloc.s
+++ b/test/ELF/linkerscript/emit-reloc.s
@@ -9,9 +9,9 @@
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section ({{.*}}) .rela.data {
-# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/linkerscript/empty-link-order.test b/test/ELF/linkerscript/empty-link-order.test
new file mode 100644
index 000000000000..b63b60ca8c15
--- /dev/null
+++ b/test/ELF/linkerscript/empty-link-order.test
@@ -0,0 +1,21 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=arm-arm-none-eabi -o %t.o < /dev/null
+
+SECTIONS {
+ .foo : {
+ bar = .;
+ *(.ARM.exidx*)
+ }
+}
+
+# RUN: ld.lld %t.o -o %t --script %s
+
+## Check we do not crash and do not set SHF_LINK_ORDER flag for .foo
+# RUN: llvm-readobj -s %t | FileCheck %s
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_ARM_EXIDX
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
diff --git a/test/ELF/linkerscript/empty-load.s b/test/ELF/linkerscript/empty-load.s
index ea58d71402d1..a2b7d8227f60 100644
--- a/test/ELF/linkerscript/empty-load.s
+++ b/test/ELF/linkerscript/empty-load.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) } }" > %t.script
+# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) } }" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
diff --git a/test/ELF/linkerscript/empty-section-size.test b/test/ELF/linkerscript/empty-section-size.test
new file mode 100644
index 000000000000..665ddf1ddf01
--- /dev/null
+++ b/test/ELF/linkerscript/empty-section-size.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t1
+# RUN: llvm-readobj -symbols %t1 | FileCheck %s
+
+## We had a bug when LLD increased the size of the output section even
+## if it was empty. That happened because of empty synthetic sections included.
+## Here we check that size of empty output section is zero.
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x0
+
+SECTIONS {
+ . = 0x1000;
+ .bss : { *(.bss*) *(COMMON) }
+ foo = SIZEOF(.bss);
+}
diff --git a/test/ELF/linkerscript/empty-sections-expressions.s b/test/ELF/linkerscript/empty-sections-expressions.s
new file mode 100644
index 000000000000..3c9a9edf5786
--- /dev/null
+++ b/test/ELF/linkerscript/empty-sections-expressions.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+## We remove empty sections that do not reference symbols in address,
+## LMA, align and subalign expressions. Here we check that.
+
+# RUN: echo "SECTIONS { .debug_info 0 : { *(.debug_info) } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+# CHECK-NOT: .debug_info
+
+# RUN: echo "SECTIONS { .debug_info foo : { *(.debug_info) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t.o
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=SEC
+# SEC: .debug_info
+
+.globl foo
+foo:
diff --git a/test/ELF/linkerscript/empty-synthetic-removed-flags.s b/test/ELF/linkerscript/empty-synthetic-removed-flags.s
new file mode 100644
index 000000000000..54a8baba3bec
--- /dev/null
+++ b/test/ELF/linkerscript/empty-synthetic-removed-flags.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { *(.got.plt) BYTE(0x11) }}" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+## We have ".got.plt" synthetic section with SHF_ALLOC|SHF_WRITE flags.
+## It is empty, so linker removes it, but it has to keep ".got.plt" output
+## section because of the BYTE command. Here we check that the output section
+## still remembers what the flags of .got.plt are.
+
+# CHECK: Section {
+# CHECK: Index: 2
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+
+## Check flags are not the same if we omit empty synthetic section in script.
+# RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { BYTE(0x11) }}" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -s %t | FileCheck --check-prefix=EMPTY %s
+
+# EMPTY: Section {
+# EMPTY: Index: 2
+# EMPTY: Name: .bar
+# EMPTY-NEXT: Type: SHT_PROGBITS
+# EMPTY-NEXT: Flags [
+# EMPTY-NEXT: SHF_ALLOC
+# EMPTY-NEXT: SHF_EXECINSTR
+# EMPTY-NEXT: ]
+
+.section .foo,"ax"
+.quad 0
diff --git a/test/ELF/linkerscript/empty-tls.s b/test/ELF/linkerscript/empty-tls.s
deleted file mode 100644
index 919ccbffbe43..000000000000
--- a/test/ELF/linkerscript/empty-tls.s
+++ /dev/null
@@ -1,14 +0,0 @@
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: echo "PHDRS { ph_tls PT_TLS; }" > %t.script
-// RUN: ld.lld -o %t.so -T %t.script %t.o -shared
-// RUN: llvm-readobj -l %t.so | FileCheck %s
-
-// test that we don't crash with an empty PT_TLS
-
-// CHECK: Type: PT_TLS
-// CHECK-NEXT: Offset: 0x0
-// CHECK-NEXT: VirtualAddress: 0x0
-// CHECK-NEXT: PhysicalAddress: 0x0
-// CHECK-NEXT: FileSize: 0
-// CHECK-NEXT: MemSize: 0
diff --git a/test/ELF/linkerscript/empty-tls.test b/test/ELF/linkerscript/empty-tls.test
new file mode 100644
index 000000000000..2f473cb55f8c
--- /dev/null
+++ b/test/ELF/linkerscript/empty-tls.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t.so -T %s %t.o -shared
+# RUN: llvm-readobj -l %t.so | FileCheck %s
+
+PHDRS {
+ ph_tls PT_TLS;
+}
+
+# Test that we don't crash with an empty PT_TLS
+
+# CHECK: Type: PT_TLS
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x0
+# CHECK-NEXT: PhysicalAddress: 0x0
+# CHECK-NEXT: FileSize: 0
+# CHECK-NEXT: MemSize: 0
diff --git a/test/ELF/linkerscript/exidx-crash.s b/test/ELF/linkerscript/exidx-crash.s
deleted file mode 100644
index c29d0135414d..000000000000
--- a/test/ELF/linkerscript/exidx-crash.s
+++ /dev/null
@@ -1,7 +0,0 @@
-# REQUIRES: aarch64
-
-# We used to crash on this.
-
-# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
-# RUN: echo "SECTIONS { .ARM.exidx : { *(.foo) } }" > %t.script
-# RUN: ld.lld -T %t.script %t.o -o %t
diff --git a/test/ELF/linkerscript/exidx-crash.test b/test/ELF/linkerscript/exidx-crash.test
new file mode 100644
index 000000000000..4d765f4d3380
--- /dev/null
+++ b/test/ELF/linkerscript/exidx-crash.test
@@ -0,0 +1,10 @@
+# REQUIRES: aarch64
+
+# We used to crash on this.
+
+# RUN: llvm-mc /dev/null -o %t.o -filetype=obj -triple=aarch64-pc-linux
+# RUN: ld.lld -T %s %t.o -o %t
+
+SECTIONS {
+ .ARM.exidx : { *(.foo) }
+}
diff --git a/test/ELF/linkerscript/expr-invalid-sec.s b/test/ELF/linkerscript/expr-invalid-sec.s
deleted file mode 100644
index 5687751b6806..000000000000
--- a/test/ELF/linkerscript/expr-invalid-sec.s
+++ /dev/null
@@ -1,6 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { foo = ADDR(.text) + ADDR(.text); };" > %t.script
-# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s
-
-# CHECK: error: {{.*}}.script:1: at least one side of the expression must be absolute
diff --git a/test/ELF/linkerscript/expr-invalid-sec.test b/test/ELF/linkerscript/expr-invalid-sec.test
new file mode 100644
index 000000000000..946062a0c575
--- /dev/null
+++ b/test/ELF/linkerscript/expr-invalid-sec.test
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld -o %t.so --script %s %t.o -shared 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.test:8: at least one side of the expression must be absolute
+
+SECTIONS {
+ foo = ADDR(.text) + ADDR(.text);
+};
diff --git a/test/ELF/linkerscript/expr-sections.s b/test/ELF/linkerscript/expr-sections.s
deleted file mode 100644
index eb60009cd971..000000000000
--- a/test/ELF/linkerscript/expr-sections.s
+++ /dev/null
@@ -1,22 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { \
-# RUN: . = . + 4; \
-# RUN: .text : { \
-# RUN: *(.text) \
-# RUN: foo1 = ADDR(.text) + 1; bar1 = 1 + ADDR(.text); \
-# RUN: foo2 = ADDR(.text) & 1; bar2 = 1 & ADDR(.text); \
-# RUN: foo3 = ADDR(.text) | 1; bar3 = 1 | ADDR(.text); \
-# RUN: } \
-# RUN: };" > %t.script
-# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
-# RUN: llvm-objdump -t -h %t.so | FileCheck %s
-
-# CHECK: 1 .text 00000000 0000000000000004 TEXT DATA
-
-# CHECK: 0000000000000005 .text 00000000 foo1
-# CHECK: 0000000000000005 .text 00000000 bar1
-# CHECK: 0000000000000000 .text 00000000 foo2
-# CHECK: 0000000000000000 .text 00000000 bar2
-# CHECK: 0000000000000005 .text 00000000 foo3
-# CHECK: 0000000000000005 .text 00000000 bar3
diff --git a/test/ELF/linkerscript/expr-sections.test b/test/ELF/linkerscript/expr-sections.test
new file mode 100644
index 000000000000..1d16cc2239e9
--- /dev/null
+++ b/test/ELF/linkerscript/expr-sections.test
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o -shared
+# RUN: llvm-objdump -t -h %t.so | FileCheck %s
+
+SECTIONS {
+ . = . + 4;
+ .text : {
+ *(.text)
+ foo1 = ADDR(.text) + 1; bar1 = 1 + ADDR(.text);
+ foo2 = ADDR(.text) & 1; bar2 = 1 & ADDR(.text);
+ foo3 = ADDR(.text) | 1; bar3 = 1 | ADDR(.text);
+ }
+};
+
+# CHECK: 5 .text 00000000 000000000000014c
+
+# CHECK: 000000000000014d .text 00000000 foo1
+# CHECK: 000000000000014d .text 00000000 bar1
+# CHECK: 0000000000000000 .text 00000000 foo2
+# CHECK: 0000000000000000 .text 00000000 bar2
+# CHECK: 000000000000014d .text 00000000 foo3
+# CHECK: 000000000000014d .text 00000000 bar3
diff --git a/test/ELF/linkerscript/extend-pt-load.s b/test/ELF/linkerscript/extend-pt-load.s
deleted file mode 100644
index 72740f1092ee..000000000000
--- a/test/ELF/linkerscript/extend-pt-load.s
+++ /dev/null
@@ -1,68 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-
-# This test demonstrates an odd consequence of the way we handle sections with just symbol
-# assignments.
-
-# First, run a test with no such section.
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .dynsym : { } \
-# RUN: .hash : { } \
-# RUN: .dynstr : { } \
-# RUN: .text : { *(.text) } \
-# RUN: . = ALIGN(0x1000); \
-# RUN: .data.rel.ro : { *(.data.rel.ro) } \
-# RUN: }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t.o -shared
-# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck --check-prefix=CHECK1 %s
-
-# CHECK1: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
-# CHECK1-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
-
-# CHECK1: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E
-# CHECK1-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
-
-# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now
-# cover the padding bits created by ALIGN.
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .dynsym : { } \
-# RUN: .hash : { } \
-# RUN: .dynstr : { } \
-# RUN: .text : { *(.text) } \
-# RUN: bar : { . = ALIGN(0x1000); } \
-# RUN: .data.rel.ro : { *(.data.rel.ro) } \
-# RUN: }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t2 --script %t.script %t.o -shared
-# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck --check-prefix=CHECK2 %s
-
-# CHECK2: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
-# CHECK2-NEXT: bar NOBITS 00000000000001bd 0001bd 000e43 00 AX
-# CHECK2-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
-
-# CHECK2: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x001000 R E
-# CHECK2-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
-
-# If the current behavior becomes a problem we should consider just moving the commands out
-# of the section. That is, handle the above like the following test.
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .dynsym : { } \
-# RUN: .hash : { } \
-# RUN: .dynstr : { } \
-# RUN: .text : { *(.text) } \
-# RUN: . = ALIGN(0x1000); \
-# RUN: HIDDEN(bar_sym = .); \
-# RUN: .data.rel.ro : { *(.data.rel.ro) } \
-# RUN: }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t3 --script %t.script %t.o -shared
-# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK1 %s
-
-nop
-
-.section .data.rel.ro, "aw"
-.byte 0
diff --git a/test/ELF/linkerscript/extend-pt-load1.test b/test/ELF/linkerscript/extend-pt-load1.test
new file mode 100644
index 000000000000..a1359eace186
--- /dev/null
+++ b/test/ELF/linkerscript/extend-pt-load1.test
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o
+# RUN: ld.lld --hash-style=sysv -o %t1 --script %s %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck %s
+
+# This test demonstrates an odd consequence of the way we handle sections with just symbol
+# assignments.
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .dynsym : {}
+ .hash : {}
+ .dynstr : {}
+ .text : { *(.text) }
+ . = ALIGN(0x1000);
+ .data.rel.ro : { *(.data.rel.ro) }
+}
+
+# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
diff --git a/test/ELF/linkerscript/extend-pt-load2.test b/test/ELF/linkerscript/extend-pt-load2.test
new file mode 100644
index 000000000000..1aa943703f27
--- /dev/null
+++ b/test/ELF/linkerscript/extend-pt-load2.test
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o
+# RUN: ld.lld --hash-style=sysv -o %t2 --script %s %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s
+
+# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now
+# cover the padding bits created by ALIGN.
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .dynsym : {}
+ .hash : {}
+ .dynstr : {}
+ .text : { *(.text) }
+ bar : { . = ALIGN(0x1000); }
+ .data.rel.ro : { *(.data.rel.ro) }
+}
+
+# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK-NEXT: bar NOBITS 00000000000001bd 0001bd 000e43 00 AX
+# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x001000 R E
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
diff --git a/test/ELF/linkerscript/extend-pt-load3.test b/test/ELF/linkerscript/extend-pt-load3.test
new file mode 100644
index 000000000000..1b7ef6fdbf94
--- /dev/null
+++ b/test/ELF/linkerscript/extend-pt-load3.test
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o
+# RUN: ld.lld --hash-style=sysv -o %t3 --script %s %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK %s
+
+# If the current behavior becomes a problem we should consider just moving the commands out
+# of the section. That is, handle the above like the following test.
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .dynsym : {}
+ .hash : {}
+ .dynstr : {}
+ .text : { *(.text) }
+ . = ALIGN(0x1000);
+ HIDDEN(bar_sym = .);
+ .data.rel.ro : { *(.data.rel.ro) }
+}
+
+# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW \ No newline at end of file
diff --git a/test/ELF/linkerscript/filename-spec.s b/test/ELF/linkerscript/filename-spec.s
index 5f075a8e5005..66fd4178387c 100644
--- a/test/ELF/linkerscript/filename-spec.s
+++ b/test/ELF/linkerscript/filename-spec.s
@@ -1,55 +1,43 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
-# RUN: %p/Inputs/filename-spec.s -o %tsecond.o
+# RUN: %p/Inputs/filename-spec.s -o %ty.o
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: KEEP(*first.o(.foo)) \
-# RUN: KEEP(*second.o(.foo)) } }" > %t1.script
-# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o
-# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s
-# FIRSTSECOND: Contents of section .foo:
-# FIRSTSECOND-NEXT: 01000000 00000000 11000000 00000000
+# RUN: echo "SECTIONS{.foo :{ KEEP(*x.o(.foo)) KEEP(*y.o(.foo)) }}" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tx.o %ty.o
+# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTY %s
+# FIRSTY: Contents of section .foo:
+# FIRSTY-NEXT: 01000000 00000000 11000000 00000000
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: KEEP(*second.o(.foo)) \
-# RUN: KEEP(*first.o(.foo)) } }" > %t2.script
-# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o
+# RUN: echo "SECTIONS{.foo :{ KEEP(*y.o(.foo)) KEEP(*x.o(.foo)) }}" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tx.o %ty.o
# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s
# SECONDFIRST: Contents of section .foo:
# SECONDFIRST-NEXT: 11000000 00000000 01000000 00000000
## Now the same tests but without KEEP. Checking that file name inside
## KEEP is parsed fine.
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: *first.o(.foo) \
-# RUN: *second.o(.foo) } }" > %t3.script
-# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o
-# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s
+# RUN: echo "SECTIONS{.foo :{ *x.o(.foo) *y.o(.foo) }}" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %tx.o %ty.o
+# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTY %s
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: *second.o(.foo) \
-# RUN: *first.o(.foo) } }" > %t4.script
-# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o
+# RUN: echo "SECTIONS{.foo :{ *y.o(.foo) *x.o(.foo) }}" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %tx.o %ty.o
# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o filename-spec1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %T/filename-spec1.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
-# RUN: %p/Inputs/filename-spec.s -o filename-spec2.o
+# RUN: %p/Inputs/filename-spec.s -o %T/filename-spec2.o
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: filename-spec2.o(.foo) \
-# RUN: filename-spec1.o(.foo) } }" > %t5.script
+# RUN: echo "SECTIONS{.foo :{ %T/filename-spec2.o(.foo) %T/filename-spec1.o(.foo) }}" > %t5.script
# RUN: ld.lld -o %t5 --script %t5.script \
-# RUN: filename-spec1.o filename-spec2.o
+# RUN: %T/filename-spec1.o %T/filename-spec2.o
# RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: filename-spec1.o(.foo) \
-# RUN: filename-spec2.o(.foo) } }" > %t6.script
+# RUN: echo "SECTIONS{.foo :{ %T/filename-spec1.o(.foo) %T/filename-spec2.o(.foo) }}" > %t6.script
# RUN: ld.lld -o %t6 --script %t6.script \
-# RUN: filename-spec1.o filename-spec2.o
-# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTSECOND %s
+# RUN: %T/filename-spec1.o %T/filename-spec2.o
+# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTY %s
# RUN: mkdir -p %t.testdir1 %t.testdir2
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.testdir1/filename-spec1.o
@@ -59,33 +47,25 @@
# RUN: llvm-ar rsc %t.testdir2/lib2.a %t.testdir2/filename-spec2.o
# Verify matching of archive library names.
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: *lib2*(.foo) \
-# RUN: *lib1*(.foo) } }" > %t7.script
+# RUN: echo "SECTIONS{.foo :{ *lib2*(.foo) *lib1*(.foo) }}" > %t7.script
# RUN: ld.lld -o %t7 --script %t7.script --whole-archive \
# RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a
# RUN: llvm-objdump -s %t7 | FileCheck --check-prefix=SECONDFIRST %s
# Verify matching directories.
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: *testdir2*(.foo) \
-# RUN: *testdir1*(.foo) } }" > %t8.script
+# RUN: echo "SECTIONS{.foo :{ *testdir2*(.foo) *testdir1*(.foo) }}" > %t8.script
# RUN: ld.lld -o %t8 --script %t8.script --whole-archive \
# RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a
# RUN: llvm-objdump -s %t8 | FileCheck --check-prefix=SECONDFIRST %s
# Verify matching of archive library names in KEEP.
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: KEEP(*lib2*(.foo)) \
-# RUN: KEEP(*lib1*(.foo)) } }" > %t9.script
+# RUN: echo "SECTIONS{.foo :{ KEEP(*lib2*(.foo)) KEEP(*lib1*(.foo)) }}" > %t9.script
# RUN: ld.lld -o %t9 --script %t9.script --whole-archive \
# RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a
# RUN: llvm-objdump -s %t9 | FileCheck --check-prefix=SECONDFIRST %s
# Verify matching directories in KEEP.
-# RUN: echo "SECTIONS { .foo : { \
-# RUN: KEEP(*testdir2*(.foo)) \
-# RUN: KEEP(*testdir1*(.foo)) } }" > %t10.script
+# RUN: echo "SECTIONS{.foo :{ KEEP(*testdir2*(.foo)) KEEP(*testdir1*(.foo)) }}" > %t10.script
# RUN: ld.lld -o %t10 --script %t10.script --whole-archive \
# RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a
# RUN: llvm-objdump -s %t10 | FileCheck --check-prefix=SECONDFIRST %s
diff --git a/test/ELF/linkerscript/fill.s b/test/ELF/linkerscript/fill.s
deleted file mode 100644
index 604506084a74..000000000000
--- a/test/ELF/linkerscript/fill.s
+++ /dev/null
@@ -1,31 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { \
-# RUN: .out : { \
-# RUN: FILL(0x11111111) \
-# RUN: . += 2; \
-# RUN: *(.aaa) \
-# RUN: . += 4; \
-# RUN: *(.bbb) \
-# RUN: . += 4; \
-# RUN: FILL(0x22222222); \
-# RUN: . += 4; \
-# RUN: } \
-# RUN: }; " > %t.script
-# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-objdump -s %t | FileCheck %s
-
-# CHECK: Contents of section .out:
-# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222
-
-.text
-.globl _start
-_start:
-
-.section .aaa, "a"
-.align 1
-.byte 0xAA
-
-.section .bbb, "a"
-.align 1
-.byte 0xBB
diff --git a/test/ELF/linkerscript/fill.test b/test/ELF/linkerscript/fill.test
new file mode 100644
index 000000000000..5bf295ec9c14
--- /dev/null
+++ b/test/ELF/linkerscript/fill.test
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/fill.s -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+SECTIONS {
+ .out : {
+ FILL(0x11111111)
+ . += 2;
+ *(.aaa)
+ . += 4;
+ *(.bbb)
+ . += 4;
+ FILL(0x22222222);
+ . += 4;
+ }
+}
+
+# CHECK: Contents of section .out:
+# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222
diff --git a/test/ELF/linkerscript/header-addr.s b/test/ELF/linkerscript/header-addr.test
index 70e6f674bafb..7994c0fc9653 100644
--- a/test/ELF/linkerscript/header-addr.s
+++ b/test/ELF/linkerscript/header-addr.test
@@ -1,13 +1,15 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "PHDRS {all PT_LOAD PHDRS;} \
-# RUN: SECTIONS { \
-# RUN: . = 0x2000 + SIZEOF_HEADERS; \
-# RUN: .text : {*(.text)} :all \
-# RUN: }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld --hash-style=sysv -o %t.so --script %s %t.o -shared
# RUN: llvm-readobj -program-headers %t.so | FileCheck %s
+PHDRS { all PT_LOAD PHDRS; }
+
+SECTIONS {
+ . = 0x2000 + SIZEOF_HEADERS;
+ .text : {*(.text)} :all
+}
+
# CHECK: ProgramHeaders [
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD
@@ -25,7 +27,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
-# RUN: ld.lld --hash-style=sysv -o %t2.so --script %t.script %t.o -shared -z max-page-size=0x2000
+# RUN: ld.lld --hash-style=sysv -o %t2.so --script %s %t.o -shared -z max-page-size=0x2000
# RUN: llvm-readobj -program-headers %t2.so \
# RUN: | FileCheck --check-prefix=MAXPAGE %s
diff --git a/test/ELF/linkerscript/header-phdr.s b/test/ELF/linkerscript/header-phdr.s
deleted file mode 100644
index 8c9097d8dfa5..000000000000
--- a/test/ELF/linkerscript/header-phdr.s
+++ /dev/null
@@ -1,13 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "PHDRS { foobar PT_LOAD FILEHDR PHDRS; } \
-# RUN: SECTIONS { . = 0x1000; .abc : { *(.zed) } : foobar }" > %t.script
-# RUN: ld.lld --script %t.script %t.o -o %t
-# RUN: llvm-readelf -l -S -W %t | FileCheck %s
-
-.section .zed, "a"
-.zero 4
-
-
-# CHECK: [ 1] .abc PROGBITS 0000000000001000 001000 000004 00 A 0 0 1
-# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001004 0x001004 R E 0x1000
diff --git a/test/ELF/linkerscript/header-phdr.test b/test/ELF/linkerscript/header-phdr.test
new file mode 100644
index 000000000000..72be15b88a94
--- /dev/null
+++ b/test/ELF/linkerscript/header-phdr.test
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: echo '.section .zed, "a"; .zero 4' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld --script %s %t.o -o %t
+# RUN: llvm-readelf -l -S -W %t | FileCheck %s
+
+# CHECK: [ 1] .abc PROGBITS 0000000000001000 001000 000004 00 A 0 0 1
+# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001004 0x001004 R E 0x1000
+
+PHDRS { foobar PT_LOAD FILEHDR PHDRS; }
+
+SECTIONS {
+ . = 0x1000;
+ .abc : { *(.zed) } : foobar
+}
diff --git a/test/ELF/linkerscript/header-phdr2.s b/test/ELF/linkerscript/header-phdr2.s
new file mode 100644
index 000000000000..fbcd03ff6056
--- /dev/null
+++ b/test/ELF/linkerscript/header-phdr2.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS { foobar PT_LOAD FILEHDR PHDRS; }" > %t.script
+# RUN: echo "SECTIONS { .text : { *(.text) } : foobar }" >> %t.script
+# RUN: not ld.lld --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: could not allocate headers
+
+ .global _start
+_start:
+ retq
diff --git a/test/ELF/linkerscript/huge-temporary-file.s b/test/ELF/linkerscript/huge-temporary-file.s
index d58709cf8f8d..e30153c28857 100644
--- a/test/ELF/linkerscript/huge-temporary-file.s
+++ b/test/ELF/linkerscript/huge-temporary-file.s
@@ -3,7 +3,7 @@
# RUN: echo "SECTIONS { .text 0x2000 : {. = 0x10 ; *(.text) } }" > %t.script
# RUN: not ld.lld %t --script %t.script -o %t1
-## This inputs previously created a 4gb temporarily fine under 32 bit
+## This inputs previously created a 4gb temporarily file under 32 bit
## configuration. Issue was fixed. There is no clean way to check that from here.
## This testcase added for documentation purposes.
diff --git a/test/ELF/linkerscript/i386-sections-max-va-overflow.s b/test/ELF/linkerscript/i386-sections-max-va-overflow.s
new file mode 100644
index 000000000000..d424112a1ce4
--- /dev/null
+++ b/test/ELF/linkerscript/i386-sections-max-va-overflow.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { . = 0xfffffff1;" > %t.script
+# RUN: echo " .bar : { *(.bar*) } }" >> %t.script
+# RUN: not ld.lld -o /dev/null --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+## .bar section has data in [0xfffffff1, 0xfffffff1 + 0x10] == [0xffffff1, 0x1].
+## Check we can catch this overflow.
+# ERR: error: section .bar at 0xFFFFFFF1 of size 0x10 exceeds available address space
+
+.section .bar,"ax",@progbits
+.zero 0x10
diff --git a/test/ELF/linkerscript/implicit-program-header.s b/test/ELF/linkerscript/implicit-program-header.s
deleted file mode 100644
index 95cdf142fe42..000000000000
--- a/test/ELF/linkerscript/implicit-program-header.s
+++ /dev/null
@@ -1,13 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld --hash-style=sysv -o %t1 --script %S/Inputs/implicit-program-header.script \
-# RUN: %t.o -shared
-# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s
-
-# CHECK: Segment Sections...
-# CHECK-NEXT: 00 .text .dynsym .hash .dynstr .dynamic
-# CHECK-NEXT: 01 .foo
-
-.quad 0
-.section .foo,"ax"
-.quad 0
diff --git a/test/ELF/linkerscript/implicit-program-header.test b/test/ELF/linkerscript/implicit-program-header.test
new file mode 100644
index 000000000000..8a3a4c6684af
--- /dev/null
+++ b/test/ELF/linkerscript/implicit-program-header.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: echo '.section .text,"ax"; .quad 0' > %t.s
+# RUN: echo '.section .foo,"ax"; .quad 0' >> %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.s -o %t.o
+# RUN: ld.lld --hash-style=sysv -o %t1 --script %s %t.o -shared
+# RUN: llvm-readelf -l %t1 | FileCheck %s
+
+# CHECK: Segment Sections...
+# CHECK-NEXT: 00 .dynsym .hash .dynstr .bar .foo .text .dynamic
+# CHECK-NEXT: 01 .bar .foo
+
+PHDRS {
+ ph_write PT_LOAD FLAGS(2);
+ ph_exec PT_LOAD FLAGS(1);
+}
+
+SECTIONS {
+ .bar : { *(.bar) } : ph_exec
+ .foo : { *(.foo) }
+ .text : { *(.text) } : ph_write
+}
diff --git a/test/ELF/linkerscript/info-section-type.s b/test/ELF/linkerscript/info-section-type.s
new file mode 100644
index 000000000000..b718e828ab7d
--- /dev/null
+++ b/test/ELF/linkerscript/info-section-type.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+## In this test we check that output section types such as
+## COPY, INFO and OVERLAY marks output section as non-allocatable.
+
+# RUN: echo "SECTIONS { .bar : { *(.foo) } };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=DEFAULT
+# DEFAULT: Name: .bar
+# DEFAULT: Type: SHT_PROGBITS
+# DEFAULT-NEXT: Flags [
+# DEFAULT-NEXT: SHF_ALLOC
+# DEFAULT-NEXT: ]
+
+# RUN: echo "SECTIONS { .bar (COPY) : { *(.foo) } };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC
+# NONALLOC: Name: .bar
+# NONALLOC: Type: SHT_PROGBITS
+# NONALLOC-NEXT: Flags [
+# NONALLOC-NEXT: ]
+
+# RUN: echo "SECTIONS { .bar (INFO) : { *(.foo) } };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC
+
+# RUN: echo "SECTIONS { .bar (OVERLAY) : { *(.foo) } };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC
+
+.section .foo,"a",@progbits
+.zero 1
diff --git a/test/ELF/linkerscript/insert-after.test b/test/ELF/linkerscript/insert-after.test
new file mode 100644
index 000000000000..4260cd77f553
--- /dev/null
+++ b/test/ELF/linkerscript/insert-after.test
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/insert-after.s -o %t1.o
+
+## Main linker script contains .text and .data sections. Here
+## we check that can use INSERT AFTER to insert sections .foo.data
+## and .foo.text at the right places.
+
+SECTIONS {
+ .foo.data : { *(.foo.data) }
+} INSERT AFTER .data;
+
+SECTIONS {
+ .foo.text : { *(.foo.text) }
+} INSERT AFTER .text;
+
+# RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s
+# 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 .text 00000008 0000000000000000 TEXT
+# CHECK-NEXT: 2 .foo.text 00000008 0000000000000008 TEXT
+# CHECK-NEXT: 3 .data 00000008 0000000000000010 DATA
+# CHECK-NEXT: 4 .foo.data 00000008 0000000000000018 DATA
+
+# RUN: not ld.lld %t1.o -o %t1 --script %s 2>&1 \
+# RUN: | FileCheck %s --check-prefix=ERR
+# ERR-DAG: error: unable to INSERT AFTER/BEFORE .text: section not defined
+# ERR-DAG: error: unable to INSERT AFTER/BEFORE .data: section not defined
diff --git a/test/ELF/linkerscript/insert-before.test b/test/ELF/linkerscript/insert-before.test
new file mode 100644
index 000000000000..52317bef6ac0
--- /dev/null
+++ b/test/ELF/linkerscript/insert-before.test
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/insert-after.s -o %t1.o
+
+## Main linker script contains .text and .data sections. Here
+## we check that can use INSERT BEFORE to insert sections .foo.data
+## and .foo.text at the right places.
+
+SECTIONS {
+ .foo.data : { *(.foo.data) }
+} INSERT BEFORE .data;
+
+SECTIONS {
+ .foo.text : { *(.foo.text) }
+} INSERT BEFORE .text;
+
+# RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s
+# 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.text 00000008 0000000000000000 TEXT
+# CHECK-NEXT: 2 .text 00000008 0000000000000008 TEXT
+# CHECK-NEXT: 3 .foo.data 00000008 0000000000000010 DATA
+# CHECK-NEXT: 4 .data 00000008 0000000000000018 DATA
+
+# RUN: not ld.lld %t1.o -o %t1 --script %s 2>&1 \
+# RUN: | FileCheck %s --check-prefix=ERR
+# ERR-DAG: error: unable to INSERT AFTER/BEFORE .text: section not defined
+# ERR-DAG: error: unable to INSERT AFTER/BEFORE .data: section not defined
diff --git a/test/ELF/linkerscript/insert-broken.test b/test/ELF/linkerscript/insert-broken.test
new file mode 100644
index 000000000000..9a295623a2ca
--- /dev/null
+++ b/test/ELF/linkerscript/insert-broken.test
@@ -0,0 +1,6 @@
+SECTIONS {
+ .foo : { *(.bar) }
+} INSERT .data;
+
+# RUN: not ld.lld -o %t1 --script %s 2>&1 | FileCheck %s
+# CHECK: {{.*}}:3: expected AFTER/BEFORE, but got '.data'
diff --git a/test/ELF/linkerscript/lazy-symbols.s b/test/ELF/linkerscript/lazy-symbols.test
index 22dffeef979b..579df9323865 100644
--- a/test/ELF/linkerscript/lazy-symbols.s
+++ b/test/ELF/linkerscript/lazy-symbols.test
@@ -1,11 +1,12 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/lazy-symbols.s -o %t1
# RUN: llvm-ar rcs %tar %t1
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
-# RUN: echo "foo = 1;" > %t.script
-# RUN: ld.lld %t2 %tar --script %t.script -o %tout
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t2
+# RUN: ld.lld %t2 %tar --script %s -o %tout
# RUN: llvm-readobj -symbols %tout | FileCheck %s
+foo = 1;
+
# This test is to ensure a linker script can define a symbol which have the same
# name as a lazy symbol.
diff --git a/test/ELF/linkerscript/linker-script-in-search-path.s b/test/ELF/linkerscript/linker-script-in-search-path.s
index be83b55b8995..8f1802299de5 100644
--- a/test/ELF/linkerscript/linker-script-in-search-path.s
+++ b/test/ELF/linkerscript/linker-script-in-search-path.s
@@ -4,16 +4,16 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: mkdir -p %T/searchpath
-# RUN: echo "OUTPUT(\"%t.out\")" > %T/searchpath/foo.script
-# RUN: ld.lld -T%T/searchpath/foo.script %t.o
+# RUN: echo 'OUTPUT("%t.out")' > %T/searchpath/%basename_t.script
+# RUN: ld.lld -T%T/searchpath/%basename_t.script %t.o
# RUN: llvm-readobj %t.out | FileCheck %s
# CHECK: Format: ELF64-x86-64
# If the linker script specified with -T is missing we should emit an error
-# RUN: not ld.lld -Tfoo.script %t.o 2>&1 | FileCheck %s -check-prefix ERROR
-# ERROR: error: cannot find linker script foo.script
+# RUN: not ld.lld -T%basename_t.script %t.o 2>&1 | FileCheck %s -check-prefix ERROR
+# ERROR: error: cannot find linker script {{.*}}.script
# But if it exists in the search path we should fall back to that instead:
# RUN: rm %t.out
-# RUN: ld.lld -L %T/searchpath -Tfoo.script %t.o
+# RUN: ld.lld -L %T/searchpath -T%basename_t.script %t.o
# RUN: llvm-readobj %t.out | FileCheck %s
diff --git a/test/ELF/linkerscript/linkerscript.s b/test/ELF/linkerscript/linkerscript.s
index 6a239ea57c8d..39d2d4620a4f 100644
--- a/test/ELF/linkerscript/linkerscript.s
+++ b/test/ELF/linkerscript/linkerscript.s
@@ -17,32 +17,32 @@
# RUN: llvm-readobj %t.out > /dev/null
# RUN: echo "SEARCH_DIR(/lib/foo/blah)" > %t.script
-# RUN: ld.lld %t.script %t
+# RUN: ld.lld %t.script %t -o %t.out
# RUN: llvm-readobj %t.out > /dev/null
# RUN: echo ";SEARCH_DIR(x);SEARCH_DIR(y);" > %t.script
-# RUN: ld.lld %t.script %t
+# RUN: ld.lld %t.script %t -o %t.out
# RUN: llvm-readobj %t.out > /dev/null
# RUN: echo ";" > %t.script
-# RUN: ld.lld %t.script %t
+# RUN: ld.lld %t.script %t -o %t.out
# 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: ld.lld %t.script1 -o %t.out
# RUN: llvm-readobj %t2 > /dev/null
# RUN: echo "INCLUDE \"foo.script\"" > %t.script
# RUN: echo "OUTPUT(\"%t.out\")" > %T/foo.script
-# RUN: not ld.lld %t.script > %t.log 2>&1
+# RUN: not ld.lld %t.script -o %t.out > %t.log 2>&1
# RUN: FileCheck -check-prefix=INCLUDE_ERR %s < %t.log
# INCLUDE_ERR: error: {{.+}}.script:1: cannot find linker script foo.script
# INCLUDE_ERR-NEXT: INCLUDE "foo.script"
# RUN: ld.lld -L %T %t.script %t
# RUN: echo "FOO(BAR)" > %t.script
-# RUN: not ld.lld -o foo %t.script > %t.log 2>&1
+# RUN: not ld.lld -o %t.out %t.script > %t.log 2>&1
# RUN: FileCheck -check-prefix=ERR1 %s < %t.log
# ERR1: unknown directive: FOO
diff --git a/test/ELF/linkerscript/lma-overflow.test b/test/ELF/linkerscript/lma-overflow.test
new file mode 100644
index 000000000000..e572c05af344
--- /dev/null
+++ b/test/ELF/linkerscript/lma-overflow.test
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+
+# RUN: echo '.section .foo,"a"; .quad 1' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: not ld.lld -o %t %t.o --script %s 2>&1 | FileCheck %s
+# CHECK: error: section '.foo' will not fit in region 'flash': overflowed by 264 bytes
+
+MEMORY {
+ ram (rwx) : org = 0x1000, len = 0x300
+ flash (rwx) : org = 0x1000, len = 0x100
+}
+SECTIONS {
+ .foo : {
+ *(.foo)
+ . += 0x200;
+ } > ram AT>flash
+}
diff --git a/test/ELF/linkerscript/locationcountererr.s b/test/ELF/linkerscript/locationcountererr.s
deleted file mode 100644
index 113e102d4bc2..000000000000
--- a/test/ELF/linkerscript/locationcountererr.s
+++ /dev/null
@@ -1,11 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS {" > %t.script
-# RUN: echo ".text 0x2000 : {. = 0x10 ; *(.text) } }" >> %t.script
-# RUN: not ld.lld %t --script %t.script -o %t1 2>&1 | FileCheck %s
-# CHECK: {{.*}}.script:2: unable to move location counter backward for: .text
-
-.globl _start
-_start:
-nop
diff --git a/test/ELF/linkerscript/locationcountererr.test b/test/ELF/linkerscript/locationcountererr.test
new file mode 100644
index 000000000000..6a1b21319c5b
--- /dev/null
+++ b/test/ELF/linkerscript/locationcountererr.test
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t
+# RUN: not ld.lld %t --script %s -o %t1 2>&1 | FileCheck %s
+# CHECK: {{.*}}.test:8: unable to move location counter backward for: .text
+
+SECTIONS {
+ .text 0x2000 : {
+ . = 0x10;
+ *(.text)
+ }
+}
diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s
index 8968f6740ee4..9efe86a7283b 100644
--- a/test/ELF/linkerscript/locationcountererr2.s
+++ b/test/ELF/linkerscript/locationcountererr2.s
@@ -1,11 +1,11 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "SECTIONS {" > %t.script
-# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script
+# RUN: echo ". = 0x150; . = 0x10; .text : {} }" >> %t.script
# RUN: ld.lld %t.o --script %t.script -o %t -shared
# RUN: llvm-objdump -section-headers %t | FileCheck %s
-# CHECK: Idx Name Size Address
-# CHECK: 1 .text 00000000 0000000000000010
+# CHECK: Name Size Address
+# CHECK: .text 00000000 0000000000000010
# RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script
# RUN: ld.lld %t.o --script %t2.script -o %t -shared
diff --git a/test/ELF/linkerscript/map-file.test b/test/ELF/linkerscript/map-file.test
new file mode 100644
index 000000000000..540b8d494887
--- /dev/null
+++ b/test/ELF/linkerscript/map-file.test
@@ -0,0 +1,60 @@
+# REQUIRES: x86
+
+# RUN: echo '.quad sym3; .quad sym4; .section .foo.1, "a"; .quad 1' > %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o
+
+# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s
+# RUN: FileCheck -strict-whitespace %s < %t.map
+
+SECTIONS {
+ . = 0x1000;
+ .foo : {
+ BYTE(0x11)
+ SHORT(0x1122)
+ LONG(0x11223344)
+ QUAD(0x1122334455667788)
+ PROVIDE_HIDDEN(sym4 = .);
+ . += 0x1000;
+ *(.foo.1)
+ PROVIDE(unused1 = 0xff);
+ HIDDEN(sym6 = .);
+ . += 0x123 *
+ (1 + 1);
+ foo = .;
+ bar = 0x42 - 0x26;
+ }
+ sym1 = .;
+ . += 0x500;
+ sym2 = .;
+ PROVIDE(unused2 = 0xff);
+ PROVIDE(sym3 = 42);
+}
+
+# CHECK: VMA LMA Size Align Out In Symbol
+# CHECK-NEXT: 0 0 1000 1 . = 0x1000
+# CHECK-NEXT: 1000 1000 125d 1 .foo
+# CHECK-NEXT: 1000 1000 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1001 1001 2 1 SHORT ( 0x1122 )
+# CHECK-NEXT: 1003 1003 4 1 LONG ( 0x11223344 )
+# CHECK-NEXT: 1007 1007 8 1 QUAD ( 0x1122334455667788 )
+# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN ( sym4 = . )
+# CHECK-NEXT: 100f 100f 1000 1 . += 0x1000
+# CHECK-NEXT: 200f 200f 8 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1)
+# CHECK-NEXT: 2017 2017 0 1 HIDDEN ( sym6 = . )
+# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * ( 1 + 1 )
+# CHECK-NEXT: 225d 225d 0 1 foo = .
+# CHECK-NEXT: 225d 225d 0 1 bar = 0x42 - 0x26
+# CHECK-NEXT: 225d 0 0 1 sym1 = .
+# CHECK-NEXT: 225d 0 500 1 . += 0x500
+# CHECK-NEXT: 275d 0 0 1 sym2 = .
+# CHECK-NEXT: 275d 0 0 1 PROVIDE ( sym3 = 42 )
+# CHECK-NEXT: 2760 2760 10 4 .text
+# CHECK-NEXT: 2760 2760 10 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text)
+# CHECK-NEXT: 0 0 8 1 .comment
+# CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+# CHECK-NEXT: 0 0 c0 8 .symtab
+# CHECK-NEXT: 0 0 c0 8 <internal>:(.symtab)
+# CHECK-NEXT: 0 0 2f 1 .shstrtab
+# CHECK-NEXT: 0 0 2f 1 <internal>:(.shstrtab)
+# CHECK-NEXT: 0 0 22 1 .strtab
+# CHECK-NEXT: 0 0 22 1 <internal>:(.strtab)
diff --git a/test/ELF/linkerscript/map-file2.test b/test/ELF/linkerscript/map-file2.test
new file mode 100644
index 000000000000..d9ed339e228d
--- /dev/null
+++ b/test/ELF/linkerscript/map-file2.test
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file2.s -o %t.o
+# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s
+# RUN: FileCheck -strict-whitespace %s < %t.map
+
+SECTIONS {
+ . = 0x1000;
+ .aaa : { *(.aaa.*) }
+ .bbb : AT(0x2000) { *(.bbb.*) }
+ .ccc : AT(0x3000) { *(.ccc.*) }
+ .ddd : {
+ BYTE(0x11)
+ . += 0x100;
+ *(.ddd.*)
+ }
+ .text : { *(.text.*) }
+}
+
+# CHECK: VMA LMA Size Align Out In Symbol
+# CHECK-NEXT: 0 0 1000 1 . = 0x1000
+# CHECK-NEXT: 1000 1000 8 1 .aaa
+# CHECK-NEXT: 1000 1000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.aaa)
+# CHECK-NEXT: 1008 2000 8 1 .bbb
+# CHECK-NEXT: 1008 2000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.bbb)
+# CHECK-NEXT: 1010 3000 8 1 .ccc
+# CHECK-NEXT: 1010 3000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ccc)
+# CHECK-NEXT: 1018 3008 109 1 .ddd
+# CHECK-NEXT: 1018 3008 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1019 3009 100 1 . += 0x100
+# CHECK-NEXT: 1119 3109 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd)
+# CHECK-NEXT: 1128 3118 34 8 .eh_frame
+# CHECK-NEXT: 1128 3118 30 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.eh_frame+0x0)
+# CHECK-NEXT: 115c 314c 1 4 .text
+# CHECK-NEXT: 115c 314c 1 4 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.text)
+# CHECK-NEXT: 115c 314c 0 1 f(int)
+# CHECK-NEXT: 115c 314c 0 1 _start
+# CHECK-NEXT: 0 0 8 1 .comment
+# CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+# CHECK-NEXT: 0 0 48 8 .symtab
+# CHECK-NEXT: 0 0 48 8 <internal>:(.symtab)
+# CHECK-NEXT: 0 0 48 1 .shstrtab
+# CHECK-NEXT: 0 0 48 1 <internal>:(.shstrtab)
+# CHECK-NEXT: 0 0 e 1 .strtab
+# CHECK-NEXT: 0 0 e 1 <internal>:(.strtab)
diff --git a/test/ELF/linkerscript/memory-at.s b/test/ELF/linkerscript/memory-at.test
index 9e56dbdbd657..0f06a6620a79 100644
--- a/test/ELF/linkerscript/memory-at.s
+++ b/test/ELF/linkerscript/memory-at.test
@@ -1,16 +1,21 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "MEMORY { \
-# RUN: FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0x100 \
-# RUN: RAM (rwx) : ORIGIN = 0x2000, LENGTH = 0x100 } \
-# RUN: SECTIONS { \
-# RUN: .text : { *(.text*) } > FLASH \
-# RUN: __etext = .; \
-# RUN: .data : AT (__etext) { *(.data*) } > RAM \
-# RUN: }" > %t.script
-# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: echo '.section .text,"ax"; .quad 0' > %t.s
+# RUN: echo '.section .data,"aw"; .quad 0' >> %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t
+# RUN: ld.lld %t --script %s -o %t2
# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+MEMORY {
+ FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0x100
+ RAM (rwx) : ORIGIN = 0x2000, LENGTH = 0x100
+}
+
+SECTIONS {
+ .text : { *(.text*) } > FLASH
+ __etext = .;
+ .data : AT (__etext) { *(.data*) } > RAM
+}
+
# CHECK: ProgramHeaders [
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD
@@ -38,9 +43,3 @@
# CHECK-NEXT: ]
# CHECK-NEXT: Alignment:
# CHECK-NEXT: }
-
-.section .text, "ax"
-.quad 0
-
-.section .data, "aw"
-.quad 0
diff --git a/test/ELF/linkerscript/memory-data-commands.test b/test/ELF/linkerscript/memory-data-commands.test
new file mode 100644
index 000000000000..2762ec9e985f
--- /dev/null
+++ b/test/ELF/linkerscript/memory-data-commands.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: echo ".section .foo,\"a\"" > %t.s
+# RUN: echo ".quad 1" >> %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o
+
+# RUN: not ld.lld -o %t %t.o --script %s 2>&1 | FileCheck %s
+
+# Check we are able to catch 'ram' overflow caused by BYTE command.
+# CHECK: error: section '.foo' will not fit in region 'ram': overflowed by 1 bytes
+
+MEMORY {
+ text (rwx): org = 0x0, len = 0x1000
+ ram (rwx): org = 0x1000, len = 8
+}
+SECTIONS {
+ .text : { *(.text) } > text
+ .foo : {
+ *(.foo)
+ BYTE(0x1)
+ } > ram
+}
diff --git a/test/ELF/linkerscript/memory-loc-counter.test b/test/ELF/linkerscript/memory-loc-counter.test
new file mode 100644
index 000000000000..3ca9a2cf6caa
--- /dev/null
+++ b/test/ELF/linkerscript/memory-loc-counter.test
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+
+# RUN: echo ".section .foo,\"a\"" > %t.s
+# RUN: echo ".quad 1" >> %t.s
+# RUN: echo ".section .bar,\"a\"" >> %t.s
+# RUN: echo ".quad 1" >> %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o
+
+# RUN: ld.lld -o %t %t.o --script %s
+# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s
+
+## Check that we can produce output without errors,
+## and .foo section has proper size.
+# CHECK: Section Headers:
+# CHECK-NEXT: [Nr] Name Type Address Off Size
+# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000
+# CHECK-NEXT: [ 1] .foo PROGBITS 0000000000001000 001000 000108
+# CHECK-NEXT: [ 2] .bar PROGBITS 0000000000001108 001108 000008
+
+## Check that load address is correct.
+# CHECK: Program Headers:
+# CHECK-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000002000 0x000110 0x000110
+
+MEMORY {
+ ram (rwx) : org = 0x1000, len = 0x200
+ flash (rwx) : org = 0x2000, len = 0x200
+}
+SECTIONS {
+ .foo : {
+ *(.foo)
+ . += 0x100;
+ } > ram AT>flash
+ .bar : {
+ *(.bar)
+ } > ram AT>flash
+}
diff --git a/test/ELF/linkerscript/memory-region-alignment.test b/test/ELF/linkerscript/memory-region-alignment.test
new file mode 100644
index 000000000000..ba9d4e3bab3f
--- /dev/null
+++ b/test/ELF/linkerscript/memory-region-alignment.test
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: echo '.section .foo,"a"; .quad 0; .section .zed,"M",@progbits,1; .byte 0' > %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o
+
+MEMORY {
+ ram (rwx): org = 0x1, len = 96K
+}
+
+SECTIONS {
+ .foo : ALIGN(8) {
+ *(.foo)
+ } > ram
+
+ .zed : {
+ *(.zed)
+ } > ram
+}
+
+# RUN: ld.lld %t.o -o %t --script %s
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x8
+# CHECK-NEXT: Offset: 0x1008
+# CHECK-NEXT: Size: 8
+
+# CHECK: Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x10
+# CHECK-NEXT: Offset: 0x1010
+# CHECK-NEXT: Size: 0
+
+# CHECK: Name: .zed
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x10
+# CHECK-NEXT: Offset: 0x1010
+# CHECK-NEXT: Size: 1
+
+# CHECK: Name: .comment
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: SHF_STRINGS
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x0
+# CHECK-NEXT: Offset: 0x1011
+# CHECK-NEXT: Size: 8
diff --git a/test/ELF/linkerscript/memory.s b/test/ELF/linkerscript/memory.s
index 172768394d30..0c171425b20a 100644
--- a/test/ELF/linkerscript/memory.s
+++ b/test/ELF/linkerscript/memory.s
@@ -11,7 +11,7 @@
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAM %s
-# RAM: 1 .text 00000001 0000000000008000 TEXT DATA
+# RAM: 1 .text 00000001 0000000000008000 TEXT
# RAM-NEXT: 2 .data 00001000 0000000000008001 DATA
## Check RAM and ROM memory regions.
@@ -27,7 +27,7 @@
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAMROM %s
-# RAMROM: 1 .text 00000001 0000000080000000 TEXT DATA
+# RAMROM: 1 .text 00000001 0000000080000000 TEXT
# RAMROM-NEXT: 2 .data 00001000 0000000000000000 DATA
## Check memory region placement by attributes.
@@ -43,7 +43,7 @@
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=ATTRS %s
-# ATTRS: 1 .text 00000001 0000000080000000 TEXT DATA
+# ATTRS: 1 .text 00000001 0000000080000000 TEXT
# ATTRS: 2 .data 00001000 0000000000000000 DATA
## Check bad `ORIGIN`.
diff --git a/test/ELF/linkerscript/memory2.s b/test/ELF/linkerscript/memory2.s
index 2e7381fb8914..7f86ecec29b7 100644
--- a/test/ELF/linkerscript/memory2.s
+++ b/test/ELF/linkerscript/memory2.s
@@ -2,7 +2,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: echo "MEMORY { ram (rwx) : ORIGIN = 0, LENGTH = 2K } \
# RUN: SECTIONS { .text : { *(.text*) } > ram }" > %t.script
-# RUN: ld.lld -o %t2 --script %t.script %t
+# RUN: ld.lld -o /dev/null --script %t.script %t
.text
.global _start
diff --git a/test/ELF/linkerscript/memory4.test b/test/ELF/linkerscript/memory4.test
new file mode 100644
index 000000000000..e73d36085562
--- /dev/null
+++ b/test/ELF/linkerscript/memory4.test
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: echo ".section .text,\"ax\"; nop; .section .data,\"aw\"; nop;" \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+
+# CHECK: 1 .text 00000001 0000000000042000
+# CHECK-NEXT: 2 .data 00000001 0000000000042400
+
+## Test that address expressions changes the position in a memory region.
+
+MEMORY {
+ ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000
+}
+SECTIONS {
+ .text : { *(.text*) }
+ data_addr = ALIGN(1024);
+ .data data_addr : { *(.data*) }
+}
diff --git a/test/ELF/linkerscript/memory5.test b/test/ELF/linkerscript/memory5.test
new file mode 100644
index 000000000000..150ddf0e833c
--- /dev/null
+++ b/test/ELF/linkerscript/memory5.test
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: echo ".section .text,\"ax\"; nop; .section .data,\"aw\"; nop;" \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+
+# CHECK: 1 .text 00000001 0000000000042000
+# CHECK-NEXT: 2 .data 00000001 0000000000044001
+
+## Test that assign to Dot changes the position in a memory region.
+
+MEMORY {
+ ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000
+}
+SECTIONS {
+ .text : { *(.text*) }
+ . += 0x2000;
+ .data : { *(.data*) }
+}
diff --git a/test/ELF/linkerscript/merge-header-load.s b/test/ELF/linkerscript/merge-header-load.s
new file mode 100644
index 000000000000..5fb866abef85
--- /dev/null
+++ b/test/ELF/linkerscript/merge-header-load.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: . = 0xffffffff80000200; \
+# RUN: .text : AT (0x4200) { *(.text) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t.o --script %t.script -o %t
+# RUN: llvm-readelf -program-headers %t | FileCheck %s
+
+# Test that we put the header in the first PT_LOAD. We used to create a PT_LOAD
+# just for it and it would have a different virtual to physical address delta.
+
+# CHECK: Program Headers:
+# CHECK: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: PHDR 0x000040 0xffffffff80000040 0x0000000000004040
+# CHECK-NEXT: LOAD 0x000000 0xffffffff80000000 0x0000000000004000
+# CHECK-NOT: LOAD
+
+.global _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/merge-sections-syms.s b/test/ELF/linkerscript/merge-sections-syms.s
index 713d334a1a5a..421749b6f1b9 100644
--- a/test/ELF/linkerscript/merge-sections-syms.s
+++ b/test/ELF/linkerscript/merge-sections-syms.s
@@ -20,7 +20,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: A
-# CHECK-NEXT: Value: 0x195
+# CHECK-NEXT: Value: 0x226
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
@@ -29,7 +29,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: B
-# CHECK-NEXT: Value: 0x196
+# CHECK-NEXT: Value: 0x227
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s
index 2709bdaee444..8fb9e87d616a 100644
--- a/test/ELF/linkerscript/merge-sections.s
+++ b/test/ELF/linkerscript/merge-sections.s
@@ -28,8 +28,7 @@
# CHECK-NEXT: Value: 0x[[ADDR1]]
# CHECK: Name: end
-# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE
-# CHECK-NEXT: Value: 0x19E
+# CHECK-NEXT: Value: 0x236
# Check that we don't crash with --gc-sections
# RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared
diff --git a/test/ELF/linkerscript/no-pt-load.s b/test/ELF/linkerscript/no-pt-load.s
deleted file mode 100644
index c70402501391..000000000000
--- a/test/ELF/linkerscript/no-pt-load.s
+++ /dev/null
@@ -1,5 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "PHDRS {foo PT_DYNAMIC ;} " \
-# RUN: "SECTIONS { .text : { *(.text) } : foo }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t.o
diff --git a/test/ELF/linkerscript/no-pt-load.test b/test/ELF/linkerscript/no-pt-load.test
new file mode 100644
index 000000000000..16f7f4409984
--- /dev/null
+++ b/test/ELF/linkerscript/no-pt-load.test
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t1 --script %s %t.o
+
+## Check we do not crash.
+
+PHDRS { foo PT_DYNAMIC; }
+
+SECTIONS {
+ .text : { *(.text) } : foo
+}
diff --git a/test/ELF/linkerscript/no-space.s b/test/ELF/linkerscript/no-space.s
index 21a38e42b2a3..7232495a3fd4 100644
--- a/test/ELF/linkerscript/no-space.s
+++ b/test/ELF/linkerscript/no-space.s
@@ -1,13 +1,13 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS {foo 0 : {*(foo*)} }" > %t.script
+# RUN: echo "SECTIONS {foo 0 : {*(foo*)} .dynsym : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
-# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+# RUN: llvm-readelf -l %t | FileCheck %s
-# RUN: echo "SECTIONS {foo : {*(foo*)} }" > %t.script
+# RUN: echo "SECTIONS {foo : {*(foo*)} .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
-# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+# RUN: llvm-readelf -l %t | FileCheck %s
# There is not enough address space available for the header, so just start the PT_LOAD
# after it. Don't create a PT_PHDR as the header is not allocated.
@@ -18,7 +18,7 @@
# CHECK: Section to Segment mapping:
# CHECK-NEXT: Segment Sections...
-# CHECK-NEXT: 00 foo .text .dynsym .hash .dynstr
+# CHECK-NEXT: 00 foo .dynsym .dynstr .hash
.section foo, "a"
.quad 0
diff --git a/test/ELF/linkerscript/nobits-offset.s b/test/ELF/linkerscript/nobits-offset.s
new file mode 100644
index 000000000000..c4141487630b
--- /dev/null
+++ b/test/ELF/linkerscript/nobits-offset.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .sec1 (NOLOAD) : { . += 1; } \
+# RUN: .text : { *(.text) } \
+# RUN: };" > %t.script
+# RUN: ld.lld %t.o -T %t.script -o %t
+# RUN: llvm-readelf --sections %t | FileCheck %s
+
+# We used to misalign section offsets if the first section in a
+# PT_LOAD was SHT_NOBITS.
+
+# CHECK: [ 2] .text PROGBITS 0000000000000010 001010 000010 00 AX 0 0 16
+
+.global _start
+_start:
+ nop
+.p2align 4
diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s
index 28be55df1f12..bd49160d80bd 100644
--- a/test/ELF/linkerscript/noload.s
+++ b/test/ELF/linkerscript/noload.s
@@ -2,12 +2,13 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { \
# RUN: .data_noload_a (NOLOAD) : { *(.data_noload_a) } \
-# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script
+# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } \
+# RUN: .text (0x20000) : { *(.text) } };" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj --symbols -sections %t | FileCheck %s
+# RUN: llvm-readobj -sections -program-headers %t | FileCheck %s
# CHECK: Section {
-# CHECK: Index: 2
+# CHECK: Index: 1
# CHECK-NEXT: Name: .data_noload_a
# CHECK-NEXT: Type: SHT_NOBITS
# CHECK-NEXT: Flags [
@@ -15,7 +16,7 @@
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: Offset: 0xE8
# CHECK-NEXT: Size: 4096
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
@@ -23,7 +24,7 @@
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Index: 2
# CHECK-NEXT: Name: .data_noload_b
# CHECK-NEXT: Type: SHT_NOBITS
# CHECK-NEXT: Flags [
@@ -31,13 +32,29 @@
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x10000
-# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: Offset: 0xE8
# CHECK-NEXT: Size: 4096
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: }
+# CHECK: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x20000
+# CHECK-NEXT: PhysicalAddress: 0x20000
+# 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: }
+
+.section .text,"ax",@progbits
+ nop
.section .data_noload_a,"aw",@progbits
.zero 4096
diff --git a/test/ELF/linkerscript/non-absolute.s b/test/ELF/linkerscript/non-absolute.s
index a0e9e7dc6782..b4b25a7bbf84 100644
--- a/test/ELF/linkerscript/non-absolute.s
+++ b/test/ELF/linkerscript/non-absolute.s
@@ -5,9 +5,11 @@
# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DUMP
# RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SYMBOL
+# B = A + 0x1 = -0x10 + 0x1 = -0xf -> 0xFFFFFFFFFFFFFFF1
+# B - (0x94+6) = -0xf - (0x94+6) = -169
# DUMP: Disassembly of section .text:
# DUMP-NEXT: foo:
-# DUMP-NEXT: 0: {{.*}} -21(%rip), %eax
+# DUMP-NEXT: 94: {{.*}} -169(%rip), %eax
# SYMBOL: Symbol {
# SYMBOL: Name: B
@@ -18,7 +20,7 @@
# SYMBOL-NEXT: Other [
# SYMBOL-NEXT: STV_HIDDEN
# SYMBOL-NEXT: ]
-# SYMBOL-NEXT: Section: .text
+# SYMBOL-NEXT: Section: .dynsym
# SYMBOL-NEXT: }
.text
diff --git a/test/ELF/linkerscript/non-absolute2.s b/test/ELF/linkerscript/non-absolute2.s
deleted file mode 100644
index 97c34d31a912..000000000000
--- a/test/ELF/linkerscript/non-absolute2.s
+++ /dev/null
@@ -1,12 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
-# RUN: echo "SECTIONS { A = . + 0x1; . += 0x1000; }" > %t.script
-# RUN: ld.lld -shared %t1.o --script %t.script -o %t
-# RUN: llvm-objdump -section-headers -t %t | FileCheck %s
-
-# CHECK: Sections:
-# CHECK-NEXT: Idx Name Size Address
-# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000000 0000000000001000
-
-# CHECK: 0000000000000001 .text 00000000 A
diff --git a/test/ELF/linkerscript/non-absolute2.test b/test/ELF/linkerscript/non-absolute2.test
new file mode 100644
index 000000000000..b60666412b8a
--- /dev/null
+++ b/test/ELF/linkerscript/non-absolute2.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t1.o
+# RUN: ld.lld -shared %t1.o --script %s -o %t
+# RUN: llvm-objdump -section-headers -t %t | FileCheck %s
+
+SECTIONS {
+ A = . + 0x1;
+ . += 0x1000;
+}
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .dynsym 00000030 0000000000001000
+# CHECK: 5 .text 00000000 000000000000106c
+
+# CHECK: 0000000000000001 .dynsym 00000000 A
diff --git a/test/ELF/linkerscript/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s
index 229f028a16b2..d9984b3867d4 100644
--- a/test/ELF/linkerscript/non-alloc-segment.s
+++ b/test/ELF/linkerscript/non-alloc-segment.s
@@ -16,7 +16,7 @@
# RUN: .foo : {*(.foo)} :foo \
# RUN: }" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
+# RUN: llvm-readelf -s -l %t | FileCheck %s
# RUN: llvm-readobj -l %t | FileCheck --check-prefix=PHDR %s
# CHECK: Program Headers:
diff --git a/test/ELF/linkerscript/non-alloc.s b/test/ELF/linkerscript/non-alloc.s
index 3257cb965565..87f9afff8091 100644
--- a/test/ELF/linkerscript/non-alloc.s
+++ b/test/ELF/linkerscript/non-alloc.s
@@ -1,9 +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 %s -o %t.o
# RUN: echo "SECTIONS { .foo 0 : {*(foo)} }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared
-# RUN: llvm-readobj -elf-output-style=GNU -s -l %t1 | FileCheck %s
+# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
+# RUN: llvm-readelf -s -l %t | FileCheck %s
# Test that we create all necessary PT_LOAD. We use to stop at the first
# non-alloc, causing us to not create PT_LOAD for linker generated sections.
@@ -15,7 +15,7 @@
# CHECK: Section to Segment mapping:
# CHECK-NEXT: Segment Sections...
-# CHECK-NEXT: 00 .text .dynsym .hash .dynstr
+# CHECK-NEXT: 00 .dynsym .hash .dynstr .text
# CHECK-NEXT: 01 .dynamic
nop
diff --git a/test/ELF/linkerscript/numbers.s b/test/ELF/linkerscript/numbers.s
index d4fd13fd8197..98d7e3361343 100644
--- a/test/ELF/linkerscript/numbers.s
+++ b/test/ELF/linkerscript/numbers.s
@@ -29,12 +29,12 @@
## Mailformed number errors.
# RUN: echo "SECTIONS { . = 0x11h; }" > %t2.script
-# RUN: not ld.lld %t --script %t2.script -o %t3 2>&1 | \
+# RUN: not ld.lld %t --script %t2.script -o /dev/null 2>&1 | \
# RUN: FileCheck --check-prefix=ERR1 %s
# ERR1: malformed number: 0x11h
# RUN: echo "SECTIONS { . = 0x11k; }" > %t3.script
-# RUN: not ld.lld %t --script %t3.script -o %t4 2>&1 | \
+# RUN: not ld.lld %t --script %t3.script -o /dev/null 2>&1 | \
# RUN: FileCheck --check-prefix=ERR2 %s
# ERR2: malformed number: 0x11k
@@ -43,13 +43,28 @@
# RUN: FileCheck --check-prefix=ERR3 %s
# ERR3: malformed number: 0x11m
+# RUN: echo "SECTIONS { . = 1zh; }" > %t5.script
+# RUN: not ld.lld %t --script %t5.script -o %t5 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR4 %s
+# ERR4: malformed number: 1zh
+
+# RUN: echo "SECTIONS { . = 1zk; }" > %t6.script
+# RUN: not ld.lld %t --script %t6.script -o %t6 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR5 %s
+# ERR5: malformed number: 1zk
+
+# RUN: echo "SECTIONS { . = 1zm; }" > %t7.script
+# RUN: not ld.lld %t --script %t7.script -o /dev/null 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR6 %s
+# ERR6: malformed number: 1zm
+
## Make sure that numbers can be followed by a ":" with and without a space,
## e.g. "0x100 :" or "0x100:"
# RUN: echo "SECTIONS { \
# RUN: .hex1 0x400 : { *(.hex.1) } \
# RUN: .hex2 0x500:{ *(.hex.2) } \
-# RUN: }" > %t5.script
-# RUN: ld.lld %t --script %t5.script -o %t6
+# RUN: }" > %t8.script
+# RUN: ld.lld %t --script %t8.script -o %t6
# RUN: llvm-objdump -section-headers %t6 | FileCheck -check-prefix=SECADDR %s
# SECADDR: Sections:
# SECADDR-NEXT: Idx Name Size Address
diff --git a/test/ELF/linkerscript/openbsd-bootdata.s b/test/ELF/linkerscript/openbsd-bootdata.s
deleted file mode 100644
index 3e90574bb3a3..000000000000
--- a/test/ELF/linkerscript/openbsd-bootdata.s
+++ /dev/null
@@ -1,7 +0,0 @@
-# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
-# RUN: echo "PHDRS { boot PT_OPENBSD_BOOTDATA; }" > %t.script
-# RUN: ld.lld --script %t.script %t.o -o %t
-# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
-
-# CHECK: ProgramHeader {
-# CHECK: Type: PT_OPENBSD_BOOTDATA (0x65A41BE6)
diff --git a/test/ELF/linkerscript/openbsd-bootdata.test b/test/ELF/linkerscript/openbsd-bootdata.test
new file mode 100644
index 000000000000..6846c7f22f86
--- /dev/null
+++ b/test/ELF/linkerscript/openbsd-bootdata.test
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld --script %s %t.o -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
+
+PHDRS { boot PT_OPENBSD_BOOTDATA; }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_OPENBSD_BOOTDATA (0x65A41BE6)
diff --git a/test/ELF/linkerscript/openbsd-randomize.s b/test/ELF/linkerscript/openbsd-randomize.s
index bf885f423b02..575a6b25be78 100644
--- a/test/ELF/linkerscript/openbsd-randomize.s
+++ b/test/ELF/linkerscript/openbsd-randomize.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; rand PT_OPENBSD_RANDOMIZE; } \
# RUN: SECTIONS { . = SIZEOF_HEADERS; \
diff --git a/test/ELF/linkerscript/openbsd-wxneeded.s b/test/ELF/linkerscript/openbsd-wxneeded.test
index d371da9d8645..1868c0e08802 100644
--- a/test/ELF/linkerscript/openbsd-wxneeded.s
+++ b/test/ELF/linkerscript/openbsd-wxneeded.test
@@ -1,8 +1,10 @@
-# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
-# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; }" > %t.script
-# RUN: ld.lld -z wxneeded --script %t.script %t.o -o %t
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld -z wxneeded --script %s %t.o -o %t
# RUN: llvm-readobj --program-headers %t | FileCheck %s
+PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; }
+
# CHECK: ProgramHeader {
# CHECK: Type: PT_OPENBSD_WXNEEDED (0x65A3DBE7)
# CHECK-NEXT: Offset: 0x0
diff --git a/test/ELF/linkerscript/operators.s b/test/ELF/linkerscript/operators.test
index 494fc08c0f99..2be24dfc2fe3 100644
--- a/test/ELF/linkerscript/operators.s
+++ b/test/ELF/linkerscript/operators.test
@@ -1,42 +1,57 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo "SECTIONS { \
-# RUN: _start = .; \
-# RUN: plus = 1 + 2 + 3; \
-# RUN: minus = 5 - 1; \
-# RUN: div = 6 / 2; \
-# RUN: mul = 1 + 2 * 3; \
-# RUN: nospace = 1+2*6/3; \
-# RUN: braces = 1 + (2 + 3) * 4; \
-# RUN: and = 0xbb & 0xee; \
-# RUN: ternary1 = 1 ? 1 : 2; \
-# RUN: ternary2 = 0 ? 1 : 2; \
-# RUN: less = 1 < 0 ? 1 : 2; \
-# RUN: lesseq = 1 <= 1 ? 1 : 2; \
-# RUN: greater = 0 > 1 ? 1 : 2; \
-# RUN: greatereq = 1 >= 1 ? 1 : 2; \
-# RUN: eq = 1 == 1 ? 1 : 2; \
-# RUN: neq = 1 != 1 ? 1 : 2; \
-# RUN: plusassign = 1; \
-# RUN: plusassign += 2; \
-# RUN: unary = -1 + 3; \
-# RUN: lshift = 1 << 5; \
-# RUN: rshift = 0xff >> 3; \
-# RUN: maxpagesize = CONSTANT (MAXPAGESIZE); \
-# RUN: commonpagesize = CONSTANT (COMMONPAGESIZE); \
-# RUN: . = 0xfff0; \
-# RUN: datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0); \
-# RUN: datasegmentalign2 = DATA_SEGMENT_ALIGN (0, 0); \
-# RUN: _end = .; \
-# RUN: minus_rel = _end - 0x10; \
-# RUN: minus_abs = _end - _start; \
-# RUN: }" > %t.script
-# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t
+# RUN: ld.lld %t --script %s -o %t2
# RUN: llvm-objdump -t %t2 | FileCheck %s
+SECTIONS {
+ _start = .;
+ plus = 1 + 2 + 3;
+ minus = 5 - 1;
+ div = 6 / 2;
+ mod = 20 % 7;
+ mul = 1 + 2 * 3;
+ nospace = 1+2*6/3;
+ braces = 1 + (2 + 3) * 4;
+ and = 0xbb & 0xee;
+ ternary1 = 1 ? 1 : 2;
+ ternary2 = 0 ? 1 : 2;
+ less = 1 < 0 ? 1 : 2;
+ lesseq = 1 <= 1 ? 1 : 2;
+ greater = 0 > 1 ? 1 : 2;
+ greatereq = 1 >= 1 ? 1 : 2;
+ eq = 1 == 1 ? 1 : 2;
+ neq = 1 != 1 ? 1 : 2;
+ plusassign = 1;
+ plusassign += 2;
+ unary = -1 + 3;
+ lshift = 1 << 5;
+ rshift = 0xff >> 3;
+ precedence1 = 1 | 0xff & 1 << 1 + 1 * 2;
+ precedence2 = (1 | (0xff & (1 << (1 + (1 * 2)))));
+ maxpagesize = CONSTANT (MAXPAGESIZE);
+ commonpagesize = CONSTANT (COMMONPAGESIZE);
+ . = 0xfff0;
+ datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0);
+ datasegmentalign2 = DATA_SEGMENT_ALIGN (0, 0);
+ _end = .;
+ minus_rel = _end - 0x10;
+ minus_abs = _end - _start;
+ max = MAX(11, 22);
+ min = MIN(11, 22);
+ logicaland1 = 0 && 0;
+ logicaland2 = 0 && 1;
+ logicaland3 = 1 && 0;
+ logicaland4 = 1 && 1;
+ logicalor1 = 0 || 0;
+ logicalor2 = 0 || 1;
+ logicalor3 = 1 || 0;
+ logicalor4 = 1 || 1;
+}
+
# CHECK: 00000000000006 *ABS* 00000000 plus
# CHECK: 00000000000004 *ABS* 00000000 minus
# CHECK: 00000000000003 *ABS* 00000000 div
+# CHECK: 00000000000006 *ABS* 00000000 mod
# CHECK: 00000000000007 *ABS* 00000000 mul
# CHECK: 00000000000005 *ABS* 00000000 nospace
# CHECK: 00000000000015 *ABS* 00000000 braces
@@ -53,12 +68,24 @@
# CHECK: 00000000000002 *ABS* 00000000 unary
# CHECK: 00000000000020 *ABS* 00000000 lshift
# CHECK: 0000000000001f *ABS* 00000000 rshift
+# CHECK: 00000000000009 *ABS* 00000000 precedence1
+# CHECK: 00000000000009 *ABS* 00000000 precedence2
# CHECK: 00000000001000 *ABS* 00000000 maxpagesize
# CHECK: 00000000001000 *ABS* 00000000 commonpagesize
# CHECK: 0000000000ffff *ABS* 00000000 datasegmentalign
# CHECK: 0000000000fff0 *ABS* 00000000 datasegmentalign2
# CHECK: 0000000000ffe0 .text 00000000 minus_rel
# CHECK: 0000000000fff0 *ABS* 00000000 minus_abs
+# CHECK: 00000000000016 *ABS* 00000000 max
+# CHECK: 0000000000000b *ABS* 00000000 min
+# CHECK: 00000000000000 *ABS* 00000000 logicaland1
+# CHECK: 00000000000000 *ABS* 00000000 logicaland2
+# CHECK: 00000000000000 *ABS* 00000000 logicaland3
+# CHECK: 00000000000001 *ABS* 00000000 logicaland4
+# CHECK: 00000000000000 *ABS* 00000000 logicalor1
+# CHECK: 00000000000001 *ABS* 00000000 logicalor2
+# CHECK: 00000000000001 *ABS* 00000000 logicalor3
+# CHECK: 00000000000001 *ABS* 00000000 logicalor4
## Mailformed number error.
# RUN: echo "SECTIONS { . = 0x12Q41; }" > %t.script
@@ -88,14 +115,16 @@
# RUN: echo "SECTIONS { . = 1 / 0; }" > %t.script
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
# RUN: FileCheck --check-prefix=DIVZERO %s
-# DIVZERO: division by zero
+# DIVZERO: {{.*}}.script:1: division by zero
+
+## Mod by zero error.
+# RUN: echo "SECTIONS { . = 1 % 0; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=MODZERO %s
+# MODZERO: {{.*}}.script:1: modulo by zero
## Broken ternary operator expression.
# RUN: echo "SECTIONS { . = 1 ? 2; }" > %t.script
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
# RUN: FileCheck --check-prefix=TERNERR %s
# TERNERR: : expected, but got ;
-
-.globl _start
-_start:
-nop
diff --git a/test/ELF/linkerscript/orphan-first-cmd.s b/test/ELF/linkerscript/orphan-first-cmd.s
deleted file mode 100644
index 263cb30d6868..000000000000
--- a/test/ELF/linkerscript/orphan-first-cmd.s
+++ /dev/null
@@ -1,20 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { \
-# RUN: foo = 123; \
-# RUN: . = 0x1000; \
-# RUN: . = 0x2000; \
-# RUN: .bar : { *(.bar) } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t -T %t.script %t.o -shared
-# RUN: llvm-readobj -s %t | 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: 0x1000
-
-.section .bar, "aw"
diff --git a/test/ELF/linkerscript/orphan-first-cmd.test b/test/ELF/linkerscript/orphan-first-cmd.test
new file mode 100644
index 000000000000..84b183f96efb
--- /dev/null
+++ b/test/ELF/linkerscript/orphan-first-cmd.test
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: echo '.section .bar, "aw"' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld -o %t -T %s %t.o -shared
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+SECTIONS {
+ foo = 123;
+ . = 0x1000;
+ . = 0x2000;
+ .bar : { *(.bar) }
+}
+
+# CHECK: Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1070
diff --git a/test/ELF/linkerscript/orphan-phdrs.s b/test/ELF/linkerscript/orphan-phdrs.s
index 648911162e97..f9d1467b532a 100644
--- a/test/ELF/linkerscript/orphan-phdrs.s
+++ b/test/ELF/linkerscript/orphan-phdrs.s
@@ -10,7 +10,7 @@
# RUN: .rw : { *(.rw) } \
# RUN: }" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
+# RUN: llvm-readelf -s -l %t | FileCheck %s
## Check that the orphan section is placed correctly and belongs to
## the correct segment.
@@ -18,6 +18,7 @@
# CHECK: Section Headers
# CHECK: .text
# CHECK-NEXT: .orphan
+# CHECK-NEXT: .empty
# CHECK-NEXT: .rw
# CHECK: Segment Sections
diff --git a/test/ELF/linkerscript/orphan.s b/test/ELF/linkerscript/orphan.s
index f51085383a9e..4dbaf37c687e 100644
--- a/test/ELF/linkerscript/orphan.s
+++ b/test/ELF/linkerscript/orphan.s
@@ -13,7 +13,7 @@
## .bss is SHT_NOBITS section and should be last RW section, so some space
## in ELF file could be saved.
# CHECK: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT DATA
+# CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT
# CHECK-NEXT: 2 .rw1 00000008 0000000000000000 DATA
# CHECK-NEXT: 3 .rw2 00000008 0000000000000008 DATA
# CHECK-NEXT: 4 .rw3 00000008 0000000000000010 DATA
diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s
index c43df43e5002..da8c103bb47f 100644
--- a/test/ELF/linkerscript/out-of-order.s
+++ b/test/ELF/linkerscript/out-of-order.s
@@ -1,19 +1,37 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o
-# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script
+# RUN: echo "SECTIONS { .data 0x4000 : {*(.data)} .dynsym 0x2000 : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t.so --script %t.script %t.o -shared
# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# Note: how the layout is done:
+# we need to layout 2 segments, each contains sections:
+# seg1: .data .dynamic
+# seg2: .dynsym .dynstr .text .hash
+# for each segment, we start from the first section, regardless
+# whether it is an orphan or not (sections that are not listed in the
+# linkerscript are orphans):
+# for seg1, we assign address: .data(0x4000), .dynamic(0x4008)
+# for seg2, we assign address: .dynsym(0x2000), .dynstr(0x2018) ...
+# .dynsym is not an orphan, so we take address from script, we assign
+# .dynstr current address cursor, which is the end # of .dynsym and so
+# on for later sections.
+
+# Also note, it is absolutely *illegal* to have section addresses of
+# the same segment in none-increasing order, authors of linker scripts
+# must take responsibility to make sure this does not happen.
+
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA
+# CHECK-NEXT: 1 .data 00000008 0000000000004000
# CHECK-NEXT: 2 .dynamic 00000060 0000000000004008
-# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA
-# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008
-# CHECK-NEXT: 5 .hash 00000010 0000000000002020
-# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030
+# CHECK-NEXT: 3 .dynsym 00000018 0000000000002000
+# CHECK-NEXT: 4 .dynstr 00000001 0000000000002018
+# CHECK-NEXT: 5 .hash 00000010 000000000000201c
+# CHECK-NEXT: 6 .text 00000008 000000000000202c
.quad 0
.data
.quad 0
+
diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s
index c892a88a947e..ca85465036fe 100644
--- a/test/ELF/linkerscript/output-too-large.s
+++ b/test/ELF/linkerscript/output-too-large.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script
-# RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld --no-check-sections --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: output file too large
.global _start
diff --git a/test/ELF/linkerscript/outputarch.s b/test/ELF/linkerscript/outputarch.s
deleted file mode 100644
index dd3bf93611b4..000000000000
--- a/test/ELF/linkerscript/outputarch.s
+++ /dev/null
@@ -1,4 +0,0 @@
-# REQUIRES: x86
-# RUN: echo "OUTPUT_ARCH(All data written here is ignored)" > %t.script
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
-# RUN: ld.lld -shared -o %t2 %t1 %t.script
diff --git a/test/ELF/linkerscript/outputarch.test b/test/ELF/linkerscript/outputarch.test
new file mode 100644
index 000000000000..4819a983cfce
--- /dev/null
+++ b/test/ELF/linkerscript/outputarch.test
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd /dev/null -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %s
+
+OUTPUT_ARCH(All data written here is ignored)
diff --git a/test/ELF/linkerscript/overlapping-sections.s b/test/ELF/linkerscript/overlapping-sections.s
new file mode 100644
index 000000000000..818301fd2b0e
--- /dev/null
+++ b/test/ELF/linkerscript/overlapping-sections.s
@@ -0,0 +1,113 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \
+# RUN: .sec2 0x8800 : AT(0x8080) { sec2_start = .; *(.second_sec) sec2_end = .;} \
+# RUN: }" > %t-lma.script
+# RUN: not ld.lld -o %t.so --script %t-lma.script %t.o -shared 2>&1 | FileCheck %s -check-prefix LMA-OVERLAP-ERR
+# LMA-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2
+# LMA-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF]
+# LMA-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8080, 0x817F]
+
+# Check that we create the expected binary with --noinhibit-exec or --no-check-sections:
+# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --noinhibit-exec
+# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --no-check-sections -fatal-warnings
+# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --check-sections --no-check-sections -fatal-warnings
+
+# Verify that the .sec2 was indeed placed in a PT_LOAD where the PhysAddr
+# overlaps with where .sec1 is loaded:
+# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-LMA
+# BAD-LMA-LABEL: Section Headers:
+# BAD-LMA: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1
+# BAD-LMA: .sec2 PROGBITS 0000000000008800 002800 000100 00 WA 0 0 1
+# BAD-LMA-LABEL: Program Headers:
+# BAD-LMA-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# BAD-LMA-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000
+# BAD-LMA-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000
+# BAD-LMA-NEXT: LOAD 0x002800 0x0000000000008800 0x0000000000008080 0x000170 0x000170 RW 0x1000
+# BAD-LMA-LABEL: Section to Segment mapping:
+# BAD-LMA: 01 .sec1
+# BAD-LMA: 02 .sec2 .dynamic
+
+# Now try a script where the virtual memory addresses overlap but ensure that the
+# load addresses don't:
+# RUN: echo "SECTIONS { \
+# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \
+# RUN: .sec2 0x8020 : AT(0x8800) { sec2_start = .; *(.second_sec) sec2_end = .;} \
+# RUN: }" > %t-vaddr.script
+# RUN: not ld.lld -o %t.so --script %t-vaddr.script %t.o -shared 2>&1 | FileCheck %s -check-prefix VADDR-OVERLAP-ERR
+# VADDR-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2
+# VADDR-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF]
+# VADDR-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8020, 0x811F]
+
+# Check that the expected binary was created with --noinhibit-exec:
+# RUN: ld.lld -o %t.so --script %t-vaddr.script %t.o -shared --noinhibit-exec
+# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-VADDR
+# BAD-VADDR-LABEL: Section Headers:
+# BAD-VADDR: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1
+# BAD-VADDR: .sec2 PROGBITS 0000000000008020 003020 000100 00 WA 0 0 1
+# BAD-VADDR-LABEL: Program Headers:
+# BAD-VADDR-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# BAD-VADDR-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000
+# BAD-VADDR-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000
+# BAD-VADDR-NEXT: LOAD 0x003020 0x0000000000008020 0x0000000000008800 0x000170 0x000170 RW 0x1000
+# BAD-VADDR-LABEL: Section to Segment mapping:
+# BAD-VADDR: 01 .sec1
+# BAD-VADDR: 02 .sec2 .dynamic
+
+# Finally check the case where both LMA and vaddr overlap
+
+# RUN: echo "SECTIONS { \
+# RUN: .sec1 0x8000 : { sec1_start = .; *(.first_sec) sec1_end = .;} \
+# RUN: .sec2 0x8040 : { sec2_start = .; *(.second_sec) sec2_end = .;} \
+# RUN: }" > %t-both-overlap.script
+
+# RUN: not ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared 2>&1 | FileCheck %s -check-prefix BOTH-OVERLAP-ERR
+
+# BOTH-OVERLAP-ERR: error: section .sec1 file range overlaps with .sec2
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x2000, 0x20FF]
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x2040, 0x213F]
+# BOTH-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF]
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040, 0x813F]
+# BOTH-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF]
+# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040, 0x813F]
+
+# RUN: ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared --noinhibit-exec
+# Note: In case everything overlaps we create a binary with overlapping file
+# offsets. ld.bfd seems to place .sec1 to file offset 18000 and .sec2
+# at 18100 so that only virtual addr and LMA overlap
+# However, in order to create such a broken binary the user has to ignore a
+# fatal error by passing --noinhibit-exec, so this behaviour is fine.
+
+# RUN: llvm-objdump -s %t.so | FileCheck %s -check-prefix BROKEN-OUTPUT-FILE
+# BROKEN-OUTPUT-FILE-LABEL: Contents of section .sec1:
+# BROKEN-OUTPUT-FILE-NEXT: 8000 01010101 01010101 01010101 01010101
+# BROKEN-OUTPUT-FILE-NEXT: 8010 01010101 01010101 01010101 01010101
+# BROKEN-OUTPUT-FILE-NEXT: 8020 01010101 01010101 01010101 01010101
+# BROKEN-OUTPUT-FILE-NEXT: 8030 01010101 01010101 01010101 01010101
+# Starting here the contents of .sec2 overwrites .sec1:
+# BROKEN-OUTPUT-FILE-NEXT: 8040 02020202 02020202 02020202 02020202
+
+# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-BOTH
+# BAD-BOTH-LABEL: Section Headers:
+# BAD-BOTH: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1
+# BAD-BOTH: .sec2 PROGBITS 0000000000008040 002040 000100 00 WA 0 0 1
+# BAD-BOTH-LABEL: Program Headers:
+# BAD-BOTH-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# BAD-BOTH-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000
+# BAD-BOTH-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x0001b0 0x0001b0 RW 0x1000
+# BAD-BOTH-LABEL: Section to Segment mapping:
+# BAD-BOTH: 01 .sec1 .sec2 .dynamic
+
+.section .first_sec,"aw",@progbits
+.rept 0x100
+.byte 1
+.endr
+
+.section .second_sec,"aw",@progbits
+.rept 0x100
+.byte 2
+.endr
diff --git a/test/ELF/linkerscript/overlay-reject.test b/test/ELF/linkerscript/overlay-reject.test
new file mode 100644
index 000000000000..fcb82b6df4b5
--- /dev/null
+++ b/test/ELF/linkerscript/overlay-reject.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}.test:{{.*}}: { expected, but got 0x3000
+# CHECK-NEXT: >>> .out.aaa 0x3000 : { *(.aaa) }
+# CHECK-NEXT: >>> ^
+
+SECTIONS {
+ OVERLAY 0x1000 : AT ( 0x2000 ) {
+ .out.aaa 0x3000 : { *(.aaa) }
+ }
+}
diff --git a/test/ELF/linkerscript/overlay-reject2.test b/test/ELF/linkerscript/overlay-reject2.test
new file mode 100644
index 000000000000..490533c5fa5e
--- /dev/null
+++ b/test/ELF/linkerscript/overlay-reject2.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}.test:{{.*}}: { expected, but got AX
+# CHECK-NEXT: >>> .out.aaa { *(.aaa) } > AX AT>FLASH
+# CHECK-NEXT: >>> ^
+
+MEMORY {
+ AX (ax) : ORIGIN = 0x3000, LENGTH = 0x4000
+}
+
+SECTIONS {
+ OVERLAY 0x1000 : AT ( 0x2000 ) {
+ .out.aaa { *(.aaa) } > AX AT>FLASH
+ }
+}
diff --git a/test/ELF/linkerscript/overlay.test b/test/ELF/linkerscript/overlay.test
new file mode 100644
index 000000000000..a28ab610ec09
--- /dev/null
+++ b/test/ELF/linkerscript/overlay.test
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: echo 'nop; .section .small, "a"; .long 0; .section .big, "a"; .quad 1;' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t
+
+SECTIONS {
+ OVERLAY 0x1000 : AT ( 0x4000 ) {
+ .out.big { *(.big) }
+ .out.small { *(.small) }
+ }
+}
+
+## Here we check that can handle OVERLAY which will produce sections
+## .out.big and .out.small with the same starting VAs, but different LMAs.
+## Section .big is larger than .small, we check that placing of section
+## .text does not cause overlapping error and that
+## .text's VA is 0x1000 + max(sizeof(.out.big), sizeof(.out.small)).
+
+# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t | FileCheck %s
+
+# CHECK: Section Headers:
+# CHECK: Name Type Address Off Size
+# CHECK: .out.big PROGBITS 0000000000001000 001000 000008
+# CHECK: .out.small PROGBITS 0000000000001000 002000 000004
+# CHECK: .text PROGBITS 0000000000001008 002008 000001
+
+# CHECK: Program Headers:
+# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000004000 0x000008 0x000008 R E 0x1000
+# CHECK-NEXT: LOAD 0x002000 0x0000000000001000 0x0000000000004008 0x000009 0x000009 R E 0x1000
diff --git a/test/ELF/linkerscript/page-size-align.s b/test/ELF/linkerscript/page-size-align.s
deleted file mode 100644
index 771bb13a8e6d..000000000000
--- a/test/ELF/linkerscript/page-size-align.s
+++ /dev/null
@@ -1,22 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .text : { *(.text) } \
-# RUN: . = ALIGN(CONSTANT(MAXPAGESIZE)); \
-# RUN: . = . + 0x3000; \
-# RUN: .dynamic : { *(.dynamic) } \
-# RUN: }" > %t.script
-
-# RUN: ld.lld -T %t.script -z max-page-size=0x4000 %t.o -o %t.so -shared
-# RUN: llvm-readobj -s %t.so | FileCheck %s
-
-# CHECK: Name: .dynamic
-# CHECK-NEXT: Type: SHT_DYNAMIC
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: SHF_ALLOC
-# CHECK-NEXT: SHF_WRITE
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x7000
-# CHECK-NEXT: Offset: 0x3000
diff --git a/test/ELF/linkerscript/page-size-align.test b/test/ELF/linkerscript/page-size-align.test
new file mode 100644
index 000000000000..f69413157426
--- /dev/null
+++ b/test/ELF/linkerscript/page-size-align.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -T %s -z max-page-size=0x4000 %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .text : { *(.text) }
+ . = ALIGN(CONSTANT(MAXPAGESIZE));
+ . = . + 0x3000;
+ .dynamic : { *(.dynamic) }
+}
+
+# CHECK: Name: .dynamic
+# CHECK-NEXT: Type: SHT_DYNAMIC
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x7000
+# CHECK-NEXT: Offset: 0x3000
diff --git a/test/ELF/linkerscript/parse-section-in-addr.test b/test/ELF/linkerscript/parse-section-in-addr.test
new file mode 100644
index 000000000000..6f42a6fe2788
--- /dev/null
+++ b/test/ELF/linkerscript/parse-section-in-addr.test
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t.so --script %s %t.o -shared
+# RUN: llvm-readelf -S %t.so | FileCheck %s
+
+SECTIONS {
+ .foo-bar : AT(ADDR(.foo-bar)) { *(.text) }
+}
+
+# CHECK: .foo-bar
diff --git a/test/ELF/linkerscript/provide-empty-section.s b/test/ELF/linkerscript/provide-empty-section.s
new file mode 100644
index 000000000000..56cb6aca1e3b
--- /dev/null
+++ b/test/ELF/linkerscript/provide-empty-section.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tundefined.o
+# RUN: echo "foo=42" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tdefined.o
+# RUN: echo "call foo" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %treference.o
+
+# RUN: echo "SECTIONS { .bar : { PROVIDE(foo = .); } }" > %t.script
+
+# Case 1: Provided symbol is undefined and not referenced - empty section should be removed.
+# RUN: ld.lld %tundefined.o -T %t.script -o %t1.elf
+# RUN: llvm-readobj -sections %t1.elf | FileCheck %s --check-prefix=NOSECTION
+
+# Case 2: Provided symbol is undefined and referenced - empty section should not be removed.
+# RUN: ld.lld %tundefined.o %treference.o -T %t.script -o %t2.elf
+# RUN: llvm-readobj -sections %t2.elf | FileCheck %s --check-prefix=SECTION
+
+# Case 3: Provided symbol is defined and not referenced - empty section should be removed.
+# RUN: ld.lld %tdefined.o -T %t.script -o %t3.elf
+# RUN: llvm-readobj -sections %t3.elf | FileCheck %s --check-prefix=NOSECTION
+
+# Case 4: Provided symbol is defined and referenced - empty section should not be removed.
+# RUN: ld.lld %tdefined.o %treference.o -T %t.script -o %t4.elf
+# RUN: llvm-readobj -sections %t4.elf | FileCheck %s --check-prefix=SECTION
+
+.global _start
+_start:
+ ret
+
+# SECTION: .bar
+# NOSECTION-NOT: .bar
diff --git a/test/ELF/linkerscript/provide-shared2.s b/test/ELF/linkerscript/provide-shared2.s
new file mode 100644
index 000000000000..8a3200b6f545
--- /dev/null
+++ b/test/ELF/linkerscript/provide-shared2.s
@@ -0,0 +1,13 @@
+# 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/provide-shared2.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: echo "SECTIONS { . = . + SIZEOF_HEADERS; PROVIDE(foo = 42); }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o %t2.so
+# RUN: llvm-readelf --dyn-symbols %t | FileCheck %s
+
+# CHECK: 1 1: 000000000000002a 0 NOTYPE GLOBAL DEFAULT ABS foo@
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/pt-interp.test b/test/ELF/linkerscript/pt-interp.test
new file mode 100644
index 000000000000..0441817aea6d
--- /dev/null
+++ b/test/ELF/linkerscript/pt-interp.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o
+# RUN: ld.lld -o %t.so -shared %t.o
+
+## Check we create PT_INTERP program header when it is specified in PHDRS.
+# RUN: echo "PHDRS { interp PT_INTERP; }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t.o %t.so --dynamic-linker foo
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+# CHECK: PT_INTERP
+
+## Check we do not create it if it is not specified,
+## but only if PHDRS is not empty by itself.
+# RUN: echo "PHDRS { ph_text PT_LOAD; }" > %t2.script
+# RUN: ld.lld -o %t1 --script %t2.script %t.o %t.so --dynamic-linker foo
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s --check-prefix=NOINTERP
+# NOINTERP-NOT: PT_INTERP
+
+## Otherwise, if PHDRS is empty, we create PT_INTERP header.
+# RUN: echo "PHDRS {}" > %t3.script
+# RUN: ld.lld -o %t1 --script %t3.script %t.o %t.so --dynamic-linker foo
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
diff --git a/test/ELF/linkerscript/pt_gnu_eh_frame.s b/test/ELF/linkerscript/pt_gnu_eh_frame.s
index 81b4c6307d4c..7f9ebaa8d8d1 100644
--- a/test/ELF/linkerscript/pt_gnu_eh_frame.s
+++ b/test/ELF/linkerscript/pt_gnu_eh_frame.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: echo "SECTIONS { /DISCARD/ : { *(.eh_frame*) *(.eh_frame_hdr*) } }" > %t.script
-# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: ld.lld -o /dev/null --eh-frame-hdr --script %t.script %t
.global _start
_start:
diff --git a/test/ELF/linkerscript/region-alias.s b/test/ELF/linkerscript/region-alias.s
index 8a88f6f5ad9f..af4a0f377ddd 100644
--- a/test/ELF/linkerscript/region-alias.s
+++ b/test/ELF/linkerscript/region-alias.s
@@ -15,7 +15,7 @@
# RUN: echo "REGION_ALIAS (\"ALIAS_DATA\", RAM);" >> %t.script.inc
# RUN: ld.lld %t --script %t.script -o %t2
# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
-# CHECK: .text 00000001 0000000000001000 TEXT DATA
+# CHECK: .text 00000001 0000000000001000 TEXT
# CHECK: .data 00000008 0000000000002000 DATA
## All to ROM.
@@ -23,7 +23,7 @@
# RUN: echo "REGION_ALIAS (\"ALIAS_DATA\", ROM);" >> %t.script.inc
# RUN: ld.lld %t --script %t.script -o %t2
# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=RAM
-# RAM: .text 00000001 0000000000001000 TEXT DATA
+# RAM: .text 00000001 0000000000001000 TEXT
# RAM: .data 00000008 0000000000001001 DATA
## Redefinition of region.
diff --git a/test/ELF/linkerscript/rosegment.s b/test/ELF/linkerscript/rosegment.test
index 3201b8bda9fb..41479e609d24 100644
--- a/test/ELF/linkerscript/rosegment.s
+++ b/test/ELF/linkerscript/rosegment.test
@@ -1,12 +1,14 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t
# Test that with linker scripts we don't create a RO PT_LOAD.
-# RUN: echo "SECTIONS {}" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: ld.lld -o %t1 --script %s %t -shared
# RUN: llvm-readobj -l %t1 | FileCheck %s
+SECTIONS {
+}
+
# CHECK-NOT: Type: PT_LOAD
# CHECK: Type: PT_LOAD
diff --git a/test/ELF/linkerscript/section-metadata.s b/test/ELF/linkerscript/section-metadata.s
index f447240ac3a9..44547b8ab002 100644
--- a/test/ELF/linkerscript/section-metadata.s
+++ b/test/ELF/linkerscript/section-metadata.s
@@ -10,15 +10,15 @@
# RUN: llvm-objdump -s %t | FileCheck --check-prefix=INV %s
-# CHECK: Contents of section .text:
-# CHECK-NEXT: 02000000 00000000 01000000 00000000
# CHECK: Contents of section .rodata:
# CHECK-NEXT: 02000000 00000000 01000000 00000000
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
-# INV: Contents of section .text:
-# INV-NEXT: 01000000 00000000 02000000 00000000
# INV: Contents of section .rodata:
# INV-NEXT: 01000000 00000000 02000000 00000000
+# INV: Contents of section .text:
+# INV-NEXT: 01000000 00000000 02000000 00000000
.global _start
_start:
diff --git a/test/ELF/linkerscript/section-metadata2.s b/test/ELF/linkerscript/section-metadata2.s
new file mode 100644
index 000000000000..4a538b6190e7
--- /dev/null
+++ b/test/ELF/linkerscript/section-metadata2.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text.*) } }" > %t.script
+
+# RUN: echo "_bar" > %t.ord
+# RUN: echo "_foo" >> %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK: Contents of section .rodata:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+
+# RUN: echo "_foo" > %t.ord
+# RUN: echo "_bar" >> %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=INV
+
+# INV: Contents of section .rodata:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+# INV: Contents of section .text:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+
+.section .text.foo,"a",@progbits
+_foo:
+.quad 1
+
+.section .text.bar,"a",@progbits
+_bar:
+.quad 2
+
+.section .rodata.foo,"ao",@progbits,.text.foo
+.quad 1
+
+.section .rodata.bar,"ao",@progbits,.text.bar
+.quad 2
diff --git a/test/ELF/linkerscript/sections-keep.s b/test/ELF/linkerscript/sections-keep.s
index feb0baca9c3d..2c778e3e936b 100644
--- a/test/ELF/linkerscript/sections-keep.s
+++ b/test/ELF/linkerscript/sections-keep.s
@@ -1,14 +1,14 @@
# REQUIRES: x86
-# 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/keep.s -o %t2.o
+# 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/keep.s -o %t1.o
## 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: ld.lld --gc-sections -o %t --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t | \
# RUN: FileCheck -check-prefix=SECGC %s
# SECGC: Sections:
# SECGC-NEXT: Idx Name Size
@@ -21,8 +21,8 @@
# 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: ld.lld --gc-sections -o %t --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t | \
# RUN: FileCheck -check-prefix=SECNOGC %s
# SECNOGC: Sections:
# SECNOGC-NEXT: Idx Name Size
@@ -38,14 +38,14 @@
# RUN: . = SIZEOF_HEADERS; \
# 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
+# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=MIXED1 %s
# MIXED1: Sections:
# MIXED1-NEXT: Idx Name Size
# MIXED1-NEXT: 0 00000000
# MIXED1-NEXT: 1 .keep 00000004
-# MIXED1-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA
-# MIXED1-NEXT: 3 .temp 00000004 00000000000000f3 DATA
+# MIXED1-NEXT: 2 .temp 00000004 00000000000000ec
+# MIXED1-NEXT: 3 .text 00000007 00000000000000f0
# MIXED1-NEXT: 4 .comment 00000008 0000000000000000
# MIXED1-NEXT: 5 .symtab 00000060 0000000000000000
# MIXED1-NEXT: 6 .shstrtab 00000036 0000000000000000
@@ -59,14 +59,14 @@
# RUN: . = SIZEOF_HEADERS; \
# 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
+# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=MIXED2 %s
# MIXED2: Sections:
# MIXED2-NEXT: Idx Name Size
# MIXED2-NEXT: 0 00000000
-# MIXED2-NEXT: 1 .nokeep 00000004 00000000000000e8 DATA
-# MIXED2-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA
-# MIXED2-NEXT: 3 .temp 00000004 00000000000000f3 DATA
+# MIXED2-NEXT: 1 .nokeep 00000004 00000000000000e8
+# MIXED2-NEXT: 2 .temp 00000004 00000000000000ec
+# MIXED2-NEXT: 3 .text 00000007 00000000000000f0
# MIXED2-NEXT: 4 .comment 00000008 0000000000000000
# MIXED2-NEXT: 5 .symtab 00000060 0000000000000000
# MIXED2-NEXT: 6 .shstrtab 00000038 0000000000000000
@@ -75,10 +75,10 @@
# Check file pattern for kept sections.
# RUN: echo "SECTIONS { \
# RUN: . = SIZEOF_HEADERS; \
-# RUN: .keep : { KEEP(*2.o(.keep)) } \
+# RUN: .keep : { KEEP(*1.o(.keep)) } \
# RUN: }" > %t.script
-# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t2.o %t
-# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=FILEMATCH %s
+# RUN: ld.lld --gc-sections -o %t --script %t.script %t1.o %t.o
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=FILEMATCH %s
# FILEMATCH: Contents of section .keep:
# FILEMATCH-NEXT: 00e8 41414141 AAAA
diff --git a/test/ELF/linkerscript/sections-max-va-overflow.s b/test/ELF/linkerscript/sections-max-va-overflow.s
new file mode 100644
index 000000000000..ce771b4784c4
--- /dev/null
+++ b/test/ELF/linkerscript/sections-max-va-overflow.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { . = 0xfffffffffffffff1;" > %t.script
+# RUN: echo " .bar : { *(.bar*) } }" >> %t.script
+# RUN: not ld.lld -o /dev/null --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+## .bar section has data in [0xfffffffffffffff1, 0xfffffffffffffff1 + 0x10] ==
+## [0xfffffffffffffff1, 0x1]. Check we can catch this overflow.
+# ERR: error: section .bar at 0xFFFFFFFFFFFFFFF1 of size 0x10 exceeds available address space
+
+.section .bar,"ax",@progbits
+.zero 0x10
diff --git a/test/ELF/linkerscript/sections-sort.s b/test/ELF/linkerscript/sections-sort.s
index 99bbbead925c..e665c9aaa74a 100644
--- a/test/ELF/linkerscript/sections-sort.s
+++ b/test/ELF/linkerscript/sections-sort.s
@@ -13,13 +13,13 @@ nop
.section foo, "a"
.byte 0
-# CHECK: Id
+# CHECK: Idx
# CHECK-NEXT: 0
# CHECK-NEXT: 1 .text
-# CHECK-NEXT: 2 foo
-# CHECK-NEXT: 3 .dynsym
-# CHECK-NEXT: 4 .hash
-# CHECK-NEXT: 5 .dynstr
+# CHECK-NEXT: 2 .dynsym
+# CHECK-NEXT: 3 .hash
+# CHECK-NEXT: 4 .dynstr
+# CHECK-NEXT: 5 foo
# CHECK-NEXT: 6 .dynamic
# CHECK-NEXT: 7 .comment
# CHECK-NEXT: 8 .symtab
diff --git a/test/ELF/linkerscript/sections-va-overflow.test b/test/ELF/linkerscript/sections-va-overflow.test
new file mode 100644
index 000000000000..7ede6ecc3de8
--- /dev/null
+++ b/test/ELF/linkerscript/sections-va-overflow.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/sections-va-overflow.s -o %t.o
+# RUN: not ld.lld -o /dev/null --script %s %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+PHDRS {
+ ph_headers PT_PHDR PHDRS;
+ ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4);
+}
+
+SECTIONS {
+ . = 0xffffffff20000000;
+ .text : { *(.text*) } : ph_text
+ .test 0x1000 : { BYTE(0) }
+ .bss : { *(.bss*) }
+}
+
+## Section .test has VA 0x1000 and placed in the same segment as section .text
+## with VA 0xffffffff20000000. That might be technically correct, but most probably
+## is a result of a broken script file and causes file offset calculation overflow.
+## It seems we do not have to support it, so we don't and we report an error in this case.
+# ERR: error: unable to place section .text at file offset [0xFFFFFFFF20000000, 0xFFFFFFFE40000000]; check your linker script for overflows
+# ERR-NOT: unable to place section .bss
diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s
index dd4b12f42b89..b1e8fb5e9a12 100644
--- a/test/ELF/linkerscript/sections.s
+++ b/test/ELF/linkerscript/sections.s
@@ -16,7 +16,7 @@
# RUN: FileCheck -check-prefix=SEC-DEFAULT %s
# Idx Name Size
-# SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT
# 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
@@ -47,7 +47,7 @@
# SEC-ORDER: 5 .strtab 00000008 {{[0-9a-f]*}}
# SEC-ORDER: 6 .comment 00000008 {{[0-9a-f]*}}
# SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT
# .text and .data have swapped names but proper sizes and types.
# RUN: echo "SECTIONS { \
@@ -58,7 +58,7 @@
# 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: 1 .data 0000000e {{[0-9a-f]*}} TEXT
# 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
@@ -80,7 +80,7 @@
# RUN: FileCheck -check-prefix=SEC-MULTI %s
# Idx Name Size
-# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT
# SEC-MULTI-NEXT: .data 00000020 {{[0-9a-f]*}} DATA
# SEC-MULTI-NEXT: .data 00000003 {{[0-9a-f]*}} DATA
# SEC-MULTI-NEXT: .bss 00000002 {{[0-9a-f]*}} BSS
diff --git a/test/ELF/linkerscript/segment-none.s b/test/ELF/linkerscript/segment-none.s
index d54e835a0c22..06566525caf7 100644
--- a/test/ELF/linkerscript/segment-none.s
+++ b/test/ELF/linkerscript/segment-none.s
@@ -9,7 +9,7 @@
# RUN: .foo : {*(.foo)} :NONE \
# RUN: }" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
+# RUN: llvm-readelf -s -l %t | FileCheck %s
## Test that section .foo is placed in segment NONE when assigned to segment
## NONE in the linker script and segment NONE is defined.
@@ -19,7 +19,7 @@
# RUN: .foo : {*(.foo)} :NONE \
# RUN: }" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck --check-prefix=DEFINED %s
+# RUN: llvm-readelf -s -l %t | FileCheck --check-prefix=DEFINED %s
# CHECK: Section to Segment mapping:
# CHECK-NEXT: Segment Sections...
diff --git a/test/ELF/linkerscript/segment-start.s b/test/ELF/linkerscript/segment-start.s
index 69897d604b3b..cb47cb6cd471 100644
--- a/test/ELF/linkerscript/segment-start.s
+++ b/test/ELF/linkerscript/segment-start.s
@@ -22,6 +22,6 @@
.quad foobar4
// RUN: echo "SECTIONS { . = SEGMENT_START(\"foobar\", foo); }" > %t.script
-// RUN: not ld.lld %t.o %t.script -shared -o %t2.so 2>&1 \
+// RUN: not ld.lld %t.o %t.script -shared -o /dev/null 2>&1 \
// RUN: | FileCheck --check-prefix=ERR %s
// ERR: {{.*}}.script:1: symbol not found: foo
diff --git a/test/ELF/linkerscript/sort-constructors.s b/test/ELF/linkerscript/sort-constructors.s
deleted file mode 100644
index a0c23af6de79..000000000000
--- a/test/ELF/linkerscript/sort-constructors.s
+++ /dev/null
@@ -1,5 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
-# RUN: echo "SECTIONS { .aaa : { SORT(CONSTRUCTORS) } }" > %t1.script
-# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
-# RUN: llvm-readobj %t1 > /dev/null
diff --git a/test/ELF/linkerscript/sort-constructors.test b/test/ELF/linkerscript/sort-constructors.test
new file mode 100644
index 000000000000..698208afd54e
--- /dev/null
+++ b/test/ELF/linkerscript/sort-constructors.test
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t1.o
+# RUN: ld.lld -shared -o %t1 --script %s %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
+
+SECTIONS {
+ .aaa : { SORT(CONSTRUCTORS) }
+}
diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s
index 4611b18d55ef..2477c835e134 100644
--- a/test/ELF/linkerscript/sort-non-script.s
+++ b/test/ELF/linkerscript/sort-non-script.s
@@ -1,14 +1,14 @@
# 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 %s -o %t.o
# RUN: echo "SECTIONS { foo : {*(foo)} }" > %t.script
-# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared
-# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
+# RUN: llvm-readelf -s %t | FileCheck %s
-# CHECK: .text {{.*}} AX
-# CHECK-NEXT: .dynsym {{.*}} A
+# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .hash {{.*}} A
# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: .text {{.*}} AX
# CHECK-NEXT: foo {{.*}} WA
# CHECK-NEXT: .dynamic {{.*}} WA
diff --git a/test/ELF/linkerscript/start-end.s b/test/ELF/linkerscript/start-end.s
deleted file mode 100644
index b68606abc181..000000000000
--- a/test/ELF/linkerscript/start-end.s
+++ /dev/null
@@ -1,16 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS { \
-# RUN: .init_array : { \
-# RUN: __init_array_start = .; \
-# RUN: *(.init_array) \
-# RUN: __init_array_end = .; } }" > %t.script
-# RUN: ld.lld %t.o -script %t.script -o %t 2>&1
-
-.globl _start
-.text
-_start:
- nop
-
-.section .init_array, "aw"
- .quad 0
diff --git a/test/ELF/linkerscript/start-end.test b/test/ELF/linkerscript/start-end.test
new file mode 100644
index 000000000000..ab7504dac2d4
--- /dev/null
+++ b/test/ELF/linkerscript/start-end.test
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: echo '.section .init_array, "aw"; .quad 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld %t.o -script %s -o %t 2>&1
+
+SECTIONS {
+ .init_array : {
+ __init_array_start = .;
+ *(.init_array)
+ __init_array_end = .;
+ }
+}
diff --git a/test/ELF/linkerscript/subalign.s b/test/ELF/linkerscript/subalign.s
index 1396798c82f6..99cb3f19a999 100644
--- a/test/ELF/linkerscript/subalign.s
+++ b/test/ELF/linkerscript/subalign.s
@@ -36,7 +36,7 @@
## Test we fail gracefuly when alignment value is not a power of 2.
# RUN: echo "SECTIONS { .aaa : SUBALIGN(3) { *(.aaa*) } }" > %t5.script
-# RUN: not ld.lld %t1.o --script %t5.script -o %t5 2>&1 | FileCheck -check-prefix=ERR %s
+# RUN: not ld.lld %t1.o --script %t5.script -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s
# ERR: {{.*}}.script:1: alignment must be power of 2
.global _start
diff --git a/test/ELF/linkerscript/symbol-assignexpr.s b/test/ELF/linkerscript/symbol-assignexpr.s
index 9ab03a173f1c..3be7d05931fe 100644
--- a/test/ELF/linkerscript/symbol-assignexpr.s
+++ b/test/ELF/linkerscript/symbol-assignexpr.s
@@ -47,7 +47,7 @@
# CHECK-NEXT: 0000000000000001 *ABS* 00000000 symbol15
# RUN: echo "SECTIONS { symbol2 = symbol; }" > %t2.script
-# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN: not ld.lld -o /dev/null --script %t2.script %t 2>&1 \
# RUN: | FileCheck -check-prefix=ERR %s
# ERR: {{.*}}.script:1: symbol not found: symbol
diff --git a/test/ELF/linkerscript/symbol-memoryexpr.s b/test/ELF/linkerscript/symbol-memoryexpr.s
index 9c75274e1644..cdd821dc585a 100644
--- a/test/ELF/linkerscript/symbol-memoryexpr.s
+++ b/test/ELF/linkerscript/symbol-memoryexpr.s
@@ -23,7 +23,7 @@
# RUN: no_exist_origin = ORIGIN(ram); \
# RUN: no_exist_length = LENGTH(ram); \
# RUN: }" > %t2.script
-# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN: not ld.lld -o /dev/null --script %t2.script %t 2>&1 \
# RUN: | FileCheck -check-prefix=ERR %s
# ERR: {{.*}}.script:1: memory region not defined: ram
diff --git a/test/ELF/linkerscript/symbol-only-flags.s b/test/ELF/linkerscript/symbol-only-flags.test
index 300d8d88da97..cea2539cd6ba 100644
--- a/test/ELF/linkerscript/symbol-only-flags.s
+++ b/test/ELF/linkerscript/symbol-only-flags.test
@@ -1,11 +1,15 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \
-# RUN: .tbss : { *(.tbss) } \
-# RUN: .foo : { bar = .; } }" > %t.script
-# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: echo '.section .tbss,"awT",@nobits; .quad 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o
+# RUN: ld.lld -o %t --script %s %t.o
# RUN: llvm-readobj -s %t | FileCheck %s
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .tbss : { *(.tbss) }
+ .foo : { bar = .; }
+}
+
## Check .foo does not get SHF_TLS flag.
# CHECK: Section {
# CHECK: Index:
@@ -15,6 +19,3 @@
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
-
-.section .tbss,"awT",@nobits
-.quad 0
diff --git a/test/ELF/linkerscript/symbol-only.s b/test/ELF/linkerscript/symbol-only.s
deleted file mode 100644
index 76d54f01cdc7..000000000000
--- a/test/ELF/linkerscript/symbol-only.s
+++ /dev/null
@@ -1,21 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: abc : { foo = .; } \
-# RUN: . = ALIGN(0x1000); \
-# RUN: bar : { *(bar) } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t -shared
-# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s
-# CHECK: Sections:
-# CHECK-NEXT: Idx Name Size Address
-# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] BSS
-# CHECK-NEXT: bar 00000000 0000000000001000 DATA
-
-# CHECK: SYMBOL TABLE:
-# CHECK: [[ADDR]] abc 00000000 foo
-
-.section bar, "a"
diff --git a/test/ELF/linkerscript/symbol-only.test b/test/ELF/linkerscript/symbol-only.test
new file mode 100644
index 000000000000..f2fefdc049b9
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-only.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: echo '.section bar, "a"' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t
+# RUN: ld.lld -o %t1 --script %s %t -shared
+# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ abc : { foo = .; }
+ . = ALIGN(0x1000);
+ bar : { *(bar) }
+}
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]]
+# CHECK: bar 00000000 0000000000001000
+
+# CHECK: SYMBOL TABLE:
+# CHECK: [[ADDR]] abc 00000000 foo
diff --git a/test/ELF/linkerscript/symbol-ordering-file.s b/test/ELF/linkerscript/symbol-ordering-file.s
index be686c420887..dd5e0a152ae9 100644
--- a/test/ELF/linkerscript/symbol-ordering-file.s
+++ b/test/ELF/linkerscript/symbol-ordering-file.s
@@ -14,6 +14,16 @@
# AFTER: Contents of section .foo:
# AFTER-NEXT: 2211
+# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t2.script
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t2.script -o %t3.out
+# RUN: llvm-objdump -s %t3.out| FileCheck %s --check-prefix=AFTER
+
+# RUN: echo "SECTIONS { .foo : { BYTE(0x33); *(.foo); BYTE(0x44) } }" > %t3.script
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t3.script -o %t4.out
+# RUN: llvm-objdump -s %t4.out| FileCheck %s --check-prefix=COMMANDS
+# COMMANDS: Contents of section .foo:
+# COMMANDS-NEXT: 33221144
+
.section .foo,"ax",@progbits,unique,1
_foo1:
.byte 0x11
diff --git a/test/ELF/linkerscript/symbol-ordering-file2.s b/test/ELF/linkerscript/symbol-ordering-file2.s
new file mode 100644
index 000000000000..31746ae0a333
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-ordering-file2.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+## Check we do not crash when trying to order linker script symbol.
+
+# RUN: echo "bar" > %t.ord
+# RUN: echo "SECTIONS { bar = 1; }" > %t.script
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t.script \
+# RUN: -o %t.out 2>&1 | FileCheck %s
+# CHECK: warning: <internal>: unable to order absolute symbol: bar
+
+## Check we do not crash when trying to order --defsym symbol.
+
+# RUN: echo "bar" > %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o -defsym=bar=1 \
+# RUN: -o %t.out 2>&1 | FileCheck %s
diff --git a/test/ELF/linkerscript/symbols-non-alloc.s b/test/ELF/linkerscript/symbols-non-alloc.s
deleted file mode 100644
index e51a39ee5d29..000000000000
--- a/test/ELF/linkerscript/symbols-non-alloc.s
+++ /dev/null
@@ -1,19 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \
-# RUN: .text : { *(.text) } \
-# RUN: .nonalloc : { *(.nonalloc) } \
-# RUN: Sym = .; \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t2 --script %t.script %t
-# RUN: llvm-objdump -section-headers -t %t2 | FileCheck %s
-
-# CHECK: Sections:
-# CHECK: .nonalloc 00000008 0000000000000000
-
-# CHECK: SYMBOL TABLE:
-# CHECK: 0000000000000008 .nonalloc 00000000 Sym
-
-.section .nonalloc,""
- .quad 0
diff --git a/test/ELF/linkerscript/symbols-non-alloc.test b/test/ELF/linkerscript/symbols-non-alloc.test
new file mode 100644
index 000000000000..6d7580affc26
--- /dev/null
+++ b/test/ELF/linkerscript/symbols-non-alloc.test
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: echo '.section .nonalloc,""; .quad 0' \
+# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t
+# RUN: ld.lld -o %t2 --script %s %t
+# RUN: llvm-objdump -section-headers -t %t2 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK: .nonalloc 00000008 0000000000000000
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0000000000000008 .nonalloc 00000000 Sym
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .text : { *(.text) }
+ .nonalloc : { *(.nonalloc) }
+ Sym = .;
+}
diff --git a/test/ELF/linkerscript/symbols-synthetic.s b/test/ELF/linkerscript/symbols-synthetic.s
deleted file mode 100644
index 95cdae9a929e..000000000000
--- a/test/ELF/linkerscript/symbols-synthetic.s
+++ /dev/null
@@ -1,98 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# Simple symbol assignment within input section list. The '.' symbol
-# is not location counter but offset from the beginning of output
-# section .foo
-# RUN: echo "SECTIONS { \
-# RUN: . = SIZEOF_HEADERS; \
-# RUN: .foo : { \
-# RUN: begin_foo = .; \
-# RUN: PROVIDE(_begin_sec = .); \
-# RUN: *(.foo) \
-# RUN: end_foo = .; \
-# RUN: PROVIDE_HIDDEN(_end_sec = .); \
-# RUN: PROVIDE(_end_sec_abs = ABSOLUTE(.)); \
-# RUN: size_foo_1 = SIZEOF(.foo); \
-# RUN: size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \
-# RUN: . = ALIGN(0x1000); \
-# RUN: begin_bar = .; \
-# RUN: *(.bar) \
-# RUN: end_bar = .; \
-# RUN: size_foo_2 = SIZEOF(.foo); } \
-# RUN: size_foo_3 = SIZEOF(.foo); \
-# RUN: .eh_frame_hdr : { \
-# RUN: __eh_frame_hdr_start = .; \
-# RUN: __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \
-# RUN: *(.eh_frame_hdr) \
-# RUN: __eh_frame_hdr_end = .; \
-# RUN: __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \
-# RUN: .eh_frame : { } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
-
-# Check that the following script is processed without errors
-# RUN: echo "SECTIONS { \
-# RUN: .eh_frame_hdr : { \
-# RUN: PROVIDE_HIDDEN(_begin_sec = .); \
-# RUN: *(.eh_frame_hdr) \
-# RUN: *(.eh_frame_hdr) \
-# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \
-# RUN: PROVIDE_HIDDEN(_end_sec = .); } \
-# RUN: }" > %t.script
-# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
-
-# Check that we can specify synthetic symbols without defining SECTIONS.
-# RUN: echo "PROVIDE_HIDDEN(_begin_sec = _start); \
-# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));" > %t.script
-# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=NO-SEC %s
-
-# Check that we can do the same as above inside SECTIONS block.
-# RUN: echo "SECTIONS { \
-# RUN: . = 0x201000; \
-# RUN: .text : { *(.text) } \
-# RUN: PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); \
-# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); }" > %t.script
-# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=IN-SEC %s
-
-# SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec
-# SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec
-# SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs
-# SIMPLE-NEXT: 0000000000001048 .text 00000000 _start
-# SIMPLE-NEXT: 0000000000000120 .foo 00000000 begin_foo
-# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo
-# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1
-# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs
-# SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar
-# SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar
-# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2
-# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3
-# SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start
-# SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2
-# SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end
-# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2
-
-# NO-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec
-# NO-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec
-
-# IN-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec
-# IN-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec
-
-.global _start
-_start:
- nop
-
-.section .foo,"a"
- .quad 0
-
-.section .bar,"a"
- .long 0
-
-.section .dah,"ax",@progbits
- .cfi_startproc
- nop
- .cfi_endproc
-
-.global _begin_sec, _end_sec, _end_sec_abs
diff --git a/test/ELF/linkerscript/synthetic-relsec-layout.s b/test/ELF/linkerscript/synthetic-relsec-layout.s
new file mode 100644
index 000000000000..efaa946cbaa9
--- /dev/null
+++ b/test/ELF/linkerscript/synthetic-relsec-layout.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .foo : { *(.rela.dyn) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.so -shared
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+# Check we are able to do custom layout for synthetic sections.
+# (here we check we can place synthetic .rela.dyn into .foo).
+
+# CHECK: Relocations [
+# CHECK: Section ({{.*}}) .foo {
+# CHECK: R_X86_64_64 .foo 0x0
+# CHECK: }
+
+.data
+.quad .foo
diff --git a/test/ELF/linkerscript/synthetic-symbols1.test b/test/ELF/linkerscript/synthetic-symbols1.test
new file mode 100644
index 000000000000..908a05f49588
--- /dev/null
+++ b/test/ELF/linkerscript/synthetic-symbols1.test
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t
+# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t
+# RUN: llvm-objdump -t %t.exe | FileCheck %s
+
+# Simple symbol assignment within input section list. The '.' symbol
+# is not location counter but offset from the beginning of output
+# section .foo
+
+SECTIONS {
+ . = SIZEOF_HEADERS;
+ .foo : {
+ begin_foo = .;
+ PROVIDE(_begin_sec = .);
+ *(.foo)
+ end_foo = .;
+ PROVIDE_HIDDEN(_end_sec = .);
+ PROVIDE(_end_sec_abs = ABSOLUTE(.));
+ size_foo_1 = SIZEOF(.foo);
+ size_foo_1_abs = ABSOLUTE(SIZEOF(.foo));
+ . = ALIGN(0x1000);
+ begin_bar = .;
+ *(.bar)
+ end_bar = .;
+ size_foo_2 = SIZEOF(.foo);
+ }
+
+ size_foo_3 = SIZEOF(.foo);
+
+ .eh_frame_hdr : {
+ __eh_frame_hdr_start = .;
+ __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10));
+ *(.eh_frame_hdr)
+ __eh_frame_hdr_end = .;
+ __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10));
+ }
+
+ .eh_frame : {}
+}
+
+# CHECK: 0000000000000128 .foo 00000000 .hidden _end_sec
+# CHECK-NEXT: 0000000000000120 .foo 00000000 _begin_sec
+# CHECK-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs
+# CHECK-NEXT: 000000000000104c .text 00000000 _start
+# CHECK-NEXT: 0000000000000120 .foo 00000000 begin_foo
+# CHECK-NEXT: 0000000000000128 .foo 00000000 end_foo
+# CHECK-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1
+# CHECK-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs
+# CHECK-NEXT: 0000000000001000 .foo 00000000 begin_bar
+# CHECK-NEXT: 0000000000001004 .foo 00000000 end_bar
+# CHECK-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2
+# CHECK-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3
+# CHECK-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start
+# CHECK-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2
+# CHECK-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end
+# CHECK-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2
diff --git a/test/ELF/linkerscript/synthetic-symbols2.test b/test/ELF/linkerscript/synthetic-symbols2.test
new file mode 100644
index 000000000000..5304c1e28f01
--- /dev/null
+++ b/test/ELF/linkerscript/synthetic-symbols2.test
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t
+# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t
+
+SECTIONS {
+ .eh_frame_hdr : {
+ PROVIDE_HIDDEN(_begin_sec = .);
+ *(.eh_frame_hdr)
+ *(.eh_frame_hdr)
+ PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.));
+ PROVIDE_HIDDEN(_end_sec = .);
+ }
+}
diff --git a/test/ELF/linkerscript/synthetic-symbols3.test b/test/ELF/linkerscript/synthetic-symbols3.test
new file mode 100644
index 000000000000..a24ecccedf0b
--- /dev/null
+++ b/test/ELF/linkerscript/synthetic-symbols3.test
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t
+# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t
+# RUN: llvm-objdump -t %t.exe | FileCheck %s
+
+# Check that we can specify synthetic symbols without defining SECTIONS.
+PROVIDE_HIDDEN(_begin_sec = _start);
+PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));
+
+# CHECK: 0000000000201000 .text 00000000 .hidden _begin_sec
+# CHECK-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec
diff --git a/test/ELF/linkerscript/synthetic-symbols4.test b/test/ELF/linkerscript/synthetic-symbols4.test
new file mode 100644
index 000000000000..fde06e3f3a44
--- /dev/null
+++ b/test/ELF/linkerscript/synthetic-symbols4.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t.o
+# RUN: ld.lld -o %t --eh-frame-hdr --script %s %t.o
+# RUN: llvm-objdump -t %t | FileCheck %s
+
+SECTIONS {
+ . = 0x201000;
+ .text : { *(.text) }
+ PROVIDE_HIDDEN(_begin_sec = ADDR(.text));
+ PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));
+}
+
+# CHECK: 0000000000201054 .text 00000000 .hidden _begin_sec
+# CHECK-NEXT: 0000000000201055 .text 00000000 .hidden _end_sec
diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s
index b7cedbc8e09c..6ddbf505ccbb 100644
--- a/test/ELF/linkerscript/unused-synthetic.s
+++ b/test/ELF/linkerscript/unused-synthetic.s
@@ -1,17 +1,17 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { \
-# RUN: .got : { *(.got) } \
+# RUN: .got : { *(.got) *(.got) } \
# RUN: .plt : { *(.plt) } \
# RUN: .text : { *(.text) } \
# RUN: }" > %t.script
# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
-# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# RUN: llvm-readelf -s %t.so | FileCheck %s
# CHECK-NOT: .got
# CHECK-NOT: .plt
+# CHECK: .dynsym
# CHECK: .text
-# CHECK-NEXT: .dynsym
# Test that the size of a removed unused synthetic input section is not added
# to the output section size. Adding a symbol assignment prevents removal of
diff --git a/test/ELF/linkerscript/unused-synthetic2.test b/test/ELF/linkerscript/unused-synthetic2.test
new file mode 100644
index 000000000000..755d1af00be0
--- /dev/null
+++ b/test/ELF/linkerscript/unused-synthetic2.test
@@ -0,0 +1,12 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux-gnueabi /dev/null -o %t.o
+
+## We incorrectly removed unused synthetic sections and crashed before.
+## Check we do not crash and do not produce .trap output section.
+# RUN: ld.lld -shared -o %t.so --script %s %t.o
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# CHECK-NOT: .trap
+
+SECTIONS {
+ .trap : { *(.ARM.exidx) *(.dummy) }
+}
diff --git a/test/ELF/linkerscript/va.s b/test/ELF/linkerscript/va.s
index 854ebcef0146..c305f0689e11 100644
--- a/test/ELF/linkerscript/va.s
+++ b/test/ELF/linkerscript/va.s
@@ -5,11 +5,11 @@
# 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: Idx Name Size Address
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000001 0000000000000000 TEXT DATA
-# CHECK-NEXT: 2 .foo 00000004 0000000000000001 DATA
-# CHECK-NEXT: 3 .boo 00000004 0000000000000005 DATA
+# CHECK-NEXT: 1 .foo 00000004 0000000000000000
+# CHECK-NEXT: 2 .boo 00000004 0000000000000004
+# CHECK-NEXT: 3 .text 00000001 0000000000000008
.global _start
_start:
diff --git a/test/ELF/linkerscript/version-script.s b/test/ELF/linkerscript/version-script.s
new file mode 100644
index 000000000000..df666e1b39ea
--- /dev/null
+++ b/test/ELF/linkerscript/version-script.s
@@ -0,0 +1,57 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "bar = foo; VERSION { V { global: foo; bar; local: *; }; }" > %t.script
+# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s
+
+# RUN: echo "SECTIONS { .text : { bar = foo; *(.text) } }" > %t.script
+# RUN: echo "VERSION { V { global: foo; bar; local: *; }; }" >> %t.script
+# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s
+
+## Check that we are able to version symbols defined in script.
+# CHECK: Symbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 0
+# CHECK-NEXT: Name: @
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 0
+# CHECK-NEXT: Name: und@
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 2
+# CHECK-NEXT: Name: foo@@V
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 2
+# CHECK-NEXT: Name: bar@@V
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# RUN: echo "bar = und; VERSION { V { global: foo; bar; local: *; }; }" > %t.script
+# RUN: not ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so \
+# RUN: 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: symbol not found: und
+
+# RUN: echo "und = 0x1; VERSION { V { global: und; local: *; }; }" > %t.script
+# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=UNDEF
+# UNDEF: Symbols [
+# UNDEF-NEXT: Symbol {
+# UNDEF-NEXT: Version: 0
+# UNDEF-NEXT: Name: @
+# UNDEF-NEXT: }
+# UNDEF-NEXT: Symbol {
+# UNDEF-NEXT: Version: 2
+# UNDEF-NEXT: Name: und@@V
+# UNDEF-NEXT: }
+# UNDEF-NEXT: ]
+
+.global und
+
+.text
+.globl foo
+.type foo,@function
+foo:
diff --git a/test/ELF/llvm33-rela-outside-group.s b/test/ELF/llvm33-rela-outside-group.s
index 8e7e7c4e6a4d..1c87817e0c75 100644
--- a/test/ELF/llvm33-rela-outside-group.s
+++ b/test/ELF/llvm33-rela-outside-group.s
@@ -1,7 +1,7 @@
// 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
+// RUN: ld.lld -shared %S/Inputs/llvm33-rela-outside-group.o %S/Inputs/llvm33-rela-outside-group.o -o /dev/null
.global bar
.weak _Z3fooIiEvv
diff --git a/test/ELF/local-dynamic.s b/test/ELF/local-dynamic.s
index 797a1071311c..c122074fd7d9 100644
--- a/test/ELF/local-dynamic.s
+++ b/test/ELF/local-dynamic.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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 {
diff --git a/test/ELF/local-got-pie.s b/test/ELF/local-got-pie.s
index b1b213af6659..c89fc1cb4ed4 100644
--- a/test/ELF/local-got-pie.s
+++ b/test/ELF/local-got-pie.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
// RUN: ld.lld --hash-style=sysv %t.o -o %t -pie
// RUN: llvm-readobj -s -r -d %t | FileCheck %s
diff --git a/test/ELF/local-got-shared.s b/test/ELF/local-got-shared.s
index c858424cfd96..284135db13e0 100644
--- a/test/ELF/local-got-shared.s
+++ b/test/ELF/local-got-shared.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
// RUN: ld.lld --hash-style=sysv %t.o -o %t -shared
// RUN: llvm-readobj -s -r -d %t | FileCheck %s
diff --git a/test/ELF/local-got.s b/test/ELF/local-got.s
index 17517f6a70ea..2c1bd58d7682 100644
--- a/test/ELF/local-got.s
+++ b/test/ELF/local-got.s
@@ -1,3 +1,4 @@
+// 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/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
diff --git a/test/ELF/local-symbols-order.s b/test/ELF/local-symbols-order.s
new file mode 100644
index 000000000000..dfd964f2de27
--- /dev/null
+++ b/test/ELF/local-symbols-order.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+
+# RUN: echo '.data; .file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs
+# RUN: llvm-readobj -symbols -sections -elf-output-style=GNU %t | FileCheck %s
+
+## Check we sort local symbols to match the following order:
+## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ...
+
+# CHECK: Section Headers:
+# CHECK: [Nr] Name
+# CHECK: [ [[ST:.*]]] .text
+# CHECK: [ [[SD:.*]]] .data
+# CHECK: [ [[SC:.*]]] .comment
+
+# CHECK: Num: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS file1
+# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo1
+# CHECK-NEXT: 3: 0000000000201000 0 SECTION LOCAL DEFAULT [[ST]]
+# CHECK-NEXT: 4: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1
+# CHECK-NEXT: 5: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2
+# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL DEFAULT 2 foo2
+# CHECK-NEXT: 7: 0000000000201000 0 SECTION LOCAL DEFAULT [[SD]]
+# CHECK-NEXT: 8: 0000000000201000 0 NOTYPE LOCAL HIDDEN 2 bar2
+# CHECK-NEXT: 9: 0000000000000000 0 SECTION LOCAL DEFAULT [[SC]]
+
+foo1:
+
+.global bar1
+.hidden bar1
+bar1:
+
+.file "file1"
diff --git a/test/ELF/local.s b/test/ELF/local.s
index 983d7ff7ba63..cb9adc864852 100644
--- a/test/ELF/local.s
+++ b/test/ELF/local.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// Check that symbol table is correctly populated with local symbols.
// RUN: llvm-mc -save-temp-labels -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 {
diff --git a/test/ELF/lto-plugin-ignore.s b/test/ELF/lto-plugin-ignore.s
index 2f45a43b2428..65230f1567e7 100644
--- a/test/ELF/lto-plugin-ignore.s
+++ b/test/ELF/lto-plugin-ignore.s
@@ -3,9 +3,8 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld %t -plugin-opt=/foo/bar -plugin-opt=-fresolution=zed \
# RUN: -plugin-opt=-pass-through=-lgcc -plugin-opt=-function-sections \
-# RUN: -plugin-opt=-data-sections -o /dev/null
+# RUN: -plugin-opt=-data-sections -plugin-opt=thinlto -o /dev/null
-# RUN: not ld.lld %t -plugin-opt=-data-sectionssss \
-# RUN: -plugin-opt=-function-sectionsss 2>&1 | FileCheck %s
-# CHECK: unknown option: -data-sectionsss
-# CHECK: unknown option: -function-sectionsss
+# RUN: not ld.lld %t -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s
+# CHECK: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-abc'
+# CHECK: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-xyz'
diff --git a/test/ELF/lto/Inputs/absolute.s b/test/ELF/lto/Inputs/absolute.s
new file mode 100644
index 000000000000..63fbc9f9234c
--- /dev/null
+++ b/test/ELF/lto/Inputs/absolute.s
@@ -0,0 +1,2 @@
+.globl blah
+ blah = 0xdeadbeef
diff --git a/test/ELF/lto/Inputs/archive-3.ll b/test/ELF/lto/Inputs/archive-3.ll
index ad8fb1e33ef2..37442469aa7e 100644
--- a/test/ELF/lto/Inputs/archive-3.ll
+++ b/test/ELF/lto/Inputs/archive-3.ll
@@ -1,5 +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 @foo() {
ret void
}
diff --git a/test/ELF/lto/Inputs/asmundef.ll b/test/ELF/lto/Inputs/asmundef.ll
new file mode 100644
index 000000000000..0992f79c9af8
--- /dev/null
+++ b/test/ELF/lto/Inputs/asmundef.ll
@@ -0,0 +1,4 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @patatino()
diff --git a/test/ELF/lto/Inputs/common3.ll b/test/ELF/lto/Inputs/common3.ll
index a4efc6591570..8f20a1e8ac2d 100644
--- a/test/ELF/lto/Inputs/common3.ll
+++ b/test/ELF/lto/Inputs/common3.ll
@@ -1,3 +1,4 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
+
@a = common hidden global i64 0, align 4
diff --git a/test/ELF/lto/Inputs/i386-empty.ll b/test/ELF/lto/Inputs/i386-empty.ll
new file mode 100644
index 000000000000..6029cb6d0900
--- /dev/null
+++ b/test/ELF/lto/Inputs/i386-empty.ll
@@ -0,0 +1,2 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "i686-linux-gnu"
diff --git a/test/ELF/lto/Inputs/lazy-internal.ll b/test/ELF/lto/Inputs/lazy-internal.ll
new file mode 100644
index 000000000000..918791c5d20f
--- /dev/null
+++ b/test/ELF/lto/Inputs/lazy-internal.ll
@@ -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 hidden void @bar() {
+ ret void
+}
diff --git a/test/ELF/lto/Inputs/sample-profile.prof b/test/ELF/lto/Inputs/sample-profile.prof
new file mode 100644
index 000000000000..0ccd747bd376
--- /dev/null
+++ b/test/ELF/lto/Inputs/sample-profile.prof
@@ -0,0 +1 @@
+f:0:0
diff --git a/test/ELF/lto/Inputs/thinlto_empty.ll b/test/ELF/lto/Inputs/thinlto_empty.ll
new file mode 100644
index 000000000000..a3c99cdfe772
--- /dev/null
+++ b/test/ELF/lto/Inputs/thinlto_empty.ll
@@ -0,0 +1,2 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/Inputs/weakodr-visibility.ll b/test/ELF/lto/Inputs/weakodr-visibility.ll
new file mode 100644
index 000000000000..1bd956059d24
--- /dev/null
+++ b/test/ELF/lto/Inputs/weakodr-visibility.ll
@@ -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 weak_odr protected i32 @foo(i8* %this) {
+ ret i32 42
+}
diff --git a/test/ELF/lto/abs-resol.ll b/test/ELF/lto/abs-resol.ll
new file mode 100644
index 000000000000..4b0fb47a9e21
--- /dev/null
+++ b/test/ELF/lto/abs-resol.ll
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/absolute.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t.o %t2.o -o %t3.out -pie
+
+; RUN: echo "blah = 0xdeadfeef;" > %t.script
+; RUN: ld.lld %t.o -T%t.script -o %t4.out -pie
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@blah = external global i8, align 1
+
+define i8* @_start() {
+ ret i8* @blah
+}
diff --git a/test/ELF/lto/archive-2.ll b/test/ELF/lto/archive-2.ll
index 6712d60c11e3..28e349ebd317 100644
--- a/test/ELF/lto/archive-2.ll
+++ b/test/ELF/lto/archive-2.ll
@@ -3,9 +3,9 @@
; 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: ld.lld %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: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared
; RUN: llvm-readobj -t %t3 | FileCheck %s
; CHECK: Name: _start (
diff --git a/test/ELF/lto/archive-3.ll b/test/ELF/lto/archive-3.ll
index 0322e412539a..fec1b6155238 100644
--- a/test/ELF/lto/archive-3.ll
+++ b/test/ELF/lto/archive-3.ll
@@ -2,12 +2,12 @@
; 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: ld.lld %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-dis %t3.0.2.internalize.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: ld.lld %t.a %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
; CHECK: define internal void @foo() {
diff --git a/test/ELF/lto/archive-no-index.ll b/test/ELF/lto/archive-no-index.ll
index 48cca0aa0794..5ac2628fefd8 100644
--- a/test/ELF/lto/archive-no-index.ll
+++ b/test/ELF/lto/archive-no-index.ll
@@ -11,8 +11,8 @@
; RUN: llvm-ar crS %t1.a %t2.o
; RUN: llvm-ar crs %t2.a %t2.o
-; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t1.a
-; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t2.a
+; RUN: ld.lld -o %t -emain %t1.o %t1.a
+; RUN: ld.lld -o %t -emain %t1.o %t2.a
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/archive.ll b/test/ELF/lto/archive.ll
index b4d011fdb888..6c4ca5e9aaaa 100644
--- a/test/ELF/lto/archive.ll
+++ b/test/ELF/lto/archive.ll
@@ -3,9 +3,9 @@
; 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: ld.lld %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: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared
; RUN: llvm-readobj -t %t3 | FileCheck %s
; CHECK: Name: g (
diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll
index d03a5e387213..604af8f9380b 100644
--- a/test/ELF/lto/asmundef.ll
+++ b/test/ELF/lto/asmundef.ll
@@ -1,6 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps
+; RUN: llvm-as %S/Inputs/asmundef.ll -o %t2.o
+; RUN: ld.lld %t.o %t2.o -o %t -save-temps
; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -20,5 +21,5 @@ define void @_start() {
ret void
}
-; CHECK: define void @foo
+; CHECK: define dso_local void @foo
diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll
index 315e710ec87c..516bec8c8a4e 100644
--- a/test/ELF/lto/available-externally.ll
+++ b/test/ELF/lto/available-externally.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; 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: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/bitcode-nodatalayout.ll b/test/ELF/lto/bitcode-nodatalayout.ll
index 5c4883a42444..c99cbb8550f0 100644
--- a/test/ELF/lto/bitcode-nodatalayout.ll
+++ b/test/ELF/lto/bitcode-nodatalayout.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: not ld.lld -m elf_x86_64 %t.o -o %t 2>&1 | FileCheck %s
+; RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
; CHECK: input module has no datalayout
diff --git a/test/ELF/lto/cache.ll b/test/ELF/lto/cache.ll
index 5ab74f5c5457..3f2bea9f2cdf 100644
--- a/test/ELF/lto/cache.ll
+++ b/test/ELF/lto/cache.ll
@@ -13,7 +13,7 @@
; RUN: ls %t.cache | count 4
; Create a file of size 64KB.
-; RUN: %python -c "print(' ' * 65536)" > %t.cache/llvmcache-foo
+; RUN: "%python" -c "print(' ' * 65536)" > %t.cache/llvmcache-foo
; This should leave the file in place.
; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k:prune_interval=0s -o %t3 %t2.o %t.o
diff --git a/test/ELF/lto/codemodel.ll b/test/ELF/lto/codemodel.ll
index cc126202f299..995575a9a0ab 100644
--- a/test/ELF/lto/codemodel.ll
+++ b/test/ELF/lto/codemodel.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %ts -mllvm -code-model=small
-; RUN: ld.lld -m elf_x86_64 %t.o -o %tl -mllvm -code-model=large
+; RUN: ld.lld %t.o -o %ts -mllvm -code-model=small
+; RUN: ld.lld %t.o -o %tl -mllvm -code-model=large
; RUN: llvm-objdump -d %ts | FileCheck %s --check-prefix=CHECK-SMALL
; RUN: llvm-objdump -d %tl | FileCheck %s --check-prefix=CHECK-LARGE
diff --git a/test/ELF/lto/combined-lto-object-name.ll b/test/ELF/lto/combined-lto-object-name.ll
index 76564f90c665..e0b98740e0f0 100644
--- a/test/ELF/lto/combined-lto-object-name.ll
+++ b/test/ELF/lto/combined-lto-object-name.ll
@@ -1,6 +1,6 @@
; 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
+; RUN: not ld.lld %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"
diff --git a/test/ELF/lto/comdat.ll b/test/ELF/lto/comdat.ll
index e1384d0abd23..1739351220cd 100644
--- a/test/ELF/lto/comdat.ll
+++ b/test/ELF/lto/comdat.ll
@@ -1,6 +1,6 @@
; 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: ld.lld %t.o %t.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
; CHECK: Name: foo
diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll
index 283182155ae6..e7c6ea10b5e2 100644
--- a/test/ELF/lto/comdat2.ll
+++ b/test/ELF/lto/comdat2.ll
@@ -1,9 +1,9 @@
; REQUIRES: x86
; 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: ld.lld %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: ld.lld %t2.o %t.o -o %t2.so -shared
; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER
diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll
index 2345a203b24c..1cb5c322ba05 100644
--- a/test/ELF/lto/common2.ll
+++ b/test/ELF/lto/common2.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
-; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps
+; RUN: ld.lld %t1.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED
diff --git a/test/ELF/lto/common3.ll b/test/ELF/lto/common3.ll
index aea33f443f4c..de52615e24f4 100644
--- a/test/ELF/lto/common3.ll
+++ b/test/ELF/lto/common3.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/cpu-string.ll b/test/ELF/lto/cpu-string.ll
new file mode 100644
index 000000000000..ff80dbb9a7b3
--- /dev/null
+++ b/test/ELF/lto/cpu-string.ll
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+
+; RUN: ld.lld %t.o -o %t.so -shared
+; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.so | FileCheck %s
+; CHECK: nop{{$}}
+
+; RUN: ld.lld -mllvm -mcpu=znver1 %t.o -o %t.znver1.so -shared
+; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.znver1.so | FileCheck -check-prefix=ZNVER1 %s
+; ZNVER1: nopw
+
+; Check we are able to use -plugin-opt=mcpu=<CPU> to set CPU string.
+; RUN: ld.lld -plugin-opt=mcpu=znver1 %t.o -o %t.znver1.so -shared
+; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.znver1.so | FileCheck -check-prefix=ZNVER1 %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() #0 {
+entry:
+ call void asm sideeffect ".p2align 4, 0x90", "~{dirflag},~{fpsr},~{flags}"()
+ ret void
+}
+
+attributes #0 = { "no-frame-pointer-elim"="true" }
diff --git a/test/ELF/lto/ctors.ll b/test/ELF/lto/ctors.ll
index 7fce645f28f6..f64189711aa5 100644
--- a/test/ELF/lto/ctors.ll
+++ b/test/ELF/lto/ctors.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %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"
diff --git a/test/ELF/lto/data-ordering-lto.s b/test/ELF/lto/data-ordering-lto.s
index 0364e587b908..bdacccc35400 100644
--- a/test/ELF/lto/data-ordering-lto.s
+++ b/test/ELF/lto/data-ordering-lto.s
@@ -8,17 +8,18 @@
# RUN: echo "pat " >> %t_order_lto.txt
# RUN: ld.lld --symbol-ordering-file %t_order_lto.txt %t.o %t.bc -o %t2.out
-# RUN: llvm-readobj -elf-output-style=GNU -t %t2.out| FileCheck %s
+# RUN: llvm-readelf -t %t2.out| FileCheck %s
# Check that the order is tin -> dipsy -> pat.
-# CHECK: Symbol table '.symtab' contains 5 entries:
+# CHECK: Symbol table '.symtab' contains 6 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
-# CHECK-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start
-# CHECK-NEXT: 2: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy
-# CHECK-NEXT: 3: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat
-# CHECK-NEXT: 4: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o
+# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start
+# CHECK-NEXT: 3: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy
+# CHECK-NEXT: 4: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat
+# CHECK-NEXT: 5: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin
.globl _start
_start:
diff --git a/test/ELF/lto/debugger-tune.ll b/test/ELF/lto/debugger-tune.ll
new file mode 100644
index 000000000000..b7457756bcb1
--- /dev/null
+++ b/test/ELF/lto/debugger-tune.ll
@@ -0,0 +1,35 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+
+; Here we verify that -debugger-tune=<value> option is
+; handled by LLD. DWARF linkage name attributes are optional,
+; they normally present, but are missing for SCE debugger tune.
+
+; RUN: ld.lld %t.o -o %t.exe
+; RUN: llvm-dwarfdump %t.exe | FileCheck %s
+; CHECK: DW_AT_linkage_name ("name_of_foo")
+
+; RUN: ld.lld -plugin-opt=-debugger-tune=sce %t.o -o %t.exe
+; RUN: llvm-dwarfdump %t.exe | FileCheck --check-prefix=SCE %s
+; SCE-NOT: name_of_foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = global i32 0, align 4, !dbg !0
+
+!llvm.dbg.cu = !{!5}
+!llvm.module.flags = !{!8, !9}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "global_foo", linkageName: "name_of_foo", scope: !2,
+ file: !3, line: 2, type: !4, isLocal: false, isDefinition: true)
+!2 = !DINamespace(name: "test", scope: null)
+!3 = !DIFile(filename: "test.cpp", directory: "/home/tests")
+!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang",
+ isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !6, globals: !7)
+!6 = !{}
+!7 = !{!0}
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll
index 2ce8570f9b68..e5f0a4875f59 100644
--- a/test/ELF/lto/defsym.ll
+++ b/test/ELF/lto/defsym.ll
@@ -2,14 +2,18 @@
; LTO
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o
-; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 -save-temps
+; RUN: llvm-readelf -t %t.so.lto.o | FileCheck --check-prefix=OBJ %s
; RUN: llvm-objdump -d %t.so | FileCheck %s
; ThinLTO
; RUN: opt -module-summary %s -o %t.o
; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o
-; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
-; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=THIN
+; RUN: ld.lld %t.o %t1.o -shared -o %t2.so -defsym=bar2=bar3 -save-temps
+; RUN: llvm-readelf -t %t2.so1.lto.o | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=THIN
+
+; OBJ: UND bar2
; Call to bar2() should not be inlined and should be routed to bar3()
; Symbol bar3 should not be eliminated
diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll
index f1e95fe75000..485014e94d9b 100644
--- a/test/ELF/lto/discard-value-names.ll
+++ b/test/ELF/lto/discard-value-names.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o
+; RUN: ld.lld -shared -save-temps %t.o -o %t2.o
; RUN: llvm-dis < %t2.o.0.0.preopt.bc | FileCheck %s
; CHECK: @GlobalValueName
diff --git a/test/ELF/lto/drop-debug-info.ll b/test/ELF/lto/drop-debug-info.ll
index 27c0260080eb..f820faf5d0e9 100644
--- a/test/ELF/lto/drop-debug-info.ll
+++ b/test/ELF/lto/drop-debug-info.ll
@@ -3,7 +3,7 @@
; 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
+; RUN: ld.lld -shared %p/Inputs/drop-debug-info.bc \
+; RUN: -disable-verify -o %t 2>&1 | FileCheck %s
; CHECK: 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
index 1ff179666f0e..f02fa02bc4fd 100644
--- a/test/ELF/lto/drop-linkage.ll
+++ b/test/ELF/lto/drop-linkage.ll
@@ -1,12 +1,12 @@
-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.0.4.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"
+
define void @foo() {
ret void
}
diff --git a/test/ELF/lto/duplicated.ll b/test/ELF/lto/duplicated.ll
index 156748117a23..fc60fbab23c9 100644
--- a/test/ELF/lto/duplicated.ll
+++ b/test/ELF/lto/duplicated.ll
@@ -1,6 +1,6 @@
; 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
+; RUN: not ld.lld %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
; CHECK: duplicate symbol: f
; CHECK-NEXT: >>> defined in {{.*}}.o
diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll
index 0e950b3c83fd..c5473d833380 100644
--- a/test/ELF/lto/dynamic-list.ll
+++ b/test/ELF/lto/dynamic-list.ll
@@ -1,7 +1,7 @@
; 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: ld.lld -o %t --dynamic-list %t.list -pie %t.o
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
; CHECK: Name: foo@
diff --git a/test/ELF/lto/dynsym.ll b/test/ELF/lto/dynsym.ll
index b2b4157820b5..d056c0b555e3 100644
--- a/test/ELF/lto/dynsym.ll
+++ b/test/ELF/lto/dynsym.ll
@@ -1,12 +1,12 @@
; 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: ld.lld %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: ld.lld %t2.o %t.so -o %t
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
; Check that we don't crash when gc'ing sections and printing the result.
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.so --gc-sections --print-gc-sections \
+; RUN: ld.lld %t2.o %t.so --gc-sections --print-gc-sections \
; RUN: -o %t
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
diff --git a/test/ELF/lto/inline-asm.ll b/test/ELF/lto/inline-asm.ll
index b6af6a5a5cbb..e0732e6def54 100644
--- a/test/ELF/lto/inline-asm.ll
+++ b/test/ELF/lto/inline-asm.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %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"
diff --git a/test/ELF/lto/internalize-basic.ll b/test/ELF/lto/internalize-basic.ll
index 43c1837528f5..5197654d5880 100644
--- a/test/ELF/lto/internalize-basic.ll
+++ b/test/ELF/lto/internalize-basic.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: ld.lld %t.o -o %t2 -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
@@ -15,7 +15,7 @@ define hidden void @foo() {
}
; Check that _start is not internalized.
-; CHECK: define void @_start()
+; CHECK: define dso_local 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
index 2034a2b3ab72..7c996e19f354 100644
--- a/test/ELF/lto/internalize-exportdyn.ll
+++ b/test/ELF/lto/internalize-exportdyn.ll
@@ -1,7 +1,7 @@
; 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: ld.lld %t.o %t2.o -o %t2 --export-dynamic -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
@@ -38,10 +38,10 @@ define linkonce_odr void @baz() {
@use_baz = global void ()* @baz
; Check what gets internalized.
-; CHECK: define void @_start()
-; CHECK: define void @foo()
+; CHECK: define dso_local void @_start()
+; CHECK: define dso_local 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()
+; CHECK: define weak_odr dso_local void @bah()
+; CHECK: define weak_odr dso_local void @baz()
diff --git a/test/ELF/lto/internalize-llvmused.ll b/test/ELF/lto/internalize-llvmused.ll
index 253dcb26d042..7e3d867da596 100644
--- a/test/ELF/lto/internalize-llvmused.ll
+++ b/test/ELF/lto/internalize-llvmused.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: ld.lld %t.o -o %t2 -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/internalize-undef.ll b/test/ELF/lto/internalize-undef.ll
index f76528bda3b0..c0860d8943bd 100644
--- a/test/ELF/lto/internalize-undef.ll
+++ b/test/ELF/lto/internalize-undef.ll
@@ -1,7 +1,7 @@
; 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: ld.lld %t.o %t2.o -o %t -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/internalize-version-script.ll b/test/ELF/lto/internalize-version-script.ll
index c577e43b50e4..7e242e1a7eff 100644
--- a/test/ELF/lto/internalize-version-script.ll
+++ b/test/ELF/lto/internalize-version-script.ll
@@ -1,7 +1,7 @@
; 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: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/irmover-error.ll b/test/ELF/lto/irmover-error.ll
index 8b9836d23ca4..d1c962ff7250 100644
--- a/test/ELF/lto/irmover-error.ll
+++ b/test/ELF/lto/irmover-error.ll
@@ -1,6 +1,6 @@
; 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
+; RUN: not ld.lld %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
; CHECK: linking module flags 'foo': IDs have conflicting values
diff --git a/test/ELF/lto/keep-undefined.ll b/test/ELF/lto/keep-undefined.ll
index cb0f4ce491f9..55d2a05b48f9 100644
--- a/test/ELF/lto/keep-undefined.ll
+++ b/test/ELF/lto/keep-undefined.ll
@@ -2,7 +2,7 @@
; This test checks that symbols which are specified in "-u" switches
; are kept over LTO if we link an executable.
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %tout -u foo
+; RUN: ld.lld %t.o -o %tout -u foo
; RUN: llvm-nm %tout | FileCheck %s
; CHECK: T foo
diff --git a/test/ELF/lto/lazy-internal.ll b/test/ELF/lto/lazy-internal.ll
new file mode 100644
index 000000000000..1bb2bac3d59e
--- /dev/null
+++ b/test/ELF/lto/lazy-internal.ll
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/lazy-internal.ll -o %t2.o
+; RUN: rm -f %t2.a
+; RUN: llvm-ar rc %t2.a %t2.o
+; RUN: ld.lld %t2.a %t1.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
+
+; CHECK: define internal void @foo()
+; CHECK: define internal void @bar()
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define hidden void @foo() {
+ call void @bar()
+ ret void
+}
+declare void @bar()
diff --git a/test/ELF/lto/linkage.ll b/test/ELF/lto/linkage.ll
index 5af9b321eeec..9b9390002c7a 100644
--- a/test/ELF/lto/linkage.ll
+++ b/test/ELF/lto/linkage.ll
@@ -1,6 +1,6 @@
; 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: ld.lld %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"
diff --git a/test/ELF/lto/linker-script-symbols-assign.ll b/test/ELF/lto/linker-script-symbols-assign.ll
index 2ffdc823a484..bd7a37402997 100644
--- a/test/ELF/lto/linker-script-symbols-assign.ll
+++ b/test/ELF/lto/linker-script-symbols-assign.ll
@@ -2,20 +2,11 @@
; RUN: llvm-as %s -o %t.o
; RUN: echo "foo = 1;" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps
; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s
; CHECK-NOT: bar
-; CHECK: Symbol {
-; CHECK: Name: foo
-; CHECK-NEXT: Value: 0x0
-; CHECK-NEXT: Size: 4
-; CHECK-NEXT: Binding: Weak
-; CHECK-NEXT: Type: Object
-; CHECK-NEXT: Other: 0
-; CHECK-NEXT: Section: .bss.foo
-; CHECK-NEXT: }
-; CHECK-NEXT:]
+; CHECK-NOT: foo
; RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=VAL
; VAL: Symbol {
@@ -29,7 +20,7 @@
; VAL-NEXT: }
; RUN: echo "zed = 1;" > %t2.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t3 --script %t2.script
+; RUN: ld.lld %t.o -o %t3 --script %t2.script
; RUN: llvm-readobj -symbols %t3 | FileCheck %s --check-prefix=ABS
; ABS: Symbol {
; ABS: Name: zed
diff --git a/test/ELF/lto/linker-script-symbols-ipo.ll b/test/ELF/lto/linker-script-symbols-ipo.ll
index 6ac1a83e1ec0..4cc95c6cacaf 100644
--- a/test/ELF/lto/linker-script-symbols-ipo.ll
+++ b/test/ELF/lto/linker-script-symbols-ipo.ll
@@ -4,7 +4,7 @@
; RUN: echo "bar = foo;" > %t.script
;; Check that without linkerscript bar is inlined.
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-objdump -d %t3 | FileCheck %s --check-prefix=IPO
; IPO: Disassembly of section .text:
; IPO: _start:
@@ -12,13 +12,13 @@
; IPO-NEXT: 201005: {{.*}} retq
;; Check that LTO does not do IPO for symbols assigned by script.
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t4 --script %t.script -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t4 --script %t.script -save-temps
; RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=NOIPO
; NOIPO: Disassembly of section .text:
; NOIPO: foo:
-; NOIPO-NEXT: 201010: {{.*}} movl $2, %eax
+; NOIPO-NEXT: {{.*}} movl $2, %eax
; NOIPO: _start:
-; NOIPO-NEXT: 201020: {{.*}} jmp -21 <foo>
+; NOIPO-NEXT: {{.*}} jmp -21 <foo>
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/linker-script-symbols.ll b/test/ELF/lto/linker-script-symbols.ll
index c2a58b6e841d..28758c052067 100644
--- a/test/ELF/lto/linker-script-symbols.ll
+++ b/test/ELF/lto/linker-script-symbols.ll
@@ -2,7 +2,7 @@
; RUN: llvm-as %s -o %t.o
; RUN: echo "foo = bar;" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps
; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s
; CHECK-NOT: zed
diff --git a/test/ELF/lto/lto-start.ll b/test/ELF/lto/lto-start.ll
index e93eecfbf033..cc1eb4bd5b01 100644
--- a/test/ELF/lto/lto-start.ll
+++ b/test/ELF/lto/lto-start.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2
+; RUN: ld.lld %t.o -o %t2
; RUN: llvm-readobj -t %t2 | FileCheck %s
; CHECK: Format: ELF64-x86-64
diff --git a/test/ELF/lto/ltopasses-basic.ll b/test/ELF/lto/ltopasses-basic.ll
index 0c4ad8b9f17c..6789bdc95fe1 100644
--- a/test/ELF/lto/ltopasses-basic.ll
+++ b/test/ELF/lto/ltopasses-basic.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; 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: ld.lld %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll
index a48959a32991..a75000d5cfd3 100644
--- a/test/ELF/lto/ltopasses-custom.ll
+++ b/test/ELF/lto/ltopasses-custom.ll
@@ -1,8 +1,8 @@
; 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: ld.lld %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: ld.lld %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
; RUN: llvm-dis %t2.so.0.4.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
diff --git a/test/ELF/lto/metadata.ll b/test/ELF/lto/metadata.ll
index 2eaacaae2726..238b5bd43b70 100644
--- a/test/ELF/lto/metadata.ll
+++ b/test/ELF/lto/metadata.ll
@@ -1,6 +1,6 @@
; 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: ld.lld %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"
diff --git a/test/ELF/lto/mix-platforms2.ll b/test/ELF/lto/mix-platforms2.ll
new file mode 100644
index 000000000000..1bd989e86746
--- /dev/null
+++ b/test/ELF/lto/mix-platforms2.ll
@@ -0,0 +1,9 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %tx64.o
+; RUN: llvm-as %S/Inputs/i386-empty.ll -o %ti386.o
+; RUN: not ld.lld %ti386.o %tx64.o -o %t.out 2>&1 | FileCheck %s
+
+; CHECK: {{.*}}x64.o is incompatible with {{.*}}i386.o
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/module-asm.ll b/test/ELF/lto/module-asm.ll
index 1389b9f5472e..eaf276214221 100644
--- a/test/ELF/lto/module-asm.ll
+++ b/test/ELF/lto/module-asm.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t
+; RUN: ld.lld %t.o -o %t
; RUN: llvm-nm %t | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/new-pass-manager.ll b/test/ELF/lto/new-pass-manager.ll
new file mode 100644
index 000000000000..918b50500166
--- /dev/null
+++ b/test/ELF/lto/new-pass-manager.ll
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+; RUN: opt -module-summary %s -o %t.o
+
+; Test new-pass-manager and debug-pass-manager option
+; RUN: ld.lld --plugin-opt=new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --plugin-opt=new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --lto-new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --lto-new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+
+; CHECK: Starting llvm::Module pass manager run
+; CHECK: Finished llvm::Module pass manager run
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll
index 57fa3041ac65..5c4ec43a21a5 100644
--- a/test/ELF/lto/opt-level.ll
+++ b/test/ELF/lto/opt-level.ll
@@ -1,30 +1,30 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.o %s
-; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o
+; RUN: ld.lld -o %t0 -e main --lto-O0 %t.o
; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s
-; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --plugin-opt=O0 %t.o
+; RUN: ld.lld -o %t0 -e main --plugin-opt=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: ld.lld -o %t2 -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: ld.lld -o %t2a -e main %t.o
; RUN: llvm-nm %t2a | FileCheck --check-prefix=CHECK-O2 %s
-; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --plugin-opt=O2 %t.o
+; RUN: ld.lld -o %t2 -e main %t.o --plugin-opt O2
; RUN: llvm-nm %t2 | 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: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID1 %s
; INVALID1: invalid optimization level for LTO: 6
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O6 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=O6 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID1 %s
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=Ofoo %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=Ofoo %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID2 %s
-; INVALID2: --plugin-opt: number expected, but got 'foo'
+; INVALID2: --plugin-opt=Ofoo: number expected, but got 'foo'
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --lto-O-1 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALIDNEGATIVE1 %s
; INVALIDNEGATIVE1: invalid optimization level for LTO: 4294967295
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O-1 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=O-1 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALIDNEGATIVE2 %s
; INVALIDNEGATIVE2: invalid optimization level for LTO: 4294967295
diff --git a/test/ELF/lto/parallel-internalize.ll b/test/ELF/lto/parallel-internalize.ll
index da5bdc6892a8..f21b3ccd29e9 100644
--- a/test/ELF/lto/parallel-internalize.ll
+++ b/test/ELF/lto/parallel-internalize.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.bc %s
; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc \
+; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc \
; RUN: -e foo --lto-O0
; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s
; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
@@ -18,6 +18,24 @@
; CHECK-NEXT: Section: Undefined (0x0)
; CHECK-NEXT: }
; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
; CHECK-NEXT: Name: bar
; CHECK-NEXT: Value: 0x201010
; CHECK-NEXT: Size: 8
diff --git a/test/ELF/lto/parallel.ll b/test/ELF/lto/parallel.ll
index a1c15af380f0..4ba3fd69d527 100644
--- a/test/ELF/lto/parallel.ll
+++ b/test/ELF/lto/parallel.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.bc %s
; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc -shared
+; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc -shared
; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll
index 8e8d9d165787..80e5dac77d83 100644
--- a/test/ELF/lto/relax-relocs.ll
+++ b/test/ELF/lto/relax-relocs.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so
+; RUN: ld.lld -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
diff --git a/test/ELF/lto/relocatable.ll b/test/ELF/lto/relocatable.ll
index ef21f84a621a..2ec9144a37b0 100644
--- a/test/ELF/lto/relocatable.ll
+++ b/test/ELF/lto/relocatable.ll
@@ -14,6 +14,15 @@
; CHECK-NEXT: Section: Undefined
; CHECK-NEXT: }
; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
; CHECK-NEXT: Name:
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 0
diff --git a/test/ELF/lto/sample-profile.ll b/test/ELF/lto/sample-profile.ll
new file mode 100644
index 000000000000..a8b110444425
--- /dev/null
+++ b/test/ELF/lto/sample-profile.ll
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; RUN: rm -f %t1.lto.o %t2.lto.o
+; RUN: ld.lld --lto-sample-profile=%p/Inputs/sample-profile.prof %t1.o %t2.o -o %t3
+; RUN opt -S %t3.lto.o | FileCheck %s
+
+; RUN: rm -f %t1.lto.o %t2.lto.o
+; RUN: ld.lld --plugin-opt=sample-profile=%p/Inputs/sample-profile.prof %t1.o %t2.o -o %t3
+; RUN opt -S %t3.lto.o | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: ProfileSummary
+declare void @g(...)
+declare void @h(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ call void (...) @h()
+ ret void
+}
diff --git a/test/ELF/lto/save-temps.ll b/test/ELF/lto/save-temps.ll
index c8e52ff4b4ec..b34134cc5d7f 100644
--- a/test/ELF/lto/save-temps.ll
+++ b/test/ELF/lto/save-temps.ll
@@ -3,7 +3,7 @@
; 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: ld.lld -shared %t.o %t2.o -save-temps
; RUN: llvm-nm a.out | FileCheck %s
; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
; RUN: llvm-nm a.out.lto.o | FileCheck %s
diff --git a/test/ELF/lto/setting-dso-local.ll b/test/ELF/lto/setting-dso-local.ll
new file mode 100644
index 000000000000..74ce4e7f16d3
--- /dev/null
+++ b/test/ELF/lto/setting-dso-local.ll
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: not ld.lld -o %t %t1.o 2>&1 | FileCheck %s
+
+; CHECK: undefined symbol: foobar
+
+; We used to crash setting foobar to non-dso_local
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foobar = external hidden global i32
+define i32* @_start() {
+ ret i32* @foobar
+}
diff --git a/test/ELF/lto/start-lib.ll b/test/ELF/lto/start-lib.ll
index ec73954a80ca..024d887a7d0a 100644
--- a/test/ELF/lto/start-lib.ll
+++ b/test/ELF/lto/start-lib.ll
@@ -4,17 +4,17 @@
; 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: ld.lld -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: ld.lld -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: ld.lld -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
diff --git a/test/ELF/lto/symbol-ordering-lto.s b/test/ELF/lto/symbol-ordering-lto.s
index 4c29e54c476e..530b63c669a4 100644
--- a/test/ELF/lto/symbol-ordering-lto.s
+++ b/test/ELF/lto/symbol-ordering-lto.s
@@ -8,16 +8,17 @@
# RUN: echo "pat " >> %t_order_lto.txt
# RUN: ld.lld --symbol-ordering-file %t_order_lto.txt %t.o %t.bc -o %t2.out
-# RUN: llvm-readobj -elf-output-style=GNU -t %t2.out| FileCheck %s
+# RUN: llvm-readelf -t %t2.out| FileCheck %s
# Check that the order is tin -> _start -> pat.
-# CHECK: Symbol table '.symtab' contains 4 entries:
+# CHECK: Symbol table '.symtab' contains 5 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
-# CHECK-NEXT: 1: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start
-# CHECK-NEXT: 2: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat
-# CHECK-NEXT: 3: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o
+# CHECK-NEXT: 2: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start
+# CHECK-NEXT: 3: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat
+# CHECK-NEXT: 4: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin
.globl _start
_start:
diff --git a/test/ELF/lto/thinlto-cant-write-index.ll b/test/ELF/lto/thinlto-cant-write-index.ll
new file mode 100644
index 000000000000..94f2a45c2743
--- /dev/null
+++ b/test/ELF/lto/thinlto-cant-write-index.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Ensure lld generates error if unable to write to index files
+; RUN: rm -f %t2.o.thinlto.bc
+; RUN: touch %t2.o.thinlto.bc
+; RUN: chmod 400 %t2.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3 2>&1 | FileCheck %s
+; CHECK: cannot open {{.*}}2.o.thinlto.bc: {{P|p}}ermission denied
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-debug-fission.ll b/test/ELF/lto/thinlto-debug-fission.ll
new file mode 100644
index 000000000000..b779ad4a45f6
--- /dev/null
+++ b/test/ELF/lto/thinlto-debug-fission.ll
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+
+; RUN: opt %s -o %t1.o
+; RUN: rm -rf %T/dwo
+
+; Test to ensure that --plugin-opt=dwo_dir=$DIR creates .dwo files under $DIR
+; RUN: ld.lld --plugin-opt=dwo_dir=%T/dwo -shared %t1.o -o /dev/null
+; RUN: llvm-readobj -h %T/dwo/0.dwo | FileCheck %s
+
+; CHECK: Format: ELF64-x86-64
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-emit-imports.ll b/test/ELF/lto/thinlto-emit-imports.ll
new file mode 100644
index 000000000000..cae7922682bc
--- /dev/null
+++ b/test/ELF/lto/thinlto-emit-imports.ll
@@ -0,0 +1,55 @@
+; REQUIRES: x86
+
+; Generate summary sections and test lld handling.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Include a file with an empty module summary index, to ensure that the expected
+; output files are created regardless, for a distributed build system.
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld generates imports files if requested for distributed backends.
+; RUN: rm -f %t3.o.imports %t3.o.thinlto.bc
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4
+
+; The imports file for this module contains the bitcode file for
+; Inputs/thinlto.ll
+; RUN: cat %t1.o.imports | count 1
+; RUN: cat %t1.o.imports | FileCheck %s --check-prefix=IMPORTS1
+; IMPORTS1: thinlto-emit-imports.ll.tmp2.o
+
+; The imports file for Input/thinlto.ll is empty as it does not import anything.
+; RUN: cat %t2.o.imports | count 0
+
+; The imports file for Input/thinlto_empty.ll is empty but should exist.
+; RUN: cat %t3.o.imports | count 0
+
+; The index file should be created even for the input with an empty summary.
+; RUN: ls %t3.o.thinlto.bc
+
+; Ensure lld generates error if unable to write to imports file.
+; RUN: rm -f %t3.o.imports
+; RUN: touch %t3.o.imports
+; RUN: chmod 400 %t3.o.imports
+; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 2>&1 | FileCheck %s --check-prefix=ERR
+; ERR: cannot open {{.*}}3.o.imports: {{P|p}}ermission denied
+
+; Ensure lld doesn't generate import files when thinlto-index-only is not enabled
+; RUN: rm -f %t1.o.imports
+; RUN: rm -f %t2.o.imports
+; RUN: rm -f %t3.o.imports
+; RUN: ld.lld --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: not ls %t1.o.imports
+; RUN: not ls %t2.o.imports
+; RUN: not ls %t3.o.imports
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-index-file.ll b/test/ELF/lto/thinlto-index-file.ll
new file mode 100644
index 000000000000..91f0b298ca35
--- /dev/null
+++ b/test/ELF/lto/thinlto-index-file.ll
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld writes linked files to linked objects file
+; RUN: ld.lld --plugin-opt=thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: FileCheck %s < %t.idx
+; CHECK: {{.*}}thinlto-index-file.ll.tmp1.o
+; CHECK: {{.*}}thinlto-index-file.ll.tmp2.o
+; CHECK: {{.*}}thinlto-index-file.ll.tmp3.o
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-index-only.ll b/test/ELF/lto/thinlto-index-only.ll
new file mode 100644
index 000000000000..6263799ee2fd
--- /dev/null
+++ b/test/ELF/lto/thinlto-index-only.ll
@@ -0,0 +1,89 @@
+; REQUIRES: x86
+
+; First ensure that the ThinLTO handling in lld handles
+; bitcode without summary sections gracefully and generates index file.
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/thinlto.ll -o %t2.o
+; RUN: rm -f %t3
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3
+; RUN: ls %t2.o.thinlto.bc
+; RUN: not test -e %t3
+; RUN: ld.lld -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t3 | FileCheck %s --check-prefix=NM
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld generates an index and not a binary if requested.
+; RUN: rm -f %t4
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t4
+; RUN: llvm-bcanalyzer -dump %t1.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND1
+; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
+; RUN: not test -e %t4
+
+; Ensure lld generates an index even if the file is wrapped in --start-lib/--end-lib
+; RUN: rm -f %t2.o.thinlto.bc %t4
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t3.o --start-lib %t2.o --end-lib -o %t4
+; RUN: ls %t2.o.thinlto.bc
+; RUN: not test -e %t4
+
+; Test that LLD generates an empty index even for lazy object file that is not added to link.
+; Test LLD generates empty imports file either because of thinlto-emit-imports-files option.
+; RUN: rm -f %t1.o.thinlto.bc
+; RUN: rm -f %t1.o.imports
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t2.o --start-lib %t1.o --end-lib \
+; RUN: --plugin-opt=thinlto-emit-imports-files -o %t3
+; RUN: ls %t1.o.thinlto.bc
+; RUN: ls %t1.o.imports
+
+; Ensure lld generates an error if unable to write an empty index file
+; for lazy object file that is not added to link.
+; RUN: rm -f %t1.o.thinlto.bc
+; RUN: touch %t1.o.thinlto.bc
+; RUN: chmod 400 %t1.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t2.o --start-lib %t1.o --end-lib \
+; RUN: -o %t3 2>&1 | FileCheck %s
+; CHECK: cannot open {{.*}}1.o.thinlto.bc: {{P|p}}ermission denied
+; RUN: rm -f %t1.o.thinlto.bc
+
+; NM: T f
+
+; The backend index for this module contains summaries from itself and
+; Inputs/thinlto.ll, as it imports from the latter.
+; BACKEND1: <MODULE_STRTAB_BLOCK
+; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o'
+; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o'
+; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
+; BACKEND1: <GLOBALVAL_SUMMARY_BLOCK
+; BACKEND1: <VERSION
+; BACKEND1: <FLAGS
+; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
+; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
+; BACKEND1: <COMBINED
+; BACKEND1: <COMBINED
+; BACKEND1: </GLOBALVAL_SUMMARY_BLOCK
+
+; The backend index for Input/thinlto.ll contains summaries from itself only,
+; as it does not import anything.
+; BACKEND2: <MODULE_STRTAB_BLOCK
+; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp2.o'
+; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
+; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
+; BACKEND2-NEXT: <VERSION
+; BACKEND2-NEXT: <FLAGS
+; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
+; BACKEND2-NEXT: <COMBINED
+; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-no-index.ll b/test/ELF/lto/thinlto-no-index.ll
new file mode 100644
index 000000000000..f80cf0e63812
--- /dev/null
+++ b/test/ELF/lto/thinlto-no-index.ll
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld doesn't generates index files when thinlto-index-only is not enabled
+; RUN: rm -f %t1.o.thinlto.bc %t2.o.thinlto.bc %t3.o.thinlto.bc
+; RUN: ld.lld -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: not ls %t1.o.thinlto.bc
+; RUN: not ls %t2.o.thinlto.bc
+; RUN: not ls %t3.o.thinlto.bc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-obj-path.ll b/test/ELF/lto/thinlto-obj-path.ll
new file mode 100644
index 000000000000..bb69bb876a28
--- /dev/null
+++ b/test/ELF/lto/thinlto-obj-path.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Test to ensure that thinlto-index-only with obj-path creates the file.
+; RUN: rm -f %t4.o
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t3
+; RUN: llvm-readobj -h %t4.o | FileCheck %s
+; RUN: llvm-nm %t4.o | count 0
+
+; CHECK: Format: ELF64-x86-64
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-object-suffix-replace.ll b/test/ELF/lto/thinlto-object-suffix-replace.ll
new file mode 100644
index 000000000000..05ce942c70f8
--- /dev/null
+++ b/test/ELF/lto/thinlto-object-suffix-replace.ll
@@ -0,0 +1,50 @@
+; REQUIRES: x86
+
+; Test to make sure the thinlto-object-suffix-replace option is handled
+; correctly.
+
+; Generate bitcode file with summary, as well as a minimized bitcode without
+; the debug metadata for the thin link.
+; RUN: opt -thinlto-bc %s -thin-link-bitcode-file=%t1.thinlink.bc -o %t1.o
+
+; First perform the thin link on the normal bitcode file, and save the
+; resulting index.
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o -o %t3
+; RUN: cp %t1.o.thinlto.bc %t1.o.thinlto.bc.orig
+
+; Next perform the thin link on the minimized bitcode file, and compare dump
+; of the resulting index to the above dump to ensure they are identical.
+; RUN: rm -f %t1.o.thinlto.bc
+; Make sure it isn't inadvertently using the regular bitcode file.
+; RUN: rm -f %t1.o
+; RUN: ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace=".thinlink.bc;.o" \
+; RUN: -shared %t1.thinlink.bc -o %t3
+; RUN: diff %t1.o.thinlto.bc.orig %t1.o.thinlto.bc
+
+; Ensure lld generates error if object suffix replace option does not have 'old;new' format
+; RUN: rm -f %t1.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace="abc:def" -shared %t1.thinlink.bc \
+; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR1
+; ERR1: --plugin-opt=thinlto-object-suffix-replace= expects 'old;new' format, but got abc:def
+
+; Ensure lld generates error if old suffix doesn't exist in file name
+; RUN: rm -f %t1.o
+; RUN: not ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace=".abc;.o" -shared %t1.thinlink.bc \
+; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR2
+; ERR2: error: -thinlto-object-suffix-replace=.abc;.o was given, but {{.*}} does not end with the suffix
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+entry:
+ ret void
+}
+
+!llvm.dbg.cu = !{}
+
+!1 = !{i32 2, !"Debug Info Version", i32 3}
+!llvm.module.flags = !{!1}
diff --git a/test/ELF/lto/thinlto-prefix-replace.ll b/test/ELF/lto/thinlto-prefix-replace.ll
new file mode 100644
index 000000000000..c276dae7b260
--- /dev/null
+++ b/test/ELF/lto/thinlto-prefix-replace.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; Check that changing the output path via thinlto-prefix-replace works
+; RUN: mkdir -p %t/oldpath
+; RUN: opt -module-summary %s -o %t/oldpath/thinlto_prefix_replace.o
+
+; Ensure that there is no existing file at the new path, so we properly
+; test the creation of the new file there.
+; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace="%t/oldpath/;%t/newpath/" -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace
+; RUN: ls %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+
+; Ensure that lld generates error if prefix replace option does not have 'old;new' format
+; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace=abc:def -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace 2>&1 | FileCheck %s --check-prefix=ERR
+; ERR: --plugin-opt=thinlto-prefix-replace= expects 'old;new' format, but got abc:def
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+entry:
+ ret void
+}
diff --git a/test/ELF/lto/thinlto.ll b/test/ELF/lto/thinlto.ll
index 37d2b88131f6..51c82ece5876 100644
--- a/test/ELF/lto/thinlto.ll
+++ b/test/ELF/lto/thinlto.ll
@@ -1,30 +1,29 @@
; REQUIRES: x86
+
; Basic ThinLTO tests.
-; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %s -o %t1.o
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
; First force single-threaded mode
-; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t.o %t2.o -o %t
-; RUN: llvm-nm %t1.lto.o | FileCheck %s --check-prefix=NM1
-; RUN: llvm-nm %t2.lto.o | FileCheck %s --check-prefix=NM2
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
; Next force multi-threaded mode
-; RUN: rm -f %t2.lto.o %t21.lto.o
-; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t.o %t2.o -o %t2
-; RUN: llvm-nm %t21.lto.o | FileCheck %s --check-prefix=NM1
-; RUN: llvm-nm %t22.lto.o | FileCheck %s --check-prefix=NM2
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
-; NM1: T f
-; NM1-NOT: U g
+; Then check without --thinlto-jobs (which currently default to hardware_concurrency)
+; RUN: ld.lld -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+; NM1: T f
; NM2: T g
-; Then check without --thinlto-jobs (which currently default to hardware_concurrency)
-; We just check that we don't crash or fail (as it's not sure which tests are
-; stable on the final output file itself.
-; RUN: ld.lld -shared %t.o %t2.o -o %t2
-
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/timepasses.ll b/test/ELF/lto/timepasses.ll
index 5c893e661945..86c9b8ed7951 100644
--- a/test/ELF/lto/timepasses.ll
+++ b/test/ELF/lto/timepasses.ll
@@ -1,8 +1,7 @@
-; We use lld -flavor gnu because llvm-lit will append --full-shutdown to
-; the ld.lld invocation.
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: lld -flavor gnu %t.o -o %t.so -shared -mllvm -time-passes 2>&1 | FileCheck %s
+; RUN: env LLD_IN_TEST=0 ld.lld %t.o -o %t.so -shared -mllvm \
+; RUN: -time-passes 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"
@@ -11,5 +10,5 @@ define void @patatino() {
ret void
}
-; We should get the output of -time-passes even when --full-shutdown is not specified.
+; We should get the output of -time-passes even when full shutdown is not specified.
; CHECK: Total Execution Time
diff --git a/test/ELF/lto/tls-mixed.ll b/test/ELF/lto/tls-mixed.ll
index 524bb4fb44a3..9d5a69303728 100644
--- a/test/ELF/lto/tls-mixed.ll
+++ b/test/ELF/lto/tls-mixed.ll
@@ -1,7 +1,7 @@
; 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
+; RUN: ld.lld %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"
diff --git a/test/ELF/lto/tls-preserve.ll b/test/ELF/lto/tls-preserve.ll
index 8aebcb783f48..c9b7675cd22f 100644
--- a/test/ELF/lto/tls-preserve.ll
+++ b/test/ELF/lto/tls-preserve.ll
@@ -1,7 +1,7 @@
; 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: ld.lld -shared %t1.o -o %t1
; RUN: llvm-readobj -t %t1 | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/type-merge.ll b/test/ELF/lto/type-merge.ll
index d6f196d7c3ba..985c44b796e1 100644
--- a/test/ELF/lto/type-merge.ll
+++ b/test/ELF/lto/type-merge.ll
@@ -1,7 +1,7 @@
; 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: ld.lld %t.o %t2.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.0.preopt.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll
index 6ebbf778dd8e..5944be7e6c09 100644
--- a/test/ELF/lto/type-merge2.ll
+++ b/test/ELF/lto/type-merge2.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; 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: ld.lld %t.o %t2.o -o %t.so -shared -save-temps
; RUN: llvm-dis %t.so.0.0.preopt.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/undef-weak.ll b/test/ELF/lto/undef-weak.ll
index 215978a73df0..e090f5653a09 100644
--- a/test/ELF/lto/undef-weak.ll
+++ b/test/ELF/lto/undef-weak.ll
@@ -1,13 +1,12 @@
; 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: ld.lld %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"
diff --git a/test/ELF/lto/undef.ll b/test/ELF/lto/undef.ll
index 41da61052290..4ea7e833df10 100644
--- a/test/ELF/lto/undef.ll
+++ b/test/ELF/lto/undef.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %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"
diff --git a/test/ELF/lto/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll
index d13630368de9..6c3dc76be12a 100644
--- a/test/ELF/lto/undefined-puts.ll
+++ b/test/ELF/lto/undefined-puts.ll
@@ -2,7 +2,7 @@
; 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: ld.lld %t1.so %t2.o -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"
diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll
index 29a59415851b..38b08ab23ee9 100644
--- a/test/ELF/lto/unnamed-addr-comdat.ll
+++ b/test/ELF/lto/unnamed-addr-comdat.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; 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: ld.lld %t.o %t.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/unnamed-addr-drop.ll b/test/ELF/lto/unnamed-addr-drop.ll
index e827cbb435e6..ad662b7fe7b6 100644
--- a/test/ELF/lto/unnamed-addr-drop.ll
+++ b/test/ELF/lto/unnamed-addr-drop.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared
+; RUN: ld.lld %t1.o %t2.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/unnamed-addr-lib.ll b/test/ELF/lto/unnamed-addr-lib.ll
index c2bc6016efd5..0c47468e6b4f 100644
--- a/test/ELF/lto/unnamed-addr-lib.ll
+++ b/test/ELF/lto/unnamed-addr-lib.ll
@@ -2,7 +2,7 @@
; 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: ld.lld %t.o %t2.so -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
; This documents a small limitation of lld's internalization logic. We decide
diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll
index 56fe148b0995..7504fdf6733b 100644
--- a/test/ELF/lto/unnamed-addr.ll
+++ b/test/ELF/lto/unnamed-addr.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared
+; RUN: ld.lld %t.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/verify-invalid.ll b/test/ELF/lto/verify-invalid.ll
index e6138a3cca62..9fa0f9e0b5f9 100644
--- a/test/ELF/lto/verify-invalid.ll
+++ b/test/ELF/lto/verify-invalid.ll
@@ -1,10 +1,10 @@
; 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: ld.lld %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: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \
; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \
; RUN: --plugin-opt=disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll
index c43b443ff749..35a36b5a8d78 100644
--- a/test/ELF/lto/version-script.ll
+++ b/test/ELF/lto/version-script.ll
@@ -1,7 +1,7 @@
; 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: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps
; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s
; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s
diff --git a/test/ELF/lto/version-script2.ll b/test/ELF/lto/version-script2.ll
new file mode 100644
index 000000000000..ab8f75a3eecc
--- /dev/null
+++ b/test/ELF/lto/version-script2.ll
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "VER1 {};" > %t.script
+; RUN: ld.lld %t.o -o %t.so -shared --version-script %t.script
+; RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+; test that we have the correct version.
+; CHECK: Name: foo@@VER1 (
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm ".global foo"
+module asm "foo:"
+module asm ".symver foo,foo@@@VER1"
diff --git a/test/ELF/lto/visibility.ll b/test/ELF/lto/visibility.ll
index 9acc0e2efaaf..434b61ef294c 100644
--- a/test/ELF/lto/visibility.ll
+++ b/test/ELF/lto/visibility.ll
@@ -1,7 +1,8 @@
; 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: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck --check-prefix=IR %s
; RUN: llvm-readobj -t %t.so | FileCheck %s
; CHECK: Name: g
@@ -28,6 +29,8 @@ 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()
+; IR: declare hidden void @g()
+
define void @f() {
call void @g()
ret void
diff --git a/test/ELF/lto/weak.ll b/test/ELF/lto/weak.ll
index 381ef7a1a347..a807c1325db5 100644
--- a/test/ELF/lto/weak.ll
+++ b/test/ELF/lto/weak.ll
@@ -1,6 +1,6 @@
; 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: ld.lld %t.o %t.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/weakodr-visibility.ll b/test/ELF/lto/weakodr-visibility.ll
new file mode 100644
index 000000000000..95bd3e4c5a28
--- /dev/null
+++ b/test/ELF/lto/weakodr-visibility.ll
@@ -0,0 +1,40 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/weakodr-visibility.ll -o %t2.o
+
+; Testcase checks we keep desired visibility of weak
+; symbol in a library even if select different definition.
+; We change the order of input files in command line and
+; check that linker selects different symbol definitions,
+; but keeps `protected` visibility.
+
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=FIRST
+; CHECK: Symbol {
+; CHECK: Name: foo
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Weak
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other [
+; CHECK-NEXT: STV_PROTECTED
+; CHECK-NEXT: ]
+; CHECK-NEXT: Section:
+; CHECK-NEXT: }
+; FIRST: foo:
+; FIRST-NEXT: movl $41, %eax
+
+; Now swap the files order.
+; RUN: ld.lld %t2.o %t1.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=SECOND
+; SECOND: foo:
+; SECOND-NEXT: movl $42, %eax
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define weak_odr i32 @foo(i8* %this) {
+ ret i32 41
+}
diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll
index 83e09493fb5d..b82bece253d1 100644
--- a/test/ELF/lto/wrap-1.ll
+++ b/test/ELF/lto/wrap-1.ll
@@ -20,8 +20,8 @@
; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar
; in the resolutions file.
; RESOLS: ,bar,xr
-; RESOLS: ,__wrap_bar,px
-; RESOLS: ,__real_bar,pxr
+; RESOLS: ,__wrap_bar,plx
+; RESOLS: ,__real_bar,plxr
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/map-file-i686.s b/test/ELF/map-file-i686.s
new file mode 100644
index 000000000000..bab2c4b377e2
--- /dev/null
+++ b/test/ELF/map-file-i686.s
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t1.o
+// RUN: ld.lld %t1.o -o /dev/null -M | FileCheck -strict-whitespace %s
+
+.global _start
+_start:
+ nop
+
+// CHECK: VMA LMA Size Align Out In Symbol
+// CHECK-NEXT: 11000 11000 1 4 .text
+// CHECK-NEXT: 11000 11000 1 4 {{.*}}{{/|\\}}map-file-i686.s.tmp1.o:(.text)
+// CHECK-NEXT: 11000 11000 0 1 _start
+// CHECK-NEXT: 0 0 8 1 .comment
+// CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+// CHECK-NEXT: 0 0 20 4 .symtab
+// CHECK-NEXT: 0 0 20 4 <internal>:(.symtab)
+// CHECK-NEXT: 0 0 2a 1 .shstrtab
+// CHECK-NEXT: 0 0 2a 1 <internal>:(.shstrtab)
+// CHECK-NEXT: 0 0 8 1 .strtab
+// CHECK-NEXT: 0 0 8 1 <internal>:(.strtab)
diff --git a/test/ELF/map-file.s b/test/ELF/map-file.s
index d1acabe28126..76e50fb5db04 100644
--- a/test/ELF/map-file.s
+++ b/test/ELF/map-file.s
@@ -15,16 +15,21 @@
.global _start
_start:
+.cfi_startproc
+.cfi_endproc
.quad sharedFoo
.quad sharedBar
- callq sharedFunc1
- callq sharedFunc2
- call baz
+ .byte 0xe8
+ .long sharedFunc1 - .
+ .byte 0xe8
+ .long sharedFunc2 - .
+ .byte 0xe8
+ .long baz - .
.global _Z1fi
_Z1fi:
.cfi_startproc
-.cfi_endproc
nop
+.cfi_endproc
.weak bar
bar:
.long bar - .
@@ -35,58 +40,61 @@ local:
abs = 0xAB5
labs = 0x1AB5
-// CHECK: Address Size Align Out In Symbol
-// CHECK-NEXT: 00000000002001c8 0000000000000078 8 .dynsym
-// CHECK-NEXT: 00000000002001c8 0000000000000078 8 <internal>:(.dynsym)
-// CHECK-NEXT: 0000000000200240 000000000000002c 8 .gnu.hash
-// CHECK-NEXT: 0000000000200240 000000000000002c 8 <internal>:(.gnu.hash)
-// CHECK-NEXT: 000000000020026c 0000000000000030 4 .hash
-// CHECK-NEXT: 000000000020026c 0000000000000030 4 <internal>:(.hash)
-// CHECK-NEXT: 000000000020029c 0000000000000031 1 .dynstr
-// CHECK-NEXT: 000000000020029c 0000000000000031 1 <internal>:(.dynstr)
-// CHECK-NEXT: 00000000002002d0 0000000000000030 8 .rela.dyn
-// CHECK-NEXT: 00000000002002d0 0000000000000030 8 <internal>:(.rela.dyn)
-// CHECK-NEXT: 0000000000200300 0000000000000030 8 .rela.plt
-// CHECK-NEXT: 0000000000200300 0000000000000030 8 <internal>:(.rela.plt)
-// CHECK-NEXT: 0000000000200330 0000000000000030 8 .eh_frame
-// CHECK-NEXT: 0000000000200330 0000000000000030 8 <internal>:(.eh_frame)
-// CHECK-NEXT: 0000000000201000 000000000000002d 4 .text
-// CHECK-NEXT: 0000000000201000 0000000000000028 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text)
-// CHECK-NEXT: 0000000000201000 0000000000000000 0 _start
-// CHECK-NEXT: 000000000020101f 0000000000000000 0 f(int)
-// CHECK-NEXT: 0000000000201028 0000000000000000 0 local
-// CHECK-NEXT: 0000000000201028 0000000000000002 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text)
-// CHECK-NEXT: 0000000000201028 0000000000000000 0 foo
-// CHECK-NEXT: 0000000000201029 0000000000000000 0 bar
-// CHECK-NEXT: 000000000020102a 0000000000000000 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed)
-// CHECK-NEXT: 000000000020102a 0000000000000000 0 zed
-// CHECK-NEXT: 000000000020102c 0000000000000000 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text)
-// CHECK-NEXT: 000000000020102c 0000000000000000 0 bah
-// CHECK-NEXT: 000000000020102c 0000000000000001 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text)
-// CHECK-NEXT: 000000000020102c 0000000000000000 0 baz
-// CHECK-NEXT: 0000000000201030 0000000000000030 16 .plt
-// CHECK-NEXT: 0000000000201030 0000000000000030 16 <internal>:(.plt)
-// CHECK-NEXT: 0000000000201040 0000000000000000 0 sharedFunc1
-// CHECK-NEXT: 0000000000201050 0000000000000000 0 sharedFunc2
-// CHECK-NEXT: 0000000000202000 0000000000000028 8 .got.plt
-// CHECK-NEXT: 0000000000202000 0000000000000028 8 <internal>:(.got.plt)
-// CHECK-NEXT: 0000000000203000 0000000000000100 8 .dynamic
-// CHECK-NEXT: 0000000000203000 0000000000000100 8 <internal>:(.dynamic)
-// CHECK-NEXT: 0000000000204000 0000000000000010 16 .bss
-// CHECK-NEXT: 0000000000204000 0000000000000004 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON)
-// CHECK-NEXT: 0000000000204000 0000000000000004 0 common
-// CHECK-NEXT: 0000000000204004 0000000000000004 1 <internal>:(.bss)
-// CHECK-NEXT: 0000000000204004 0000000000000004 0 sharedFoo
-// CHECK-NEXT: 0000000000204008 0000000000000008 1 <internal>:(.bss)
-// CHECK-NEXT: 0000000000204008 0000000000000008 0 sharedBar
-// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
-// CHECK-NEXT: 0000000000000000 0000000000000008 1 <internal>:(.comment)
-// CHECK-NEXT: 0000000000000000 0000000000000198 8 .symtab
-// CHECK-NEXT: 0000000000000000 0000000000000198 8 <internal>:(.symtab)
-// CHECK-NEXT: 0000000000000000 0000000000000084 1 .shstrtab
-// CHECK-NEXT: 0000000000000000 0000000000000084 1 <internal>:(.shstrtab)
-// CHECK-NEXT: 0000000000000000 000000000000006d 1 .strtab
-// CHECK-NEXT: 0000000000000000 000000000000006d 1 <internal>:(.strtab)
+// CHECK: VMA LMA Size Align Out In Symbol
+// CHECK-NEXT: 2001c8 2001c8 78 8 .dynsym
+// CHECK-NEXT: 2001c8 2001c8 78 8 <internal>:(.dynsym)
+// CHECK-NEXT: 200240 200240 2c 8 .gnu.hash
+// CHECK-NEXT: 200240 200240 2c 8 <internal>:(.gnu.hash)
+// CHECK-NEXT: 20026c 20026c 30 4 .hash
+// CHECK-NEXT: 20026c 20026c 30 4 <internal>:(.hash)
+// CHECK-NEXT: 20029c 20029c 31 1 .dynstr
+// CHECK-NEXT: 20029c 20029c 31 1 <internal>:(.dynstr)
+// CHECK-NEXT: 2002d0 2002d0 30 8 .rela.dyn
+// CHECK-NEXT: 2002d0 2002d0 30 8 <internal>:(.rela.dyn)
+// CHECK-NEXT: 200300 200300 30 8 .rela.plt
+// CHECK-NEXT: 200300 200300 30 8 <internal>:(.rela.plt)
+// CHECK-NEXT: 200330 200330 64 8 .eh_frame
+// CHECK-NEXT: 200330 200330 2c 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0)
+// CHECK-NEXT: 200360 200360 14 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c)
+// CHECK-NEXT: 200378 200378 18 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18)
+// CHECK-NEXT: 201000 201000 2d 4 .text
+// CHECK-NEXT: 201000 201000 28 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text)
+// CHECK-NEXT: 201000 201000 0 1 _start
+// CHECK-NEXT: 20101f 20101f 0 1 f(int)
+// CHECK-NEXT: 201028 201028 0 1 local
+// CHECK-NEXT: 201028 201028 2 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text)
+// CHECK-NEXT: 201028 201028 0 1 foo
+// CHECK-NEXT: 201029 201029 0 1 bar
+// CHECK-NEXT: 20102a 20102a 0 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed)
+// CHECK-NEXT: 20102a 20102a 0 1 zed
+// CHECK-NEXT: 20102c 20102c 0 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text)
+// CHECK-NEXT: 20102c 20102c 0 1 bah
+// CHECK-NEXT: 20102c 20102c 1 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text)
+// CHECK-NEXT: 20102c 20102c 0 1 baz
+// CHECK-NEXT: 201030 201030 30 16 .plt
+// CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt)
+// CHECK-NEXT: 201040 201040 0 1 sharedFunc1
+// CHECK-NEXT: 201050 201050 0 1 sharedFunc2
+// CHECK-NEXT: 202000 202000 28 8 .got.plt
+// CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt)
+// CHECK-NEXT: 203000 203000 100 8 .dynamic
+// CHECK-NEXT: 203000 203000 100 8 <internal>:(.dynamic)
+// CHECK-NEXT: 204000 204000 10 16 .bss
+// CHECK-NEXT: 204000 204000 4 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON)
+// CHECK-NEXT: 204000 204000 4 1 common
+// CHECK-NEXT: 204004 204004 4 1 <internal>:(.bss)
+// CHECK-NEXT: 204004 204004 4 1 sharedFoo
+// CHECK-NEXT: 204008 204008 8 1 <internal>:(.bss)
+// CHECK-NEXT: 204008 204008 8 1 sharedBar
+// CHECK-NEXT: 0 0 8 1 .comment
+// CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+// CHECK-NEXT: 0 0 198 8 .symtab
+// CHECK-NEXT: 0 0 198 8 <internal>:(.symtab)
+// CHECK-NEXT: 0 0 84 1 .shstrtab
+// CHECK-NEXT: 0 0 84 1 <internal>:(.shstrtab)
+// CHECK-NEXT: 0 0 6d 1 .strtab
+// CHECK-NEXT: 0 0 6d 1 <internal>:(.strtab)
+
// RUN: not ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=/ 2>&1 \
// RUN: | FileCheck -check-prefix=FAIL %s
diff --git a/test/ELF/map-gc-sections.s b/test/ELF/map-gc-sections.s
index 717ab819889d..f69edf591f2f 100644
--- a/test/ELF/map-gc-sections.s
+++ b/test/ELF/map-gc-sections.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: ld.lld %t.o -o %t -Map=- --gc-sections | FileCheck %s
+// RUN: ld.lld %t.o -o /dev/null -Map=- --gc-sections | FileCheck %s
.section .tbss,"awT",@nobits
// CHECK-NOT: foo
diff --git a/test/ELF/merge-gc-piece.s b/test/ELF/merge-gc-piece.s
new file mode 100644
index 000000000000..4aec3b2aaed3
--- /dev/null
+++ b/test/ELF/merge-gc-piece.s
@@ -0,0 +1,38 @@
+# 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 --gc-sections
+# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x200
+
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 01020000 00000000 02020000 00000000
+# CHECK-NEXT: )
+
+ .section .foo,"aM",@progbits,8
+ .quad 42
+ .global sym
+sym:
+ .quad 43
+
+ .section .bar
+ .quad .foo + 1
+ .quad .foo + 2
diff --git a/test/ELF/merge-gc-piece2.s b/test/ELF/merge-gc-piece2.s
new file mode 100644
index 000000000000..88e0904caf2e
--- /dev/null
+++ b/test/ELF/merge-gc-piece2.s
@@ -0,0 +1,27 @@
+# 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 --gc-sections
+# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 01000000 00000000 02000000 00000000
+# CHECK-NEXT: )
+
+ .section .foo,"aM",@progbits,8
+ .quad 42
+ .quad 43
+
+ .section .bar
+ .quad .foo + 1
+ .quad .foo + 2
diff --git a/test/ELF/merge-reloc-O0.s b/test/ELF/merge-reloc-O0.s
new file mode 100644
index 000000000000..daf5c34b6c0a
--- /dev/null
+++ b/test/ELF/merge-reloc-O0.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -r -o %t2.o -O0
+# RUN: llvm-readobj -s -section-data %t2.o | FileCheck %s
+
+# We combine just the sections with the same name and sh_entsize.
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment: 8
+# CHECK-NEXT: EntrySize: 8
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 41000000 00000000 42000000 00000000
+# CHECK-NEXT: )
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 4
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 41000000 42000000
+# CHECK-NEXT: )
+
+ .section .foo, "aM",@progbits,8,unique,0
+ .quad 0x41
+ .section .foo, "aM",@progbits,8,unique,1
+ .quad 0x42
+ .section .foo, "aM",@progbits,4,unique,2
+ .long 0x41
+ .long 0x42
diff --git a/test/ELF/merge-shared-str.s b/test/ELF/merge-shared-str.s
index 2ab03a4d66ab..7502eb93ab36 100644
--- a/test/ELF/merge-shared-str.s
+++ b/test/ELF/merge-shared-str.s
@@ -19,10 +19,10 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x228
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1C9
+// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x229
// CHECK-NEXT: }
// CHECK-NEXT: ]
diff --git a/test/ELF/merge-shared.s b/test/ELF/merge-shared.s
index 4c1d7c06a0ba..6615169f1ecd 100644
--- a/test/ELF/merge-shared.s
+++ b/test/ELF/merge-shared.s
@@ -17,10 +17,10 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x228
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1CA
+// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x22A
// CHECK-NEXT: }
// CHECK-NEXT: ]
diff --git a/test/ELF/merge-string-empty.s b/test/ELF/merge-string-empty.s
index 0b82ce700a2c..dc6635c96123 100644
--- a/test/ELF/merge-string-empty.s
+++ b/test/ELF/merge-string-empty.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// Ensure that a mergeable string with size 0 does not cause any issue.
-// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: ld.lld %t.o -o %t
+// RUN: ld.lld %t.o -o /dev/null
.globl _start, s
.section .rodata.str1.1,"aMS",@progbits,1
diff --git a/test/ELF/merge-string-error.s b/test/ELF/merge-string-error.s
index 78895cecca9c..70a361b6ccde 100644
--- a/test/ELF/merge-string-error.s
+++ b/test/ELF/merge-string-error.s
@@ -1,6 +1,6 @@
// 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
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
.section .rodata.str1.1,"aMS",@progbits,1
.asciz "abc"
diff --git a/test/ELF/merge-string-no-null.s b/test/ELF/merge-string-no-null.s
index fd3f5073810a..ea433fec7d46 100644
--- a/test/ELF/merge-string-no-null.s
+++ b/test/ELF/merge-string-no-null.s
@@ -1,6 +1,6 @@
// 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
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
.section .rodata.str1.1,"aMS",@progbits,1
.ascii "abc"
diff --git a/test/ELF/merge-string.s b/test/ELF/merge-string.s
index d284d0ab523c..065e8003840a 100644
--- a/test/ELF/merge-string.s
+++ b/test/ELF/merge-string.s
@@ -28,8 +28,8 @@ zed:
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
-// CHECK-NEXT: Offset: 0x1C8
+// CHECK-NEXT: Address: 0x20D
+// CHECK-NEXT: Offset: 0x20D
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -46,8 +46,8 @@ zed:
// NOTAIL-NEXT: SHF_MERGE
// NOTAIL-NEXT: SHF_STRINGS
// NOTAIL-NEXT: ]
-// NOTAIL-NEXT: Address: 0x1C8
-// NOTAIL-NEXT: Offset: 0x1C8
+// NOTAIL-NEXT: Address: 0x20D
+// NOTAIL-NEXT: Offset: 0x20D
// NOTAIL-NEXT: Size: 7
// NOTAIL-NEXT: Link: 0
// NOTAIL-NEXT: Info: 0
@@ -64,8 +64,8 @@ zed:
// NOMERGE-NEXT: SHF_MERGE
// NOMERGE-NEXT: SHF_STRINGS
// NOMERGE-NEXT: ]
-// NOMERGE-NEXT: Address: 0x1C8
-// NOMERGE-NEXT: Offset: 0x1C8
+// NOMERGE-NEXT: Address: 0x20D
+// NOMERGE-NEXT: Offset: 0x20D
// NOMERGE-NEXT: Size: 11
// NOMERGE-NEXT: Link: 0
// NOMERGE-NEXT: Info: 0
@@ -82,8 +82,8 @@ zed:
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1CC
-// CHECK-NEXT: Offset: 0x1CC
+// CHECK-NEXT: Address: 0x212
+// CHECK-NEXT: Offset: 0x212
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -95,11 +95,11 @@ zed:
// CHECK: Name: bar
-// CHECK-NEXT: Value: 0x1C9
+// CHECK-NEXT: Value: 0x20E
// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x1C8
+// CHECK-NEXT: Value: 0x20D
// CHECK: Name: zed
-// CHECK-NEXT: Value: 0x1CC
+// CHECK-NEXT: Value: 0x212
// CHECK-NEXT: Size: 0
diff --git a/test/ELF/merge-sym.s b/test/ELF/merge-sym.s
index 4a4e9824a0de..89becc85531c 100644
--- a/test/ELF/merge-sym.s
+++ b/test/ELF/merge-sym.s
@@ -15,7 +15,7 @@ foo:
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x210
// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x1CA
+// CHECK-NEXT: Value: 0x212
diff --git a/test/ELF/merge-to-non-alloc.s b/test/ELF/merge-to-non-alloc.s
new file mode 100644
index 000000000000..86f6f260814b
--- /dev/null
+++ b/test/ELF/merge-to-non-alloc.s
@@ -0,0 +1,33 @@
+// 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 %t.so | FileCheck %s
+
+// CHECK: Name: .bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 10020000 00000000 18020000 00000000 |
+// CHECK-NEXT: )
+
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x210
+
+ .section .foo,"aM",@progbits,4
+ .align 4
+ .global foo
+ .hidden foo
+foo:
+ .long 0x42
+
+ .section .bar
+ .quad foo
+ .quad foo + 8
diff --git a/test/ELF/mips-26-mask.s b/test/ELF/mips-26-mask.s
index 4cf56cfe338c..874d5c4b2338 100644
--- a/test/ELF/mips-26-mask.s
+++ b/test/ELF/mips-26-mask.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# Check reading/writing implicit addend for R_MIPS_26 relocation.
# 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.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Disassembly of section .text:
# CHECK: __start:
# CHECK-NEXT: 20000: 0e 00 80 00 jal 134348800
diff --git a/test/ELF/mips-26-n32-n64.s b/test/ELF/mips-26-n32-n64.s
index 2e24873332a7..92f533152da3 100644
--- a/test/ELF/mips-26-n32-n64.s
+++ b/test/ELF/mips-26-n32-n64.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_26 relocation handling in case of N64 ABIs.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
@@ -5,9 +6,11 @@
# RUN: ld.lld %t-so.o -shared -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 %t.exe | FileCheck %s
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,DEFAULT
+# RUN: ld.lld %t-so.o -shared -o %t.so -z hazardplt
+# RUN: ld.lld %t.o %t.so -o %t.exe -z hazardplt
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,HAZARDPLT
-# REQUIRES: mips
# CHECK: Disassembly of section .text:
# CHECK-NEXT: __start:
@@ -21,11 +24,13 @@
# CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14
# CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra
# CHECK-NEXT: 20024: 00 18 c0 c2 srl $24, $24, 3
-# CHECK-NEXT: 20028: 03 20 f8 09 jalr $25
+# DEFAULT: 20028: 03 20 f8 09 jalr $25
+# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25
# CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2
# CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3
# CHECK-NEXT: 20034: 8d f9 00 18 lw $25, 24($15)
-# CHECK-NEXT: 20038: 03 20 00 08 jr $25
+# DEFAULT: 20038: 03 20 00 08 jr $25
+# HAZARDPLT: 20038: 03 20 04 08 jr.hb $25
# CHECK-NEXT: 2003c: 25 f8 00 18 addiu $24, $15, 24
.text
diff --git a/test/ELF/mips-26.s b/test/ELF/mips-26.s
index 749920b88c8b..882129b1fa9e 100644
--- a/test/ELF/mips-26.s
+++ b/test/ELF/mips-26.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_26 relocation handling.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
@@ -9,8 +10,6 @@
# 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>
diff --git a/test/ELF/mips-32.s b/test/ELF/mips-32.s
index ef97afcc0313..7efcfcd65167 100644
--- a/test/ELF/mips-32.s
+++ b/test/ELF/mips-32.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_32 relocation calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
@@ -14,8 +15,6 @@
# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-el.so \
# RUN: | FileCheck -check-prefix=REL %s
-# REQUIRES: mips
-
.globl __start
__start:
nop
diff --git a/test/ELF/mips-64-disp.s b/test/ELF/mips-64-disp.s
index 29b62dcd050a..5d5049c4cae7 100644
--- a/test/ELF/mips-64-disp.s
+++ b/test/ELF/mips-64-disp.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_GOT_DISP relocations against various kind of symbols.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
@@ -8,8 +9,6 @@
# 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
diff --git a/test/ELF/mips-64-got-overflow.s b/test/ELF/mips-64-got-overflow.s
new file mode 100644
index 000000000000..5de71b1b366e
--- /dev/null
+++ b/test/ELF/mips-64-got-overflow.s
@@ -0,0 +1,80 @@
+# REQUIRES: mips
+# Check the primary GOT cannot be made to overflow
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: %p/Inputs/mips-64-got-load.s -o %t1.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t2.so.o
+# RUN: ld.lld -shared -mips-got-size 32 %t1.so.o %t2.so.o -o %t-sgot.so
+# RUN: ld.lld -shared -mips-got-size 24 %t1.so.o %t2.so.o -o %t-mgot.so
+# RUN: llvm-readobj -r -dt -mips-plt-got %t-sgot.so | FileCheck -check-prefix=SGOT %s
+# RUN: llvm-readobj -r -dt -mips-plt-got %t-mgot.so | FileCheck -check-prefix=MGOT %s
+
+# SGOT: Primary GOT {
+# SGOT-NEXT: Canonical gp value: 0x27FF0
+# SGOT-NEXT: Reserved entries [
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32752
+# SGOT-NEXT: Initial: 0x0
+# SGOT-NEXT: Purpose: Lazy resolver
+# SGOT-NEXT: }
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32744
+# SGOT-NEXT: Initial: 0x80000000
+# SGOT-NEXT: Purpose: Module pointer (GNU extension)
+# SGOT-NEXT: }
+# SGOT-NEXT: ]
+# SGOT-NEXT: Local entries [
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32736
+# SGOT-NEXT: Initial: 0x20020
+# SGOT-NEXT: }
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32728
+# SGOT-NEXT: Initial: 0x20030
+# SGOT-NEXT: }
+# SGOT-NEXT: ]
+# SGOT-NEXT: Global entries [
+# SGOT-NEXT: ]
+# SGOT-NEXT: Number of TLS and multi-GOT entries: 0
+# SGOT-NEXT: }
+
+# MGOT: Primary GOT {
+# MGOT-NEXT: Canonical gp value: 0x27FF0
+# MGOT-NEXT: Reserved entries [
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32752
+# MGOT-NEXT: Initial: 0x0
+# MGOT-NEXT: Purpose: Lazy resolver
+# MGOT-NEXT: }
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32744
+# MGOT-NEXT: Initial: 0x80000000
+# MGOT-NEXT: Purpose: Module pointer (GNU extension)
+# MGOT-NEXT: }
+# MGOT-NEXT: ]
+# MGOT-NEXT: Local entries [
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32736
+# MGOT-NEXT: Initial: 0x20020
+# MGOT-NEXT: }
+# MGOT-NEXT: ]
+# MGOT-NEXT: Global entries [
+# MGOT-NEXT: ]
+# MGOT-NEXT: Number of TLS and multi-GOT entries: 1
+# MGOT-NEXT: }
+
+ .text
+ .global foo2
+foo2:
+ ld $2, %got_disp(local2)($gp)
+
+ .bss
+local2:
+ .word 0
diff --git a/test/ELF/mips-64-got.s b/test/ELF/mips-64-got.s
index f2b4d5b07ab5..e1b1f3475470 100644
--- a/test/ELF/mips-64-got.s
+++ b/test/ELF/mips-64-got.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS N64 ABI GOT relocations
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
@@ -8,8 +9,6 @@
# 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)
diff --git a/test/ELF/mips-64-gprel-so.s b/test/ELF/mips-64-gprel-so.s
index 437238ef5f26..d741dd907137 100644
--- a/test/ELF/mips-64-gprel-so.s
+++ b/test/ELF/mips-64-gprel-so.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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
diff --git a/test/ELF/mips-64-rels.s b/test/ELF/mips-64-rels.s
index 78671554b1cb..e641b326ce56 100644
--- a/test/ELF/mips-64-rels.s
+++ b/test/ELF/mips-64-rels.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check handling multiple MIPS N64 ABI relocations packed
# into the single relocation record.
@@ -6,8 +7,6 @@
# 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
diff --git a/test/ELF/mips-64.s b/test/ELF/mips-64.s
index dd8a58d604c5..e37b75c070ec 100644
--- a/test/ELF/mips-64.s
+++ b/test/ELF/mips-64.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_64 relocation calculation.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
@@ -5,8 +6,6 @@
# 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
@@ -30,17 +29,16 @@ v2:
# SYM: 00020008 g .data 00000008 v2
# CHECK: Relocations [
-# CHECK-NEXT: Section (7) .rela.dyn {
-# CHECK-NEXT: 0x20010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x20000
-# ^-- v1
-# CHECK-NEXT: 0x20008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x8
+# CHECK-NEXT: Section (7) .rel.dyn {
+# CHECK-NEXT: 0x20010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x0
+# CHECK-NEXT: 0x20008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK: DynamicSection [
# CHECK: Tag Type Name/Value
-# CHECK: 0x0000000000000008 RELASZ 48 (bytes)
-# CHECK: 0x0000000000000009 RELAENT 24 (bytes)
+# CHECK: 0x0000000000000012 RELSZ 32 (bytes)
+# CHECK: 0x0000000000000013 RELENT 16 (bytes)
# CHECK: Primary GOT {
# CHECK-NEXT: Canonical gp value:
diff --git a/test/ELF/mips-abs-got.s b/test/ELF/mips-abs-got.s
new file mode 100644
index 000000000000..4964c8558325
--- /dev/null
+++ b/test/ELF/mips-abs-got.s
@@ -0,0 +1,36 @@
+# REQUIRES: mips
+
+# Check GOT relocations against absolute symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s
+# RUN: echo "SECTIONS { \
+# RUN: zero = 0; foo = 0x11004; bar = 0x22000; }" > %t.script
+# RUN: ld.lld --script %t.script -o %t.exe %t.o
+# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
+
+# CHECK: Static GOT {
+# CHECK: Local entries [
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32736
+# CHECK-NEXT: Initial: 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32728
+# CHECK-NEXT: Initial: 0x10000
+# CHECK-NEXT: }
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32720
+# CHECK-NEXT: Initial: 0x30000
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+
+ .text
+ nop
+ .reloc 0, R_MIPS_GOT_PAGE, 0
+ ld $v0, %got_page(zero)($gp)
+ ld $v0, %got_page(foo)($gp)
+ ld $v0, %got_page(bar+0x10008)($gp)
diff --git a/test/ELF/mips-align-err.s b/test/ELF/mips-align-err.s
index a3bf134e4386..8bf01dc5c382 100644
--- a/test/ELF/mips-align-err.s
+++ b/test/ELF/mips-align-err.s
@@ -3,7 +3,7 @@
# 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
+# RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: {{.*}}:(.text+0x1): improper alignment for relocation R_MIPS_PC16: 0xB is not aligned to 4 bytes
.globl __start
diff --git a/test/ELF/mips-call-hilo.s b/test/ELF/mips-call-hilo.s
index 2504612f9e34..9c7633a8464d 100644
--- a/test/ELF/mips-call-hilo.s
+++ b/test/ELF/mips-call-hilo.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_CALL_HI16 / R_MIPS_CALL_LO16 relocations calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -5,8 +6,6 @@
# RUN: llvm-objdump -d %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: foo:
# CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0
diff --git a/test/ELF/mips-call16.s b/test/ELF/mips-call16.s
index 4a5d0bf3f871..7b3da0c41ff0 100644
--- a/test/ELF/mips-call16.s
+++ b/test/ELF/mips-call16.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_CALL16 relocation calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -6,8 +7,6 @@
# RUN: llvm-readobj -mips-plt-got -symbols %t.exe \
# RUN: | FileCheck -check-prefix=GOT %s
-# REQUIRES: mips
-
.text
.globl __start
__start:
diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s
index 15afb028c1f1..ebc2625970cb 100644
--- a/test/ELF/mips-dynamic.s
+++ b/test/ELF/mips-dynamic.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS specific .dynamic section entries.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -6,7 +7,11 @@
# 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: | FileCheck -check-prefixes=EXE,NOPIE %s
+
+# RUN: ld.lld -pie %t.o %td.so -o %t.so
+# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \
+# RUN: | FileCheck -check-prefixes=EXE,PIE %s
# RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe
# RUN: llvm-readobj -sections -dynamic-table %t.exe \
@@ -16,8 +21,6 @@
# 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
@@ -44,17 +47,35 @@
# EXE-NEXT: Offset:
# EXE-NEXT: Size: 8
# 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: ]
+
+# PIE: DynamicSection [
+# PIE-NEXT: Tag Type Name/Value
+# PIE: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# PIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# PIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# PIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x0
+# PIE-NEXT: 0x70000011 MIPS_SYMTABNO 2
+# PIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# PIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# PIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]]
+# PIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}}
+# PIE-NEXT: 0x00000000 NULL 0x0
+# PIE-NEXT: ]
+
+# NOPIE: DynamicSection [
+# NOPIE-NEXT: Tag Type Name/Value
+# NOPIE: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# NOPIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# NOPIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# NOPIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x10000
+# NOPIE-NEXT: 0x70000011 MIPS_SYMTABNO 2
+# NOPIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# NOPIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# NOPIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]]
+# NOPIE-NEXT: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]]
+# NOPIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}}
+# NOPIE-NEXT: 0x00000000 NULL 0x0
+# NOPIE-NEXT: ]
# IMAGE_BASE: 0x70000006 MIPS_BASE_ADDRESS 0x123000
diff --git a/test/ELF/mips-dynsym-sort.s b/test/ELF/mips-dynsym-sort.s
index 7d4559cf9335..d1b935b63cff 100644
--- a/test/ELF/mips-dynsym-sort.s
+++ b/test/ELF/mips-dynsym-sort.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check the order of dynamic symbols for the MIPS target.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
@@ -8,8 +9,6 @@
# 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:
diff --git a/test/ELF/mips-elf-abi.s b/test/ELF/mips-elf-abi.s
new file mode 100644
index 000000000000..86c02f34f6a5
--- /dev/null
+++ b/test/ELF/mips-elf-abi.s
@@ -0,0 +1,22 @@
+# REQUIRES: mips
+# Check EI_ABIVERSION flags
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-readobj -h %t.so | FileCheck -check-prefix=DSO %s
+# RUN: ld.lld -o %t.exe %t.o
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: ld.lld -pie -o %t.pie %t.o
+# RUN: llvm-readobj -h %t.pie | FileCheck -check-prefix=PIE %s
+# RUN: ld.lld -r -o %t.rel %t.o
+# RUN: llvm-readobj -h %t.rel | FileCheck -check-prefix=REL %s
+
+# DSO: ABIVersion: 0
+# EXE: ABIVersion: 1
+# PIE: ABIVersion: 0
+# REL: ABIVersion: 0
+
+ .global __start
+ .text
+__start:
+ nop
diff --git a/test/ELF/mips-elf-flags-err.s b/test/ELF/mips-elf-flags-err.s
index e1ac8c5e015e..caa33ab28c7a 100644
--- a/test/ELF/mips-elf-flags-err.s
+++ b/test/ELF/mips-elf-flags-err.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS ELF ISA flag calculation if input files have different ISAs.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -24,14 +25,6 @@
# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 \
# RUN: | FileCheck -check-prefix=R6OCTEON %s
-# Check that lld does not allow to link incompatible floating point ABI.
-
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -mcpu=mips32 -mattr=+fp64 %s -o %t2.o
-# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=FPABI %s
-
# Check that lld take in account EF_MIPS_MACH_XXX ISA flags
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
@@ -41,24 +34,6 @@
# RUN: ld.lld %t1.o %t2.o -o %t.exe
# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=OCTEON %s
-# Check that lld does not allow to link incompatible ABIs.
-
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -target-abi n32 %S/Inputs/mips-dynamic.s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -target-abi o32 %s -o %t2.o
-# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=N32O32 %s
-
-# Check that lld does not allow to link modules with incompatible NAN flags.
-
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -mattr=+nan2008 %S/Inputs/mips-dynamic.s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: %s -o %t2.o
-# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=NAN %s
-
-# REQUIRES: mips
-
.option pic0
.text
.global __start
@@ -79,14 +54,8 @@ __start:
# R6OCTEON-NEXT: >>> {{.+}}mips-elf-flags-err.s.tmp1.o: mips64r6
# R6OCTEON-NEXT: >>> {{.+}}mips-elf-flags-err.s.tmp2.o: mips64r2 (octeon)
-# FPABI: target floating point ABI '-mdouble-float' is incompatible with '-mgp32 -mfp64': {{.*}}mips-elf-flags-err.s.tmp2.o
-
# OCTEON: Flags [
# OCTEON-NEXT: EF_MIPS_ARCH_64R2
# OCTEON-NEXT: EF_MIPS_CPIC
# OCTEON-NEXT: EF_MIPS_MACH_OCTEON
# OCTEON: ]
-
-# N32O32: error: {{.*}}mips-elf-flags-err.s.tmp2.o is incompatible with {{.*}}mips-elf-flags-err.s.tmp1.o
-
-# NAN: target -mnan=2008 is incompatible with -mnan=legacy: {{.*}}mips-elf-flags-err.s.tmp2.o
diff --git a/test/ELF/mips-elf-flags-err.test b/test/ELF/mips-elf-flags-err.test
new file mode 100644
index 000000000000..12fd418274ce
--- /dev/null
+++ b/test/ELF/mips-elf-flags-err.test
@@ -0,0 +1,89 @@
+# REQUIRES: mips
+#
+# Check warning and errors in case of input
+# files with incompatible ELF header flags.
+
+# RUN: yaml2obj -docnum 1 %s -o %t-n64.o
+# RUN: yaml2obj -docnum 2 %s -o %t-o64.o
+# RUN: yaml2obj -docnum 3 %s -o %t-n32.o
+# RUN: yaml2obj -docnum 4 %s -o %t-o32.o
+# RUN: yaml2obj -docnum 5 %s -o %t-eabi64.o
+# RUN: yaml2obj -docnum 6 %s -o %t-eabi32.o
+
+# RUN: not ld.lld %t-n64.o %t-eabi64.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=MM64,N64EABI64 %s
+#
+# RUN: not ld.lld %t-n64.o %t-o64.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=MM64,N64O64 %s
+
+# RUN: not ld.lld %t-o32.o %t-eabi32.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=O32EABI32,FP64,CPIC1 %s
+
+# RUN: not ld.lld %t-eabi32.o %t-o32.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefix=CPIC2 %s
+
+# MM64: {{.*}}n64.o: microMIPS 64-bit is not supported
+
+# N64EABI64: {{.*}}eabi64.o: ABI 'eabi64' is incompatible with target ABI 'n64'
+# N64O64: {{.*}}o64.o: ABI 'o64' is incompatible with target ABI 'n64'
+# O32EABI32: {{.*}}eabi32.o: ABI 'eabi32' is incompatible with target ABI 'o32'
+
+# NAN: {{.*}}o32.o: -mnan=legacy is incompatible with target -mnan=2008
+# FP64: {{.*}}eabi32.o: -mfp64 is incompatible with target -mfp32
+
+# CPIC1: {{.*}}tmp-eabi32.o: linking non-abicalls code with abicalls code {{.*}}o32.o
+# CPIC2: {{.*}}tmp-o32.o: linking abicalls code with non-abicalls code {{.*}}eabi32.o
+
+# n64.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64, EF_MIPS_MICROMIPS ]
+
+# o64.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O64, EF_MIPS_ARCH_64 ]
+
+# n32.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64, EF_MIPS_ABI2, EF_MIPS_NAN2008 ]
+
+# o32.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_32, EF_MIPS_ABI_O32, EF_MIPS_CPIC ]
+
+# eabi64.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64, EF_MIPS_ABI_EABI64 ]
+
+# eabi32.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_32, EF_MIPS_ABI_EABI32, EF_MIPS_FP64 ]
diff --git a/test/ELF/mips-elf-flags.s b/test/ELF/mips-elf-flags.s
index d2b3d929e2f5..68f4cc3008e4 100644
--- a/test/ELF/mips-elf-flags.s
+++ b/test/ELF/mips-elf-flags.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check generation of MIPS specific ELF header flags.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -41,8 +42,6 @@
# RUN: ld.lld %t.o %t-mm.o -o %t.exe
# RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s
-# REQUIRES: mips
-
.text
.globl __start
__start:
diff --git a/test/ELF/mips-fp-flags-err.test b/test/ELF/mips-fp-flags-err.test
new file mode 100644
index 000000000000..68a290c2caa1
--- /dev/null
+++ b/test/ELF/mips-fp-flags-err.test
@@ -0,0 +1,162 @@
+# REQUIRES: mips
+#
+# Check warning and errors in case of input
+# files with incompatible floating point ABI flags.
+
+# RUN: yaml2obj -docnum 1 %s -o %t-dbl.o
+# RUN: yaml2obj -docnum 2 %s -o %t-sgl.o
+# RUN: yaml2obj -docnum 3 %s -o %t-soft.o
+# RUN: yaml2obj -docnum 4 %s -o %t-fp64.o
+# RUN: yaml2obj -docnum 5 %s -o %t-fp64old.o
+# RUN: yaml2obj -docnum 6 %s -o %t-fp64a.o
+# RUN: yaml2obj -docnum 7 %s -o %t-fpxx.o
+
+# RUN: not ld.lld %t-dbl.o %t-fp64.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=DBLFP64 %s
+
+# RUN: not ld.lld %t-sgl.o %t-fp64old.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=SGLFP64OLD %s
+
+# RUN: not ld.lld %t-soft.o %t-fp64a.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=SOFTFP64A %s
+
+# RUN: not ld.lld %t-sgl.o %t-fpxx.o -shared -o /dev/null 2>&1 \
+# RUN: | FileCheck -check-prefixes=SGLFPXX %s
+
+# DBLFP64: {{.*}}fp64.o: floating point ABI '-mgp32 -mfp64' is incompatible with target floating point ABI '-mdouble-float'
+# SGLFP64OLD: {{.*}}fp64old.o: floating point ABI '-mgp32 -mfp64 (old)' is incompatible with target floating point ABI '-msingle-float'
+# SOFTFP64A: {{.*}}fp64a.o: floating point ABI '-mgp32 -mfp64 -mno-odd-spreg' is incompatible with target floating point ABI '-msoft-float'
+# SGLFPXX: {{.*}}fpxx.o: floating point ABI '-mfpxx' is incompatible with target floating point ABI '-msingle-float'
+
+# dbl.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_DOUBLE
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# sgl.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_SINGLE
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# soft.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_SOFT
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# fp64.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_64
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# fp64old.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_OLD_64
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# fp64a.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_64A
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
+
+# fpxx.o
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64 ]
+
+Sections:
+- Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ ISA: MIPS64
+ ASEs: []
+ FpABI: FP_XX
+ GPRSize: REG_64
+ CPR1Size: REG_64
+ CPR2Size: REG_NONE
diff --git a/test/ELF/mips-gnu-hash.s b/test/ELF/mips-gnu-hash.s
index 288d54043fc1..e66bc893a076 100644
--- a/test/ELF/mips-gnu-hash.s
+++ b/test/ELF/mips-gnu-hash.s
@@ -1,15 +1,14 @@
+# REQUIRES: mips
# 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: not ld.lld -shared -hash-style=gnu %t-be.o -o /dev/null 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
+# RUN: not ld.lld -shared -hash-style=gnu %t-el.o -o /dev/null 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
index 4e3ca5f2804a..f4640bf30dfa 100644
--- a/test/ELF/mips-got-and-copy.s
+++ b/test/ELF/mips-got-and-copy.s
@@ -23,13 +23,17 @@
# CHECK-NEXT: Reserved entries [
# CHECK: ]
# CHECK-NEXT: Local entries [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Global entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32744
# CHECK-NEXT: Initial: 0x[[DATA0]]
+# CHECK-NEXT: Value: 0x[[DATA0]]
+# CHECK-NEXT: Type: Object
+# CHECK-NEXT: Section: .bss
+# CHECK-NEXT: Name: data0@
# CHECK-NEXT: }
-# CHECK-NEXT: ]
-# CHECK-NEXT: Global entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32740
diff --git a/test/ELF/mips-got-extsym.s b/test/ELF/mips-got-extsym.s
index 3af4ba07b234..ea57d77a0353 100644
--- a/test/ELF/mips-got-extsym.s
+++ b/test/ELF/mips-got-extsym.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# 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
@@ -10,8 +11,6 @@
# 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
diff --git a/test/ELF/mips-got-hilo.s b/test/ELF/mips-got-hilo.s
index fa7e752d9f91..1ae24f3472fe 100644
--- a/test/ELF/mips-got-hilo.s
+++ b/test/ELF/mips-got-hilo.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_GOT_HI16 / R_MIPS_GOT_LO16 relocations calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -5,8 +6,6 @@
# RUN: llvm-objdump -d %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: foo:
# CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0
diff --git a/test/ELF/mips-got-page-script.s b/test/ELF/mips-got-page-script.s
index 056e4fda77c2..0ec19fc14ad4 100644
--- a/test/ELF/mips-got-page-script.s
+++ b/test/ELF/mips-got-page-script.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check calculation of MIPS GOT page address entries number
# when a linker script is provided.
@@ -8,8 +9,6 @@
# RUN: ld.lld -shared --script %t.script -o %t.so %t.o
# RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Name: foo1
# CHECK-NEXT: Value: 0x10000
# CHECK: Name: foo2
diff --git a/test/ELF/mips-got-page.s b/test/ELF/mips-got-page.s
index e2dc485ba661..46ddf4a7122c 100644
--- a/test/ELF/mips-got-page.s
+++ b/test/ELF/mips-got-page.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check the case when small section (less that 0x10000 bytes) occupies
# two adjacent 0xffff-bytes pages. We need to create two GOT entries
# for R_MIPS_GOT_PAGE relocations.
@@ -6,8 +7,6 @@
# RUN: ld.lld --section-start .rodata=0x27FFC -shared -o %t.so %t.o
# RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Name: bar
# CHECK-NEXT: Value: 0x28000
# ^ page-address = (0x28000 + 0x8000) & ~0xffff = 0x30000
diff --git a/test/ELF/mips-got-redundant.s b/test/ELF/mips-got-redundant.s
index b4c6a2b31a0e..24138ca19995 100644
--- a/test/ELF/mips-got-redundant.s
+++ b/test/ELF/mips-got-redundant.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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:
diff --git a/test/ELF/mips-got-relocs.s b/test/ELF/mips-got-relocs.s
index 5b443e51938a..d085df06524a 100644
--- a/test/ELF/mips-got-relocs.s
+++ b/test/ELF/mips-got-relocs.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_GOT16 relocation calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
@@ -30,8 +31,6 @@
# 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:
diff --git a/test/ELF/mips-got-script.s b/test/ELF/mips-got-script.s
index da1858469863..6590c59e1cda 100644
--- a/test/ELF/mips-got-script.s
+++ b/test/ELF/mips-got-script.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check number of got entries is adjusted for linker script-added space.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -5,10 +6,8 @@
# RUN: ld.lld %t.o -shared -o %t.so -T %t.script
# RUN: llvm-readobj -mips-plt-got -dynamic-table %t.so | FileCheck %s
-# REQUIRES: mips
-
-# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 5
-# ^-- 2 * header + 3 local entries
+# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4
+# ^-- 2 * header + 2 local entries
# CHECK: Local entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
@@ -22,12 +21,6 @@
# CHECK-NEXT: Initial: 0x10000
# ^-- loc2
# CHECK-NEXT: }
-# CHECK-NEXT: Entry {
-# CHECK-NEXT: Address:
-# CHECK-NEXT: Access: -32736
-# CHECK-NEXT: Initial: 0x20000
-# ^-- redundant
-# CHECK-NEXT: }
# CHECK-NEXT: ]
.text
diff --git a/test/ELF/mips-got-string.s b/test/ELF/mips-got-string.s
index 598865c681f6..cfdd0daf68dd 100644
--- a/test/ELF/mips-got-string.s
+++ b/test/ELF/mips-got-string.s
@@ -1,14 +1,13 @@
+# REQUIRES: mips
# Check R_MIPS_GOT16 relocation against merge section.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s
# RUN: ld.lld -shared -o %t.so %t.o
# RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Symbol {
# CHECK: Name: $.str
-# CHECK-NEXT: Value: 0xF4
+# CHECK-NEXT: Value: 0x1B1
# CHECK: }
# CHECK: Local entries [
diff --git a/test/ELF/mips-got-weak.s b/test/ELF/mips-got-weak.s
index e860bb482a2c..478e294f02f3 100644
--- a/test/ELF/mips-got-weak.s
+++ b/test/ELF/mips-got-weak.s
@@ -1,17 +1,16 @@
+# REQUIRES: mips
# 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: | FileCheck -check-prefixes=CHECK,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
+# RUN: | FileCheck -check-prefixes=CHECK,SYM %s
-# NOSYM: Relocations [
-# NOSYM-NEXT: ]
+# CHECK: Relocations [
+# CHECK-NEXT: ]
# NOSYM: Symbol {
# NOSYM: Name: foo
@@ -22,17 +21,19 @@
# 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
+
+# CHECK: Symbol {
+# CHECK: Name: bar
+# 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: }
+
+# NOSYM: Symbol {
+# NOSYM: Name: sym
# NOSYM-NEXT: Value: 0x20004
# NOSYM-NEXT: Size: 0
# NOSYM-NEXT: Binding: Global
@@ -40,30 +41,48 @@
# 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
+# CHECK: 0x70000011 MIPS_SYMTABNO 4
-# NOSYM: Primary GOT {
-# NOSYM-NEXT: Canonical gp value:
-# NOSYM-NEXT: Reserved entries [
-# NOSYM-NEXT: Entry {
-# NOSYM-NEXT: Address:
-# NOSYM-NEXT: Access: -32752
-# NOSYM-NEXT: Initial: 0x0
-# NOSYM-NEXT: Purpose: Lazy resolver
-# NOSYM-NEXT: }
-# NOSYM-NEXT: Entry {
-# NOSYM-NEXT: Address:
-# NOSYM-NEXT: Access: -32748
-# NOSYM-NEXT: Initial: 0x80000000
-# NOSYM-NEXT: Purpose: Module pointer (GNU extension)
-# NOSYM-NEXT: }
-# NOSYM-NEXT: ]
-# NOSYM-NEXT: Local entries [
+# SYM: 0x7000000A MIPS_LOCAL_GOTNO 4
+# SYM: 0x70000013 MIPS_GOTSYM 0x3
+
+# NOSYM: 0x7000000A MIPS_LOCAL_GOTNO 2
+# NOSYM: 0x70000013 MIPS_GOTSYM 0x1
+
+# CHECK: Primary GOT {
+# CHECK-NEXT: Canonical gp value:
+# CHECK-NEXT: Reserved entries [
+# CHECK: ]
+
+# SYM: Local entries [
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# SYM-NEXT: Access: -32744
+# SYM-NEXT: Initial: 0x20000
+# SYM-NEXT: }
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# SYM-NEXT: Access: -32740
+# SYM-NEXT: Initial: 0x20004
+# SYM-NEXT: }
+# SYM-NEXT: ]
+
+# NOSYM: Local entries [
# NOSYM-NEXT: ]
+
+# SYM-NEXT: Global entries [
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# 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: ]
+
# NOSYM-NEXT: Global entries [
# NOSYM-NEXT: Entry {
# NOSYM-NEXT: Address:
@@ -93,68 +112,9 @@
# 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:
-# SYM-NEXT: Reserved entries [
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32752
-# SYM-NEXT: Initial: 0x0
-# SYM-NEXT: Purpose: Lazy resolver
-# SYM-NEXT: }
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# 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:
-# SYM-NEXT: Access: -32744
-# SYM-NEXT: Initial: 0x20000
-# SYM-NEXT: }
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32740
-# SYM-NEXT: Initial: 0x20004
-# SYM-NEXT: }
-# SYM-NEXT: ]
-# SYM-NEXT: Global entries [
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# 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: }
+
+# CHECK: Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
.text
.global sym
diff --git a/test/ELF/mips-got16-relocatable.s b/test/ELF/mips-got16-relocatable.s
index bbacfdbaa682..04b7cbb8e904 100644
--- a/test/ELF/mips-got16-relocatable.s
+++ b/test/ELF/mips-got16-relocatable.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check writing updated addend for R_MIPS_GOT16 relocation,
# when produce a relocatable output.
@@ -7,8 +8,6 @@
# RUN: ld.lld -shared -o %t.so %t
# RUN: llvm-objdump -d %t.so | FileCheck -check-prefix=SO %s
-# REQUIRES: mips
-
# OBJ: Disassembly of section .text:
# OBJ-NEXT: .text:
# OBJ-NEXT: 0: 8f 99 00 00 lw $25, 0($gp)
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
index 6ad7b2b0d46e..cf0847da53d3 100644
--- a/test/ELF/mips-got16.s
+++ b/test/ELF/mips-got16.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_GOT16 relocation calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
@@ -5,8 +6,6 @@
# 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)
diff --git a/test/ELF/mips-gp-disp-ver.s b/test/ELF/mips-gp-disp-ver.s
new file mode 100644
index 000000000000..8eaee19daf19
--- /dev/null
+++ b/test/ELF/mips-gp-disp-ver.s
@@ -0,0 +1,14 @@
+# REQUIRES: mips
+# MIPS BFD linker puts _gp_disp symbol into DSO files and assigns zero
+# version definition index to it. This value means 'unversioned local symbol'
+# while _gp_disp is a section global symbol. We have to handle this bug
+# in the LLD because BFD linker is used for building MIPS toolchain
+# libraries. This test checks such handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %S/Inputs/mips-gp-dips-corrupt-ver.so
+
+ .global __start
+ .text
+__start:
+ lw $t0, %got(foo)($gp)
diff --git a/test/ELF/mips-gp-disp.s b/test/ELF/mips-gp-disp.s
index 7a0fd6409d18..1b4226d6022b 100644
--- a/test/ELF/mips-gp-disp.s
+++ b/test/ELF/mips-gp-disp.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check that even if _gp_disp symbol is defined in the shared library
# we use our own value.
@@ -9,8 +10,6 @@
# 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:
diff --git a/test/ELF/mips-gp-ext.s b/test/ELF/mips-gp-ext.s
index 2fd21b7a9818..9f12f1313166 100644
--- a/test/ELF/mips-gp-ext.s
+++ b/test/ELF/mips-gp-ext.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check that the linker use a value of _gp symbol defined
# in a linker script to calculate GOT relocations.
@@ -24,45 +25,45 @@
# RUN: ld.lld -shared -o %t.abs.so --script %t.abs.script %t.o
# RUN: llvm-objdump -s -t %t.abs.so | FileCheck --check-prefix=ABS %s
-# REQUIRES: mips
+# REL: Contents of section .reginfo:
+# REL-NEXT: 0018 10000104 00000000 00000000 00000000
+# REL-NEXT: 0028 00000000 000001ec
+# ^-- _gp
# REL: Contents of section .text:
-# REL-NEXT: 0000 3c080000 2108010c 8f82fffc
+# REL-NEXT: 00e0 3c080000 2108010c 8f82ff1c
# ^-- %hi(_gp_disp)
# ^-- %lo(_gp_disp)
-# ^-- 8 - (0x10c - 0x100)
+# ^-- 8 - (0x1ec - 0x100)
# G - (GP - .got)
-# REL: Contents of section .reginfo:
-# REL-NEXT: 0028 10000104 00000000 00000000 00000000
-# REL-NEXT: 0038 00000000 0000010c
-# ^-- _gp
-
# REL: Contents of section .data:
# REL-NEXT: 00f0 fffffef4
-# ^-- 0-0x10c
+# ^-- 0x30-0x1ec
+# foo - GP
-# REL: 00000000 .text 00000000 foo
+# REL: 000000e0 .text 00000000 foo
# REL: 00000000 *ABS* 00000000 .hidden _gp_disp
-# REL: 0000010c *ABS* 00000000 .hidden _gp
+# REL: 000001ec *ABS* 00000000 .hidden _gp
+
+# ABS: Contents of section .reginfo:
+# ABS-NEXT: 0018 10000104 00000000 00000000 00000000
+# ABS-NEXT: 0028 00000000 00000200
+# ^-- _gp
# ABS: Contents of section .text:
-# ABS-NEXT: 0000 3c080000 21080200 8f82ff08
+# ABS-NEXT: 00e0 3c080000 21080120 8f82ff08
# ^-- %hi(_gp_disp)
# ^-- %lo(_gp_disp)
# ^-- 8 - (0x200 - 0x100)
# G - (GP - .got)
-# ABS: Contents of section .reginfo:
-# ABS-NEXT: 0028 10000104 00000000 00000000 00000000
-# ABS-NEXT: 0038 00000000 00000200
-# ^-- _gp
-
# ABS: Contents of section .data:
-# ABS-NEXT: 00f0 fffffe00
-# ^-- 0-0x200
+# ABS-NEXT: 00f0 fffffee0
+# ^-- 0xe0-0x200
+# foo - GP
-# ABS: 00000000 .text 00000000 foo
+# ABS: 000000e0 .text 00000000 foo
# ABS: 00000000 *ABS* 00000000 .hidden _gp_disp
# ABS: 00000200 *ABS* 00000000 .hidden _gp
diff --git a/test/ELF/mips-gp-local.s b/test/ELF/mips-gp-local.s
index 8bb3c236edf0..1146af8ff751 100644
--- a/test/ELF/mips-gp-local.s
+++ b/test/ELF/mips-gp-local.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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
diff --git a/test/ELF/mips-gp-lowest.s b/test/ELF/mips-gp-lowest.s
index 32a3e85ee9ec..46da50334f5a 100644
--- a/test/ELF/mips-gp-lowest.s
+++ b/test/ELF/mips-gp-lowest.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check that default _gp value is calculated relative
# to the GP-relative section with the lowest address.
@@ -8,8 +9,6 @@
# RUN: ld.lld %t.o --script %t.rel.script -shared -o %t.so
# RUN: llvm-readobj -s -t %t.so | FileCheck %s
-# REQUIRES: mips
-
.text
.global foo
foo:
@@ -26,7 +25,7 @@ foo:
# CHECK-NEXT: SHF_MIPS_GPREL
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0xE0
+# CHECK-NEXT: Address: 0xF0
# CHECK: }
# CHECK: Section {
# CHECK: Name: .got
@@ -36,9 +35,9 @@ foo:
# CHECK-NEXT: SHF_MIPS_GPREL
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0xF0
+# CHECK-NEXT: Address: 0x100
# CHECK: }
# CHECK: Name: _gp (5)
-# CHECK-NEXT: Value: 0x80D0
-# ^-- 0xE0 + 0x7ff0
+# CHECK-NEXT: Value: 0x80E0
+# ^-- 0xF0 + 0x7ff0
diff --git a/test/ELF/mips-gprel-sec.s b/test/ELF/mips-gprel-sec.s
index dc54f87216da..7517983895b8 100644
--- a/test/ELF/mips-gprel-sec.s
+++ b/test/ELF/mips-gprel-sec.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# Check order of gp-relative sections, i.e. sections with SHF_MIPS_GPREL flag.
# 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 -s %t.so | FileCheck %s
-# REQUIRES: mips
-
.text
nop
diff --git a/test/ELF/mips-gprel32-relocs-gp0.s b/test/ELF/mips-gprel32-relocs-gp0.s
index 507224e05d15..1abdeec1b11a 100644
--- a/test/ELF/mips-gprel32-relocs-gp0.s
+++ b/test/ELF/mips-gprel32-relocs-gp0.s
@@ -1,8 +1,5 @@
+# REQUIRES: mips
# Check that relocatable object produced by LLD has zero gp0 value.
-# Also check an error message if input object file has non-zero gp0 value
-# and the linker generates a relocatable object.
-# mips-gp0-non-zero.o is a relocatable object produced from the asm code
-# below and linked by GNU bfd linker.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld -r -o %t-rel.o %t.o
@@ -12,11 +9,6 @@
# RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s
# RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s
-# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \
-# RUN: | FileCheck --check-prefix=ERR %s
-
-# REQUIRES: mips
-
# REL: GP: 0x0
# DSO: GP: 0x27FF0
@@ -31,8 +23,6 @@
# DUMP: 00010004 .text 00000000 foo
# DUMP: 00027ff0 .got 00000000 .hidden _gp
-# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value
-
.text
.global __start
__start:
diff --git a/test/ELF/mips-gprel32-relocs.s b/test/ELF/mips-gprel32-relocs.s
index 047165f19ae4..8f31aa87411d 100644
--- a/test/ELF/mips-gprel32-relocs.s
+++ b/test/ELF/mips-gprel32-relocs.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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:
diff --git a/test/ELF/mips-higher-highest.s b/test/ELF/mips-higher-highest.s
index 123b51a65add..3af7dcb4b527 100644
--- a/test/ELF/mips-higher-highest.s
+++ b/test/ELF/mips-higher-highest.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_HIGHER / R_MIPS_HIGHEST relocations calculation.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
@@ -6,8 +7,6 @@
# RUN: ld.lld %t1.o %t2.o -o %t.exe
# RUN: llvm-objdump -d %t.exe | FileCheck %s
-# REQUIRES: mips
-
.global __start
__start:
lui $6, %highest(_foo+0x300047FFF7FF7)
diff --git a/test/ELF/mips-hilo-gp-disp.s b/test/ELF/mips-hilo-gp-disp.s
index c7229ee0da25..997074efff16 100644
--- a/test/ELF/mips-hilo-gp-disp.s
+++ b/test/ELF/mips-hilo-gp-disp.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_HI16 / LO16 relocations calculation against _gp_disp.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
@@ -8,8 +9,6 @@
# 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:
diff --git a/test/ELF/mips-hilo-hi-only.s b/test/ELF/mips-hilo-hi-only.s
index 0858e3f6cd17..6fd4c683fd91 100644
--- a/test/ELF/mips-hilo-hi-only.s
+++ b/test/ELF/mips-hilo-hi-only.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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:
diff --git a/test/ELF/mips-hilo.s b/test/ELF/mips-hilo.s
index d5de9422c427..a00ffaa9fb1c 100644
--- a/test/ELF/mips-hilo.s
+++ b/test/ELF/mips-hilo.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# 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:
diff --git a/test/ELF/mips-lo16-not-relative.s b/test/ELF/mips-lo16-not-relative.s
index 614e6396cc92..2af1eead8847 100644
--- a/test/ELF/mips-lo16-not-relative.s
+++ b/test/ELF/mips-lo16-not-relative.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# 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.
@@ -9,8 +10,6 @@
# 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
diff --git a/test/ELF/mips-merge-abiflags.s b/test/ELF/mips-merge-abiflags.s
index 2e8b43bcc3b8..d061c1b022bd 100644
--- a/test/ELF/mips-merge-abiflags.s
+++ b/test/ELF/mips-merge-abiflags.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Test that lld handles input files with concatenated .MIPS.abiflags sections
# This happens e.g. with the FreeBSD BFD (BFD 2.17.50 [FreeBSD] 2007-07-03)
@@ -8,7 +9,6 @@
# RUN: %p/Inputs/mips-concatenated-abiflags.o | \
# RUN: FileCheck --check-prefix=INPUT-OBJECT %s
-# REQUIRES: mips
.globl __start
__start:
nop
diff --git a/test/ELF/mips-mgot.s b/test/ELF/mips-mgot.s
new file mode 100644
index 000000000000..0bb1a76ea8f5
--- /dev/null
+++ b/test/ELF/mips-mgot.s
@@ -0,0 +1,117 @@
+# REQUIRES: mips
+# Check MIPS multi-GOT layout.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t0.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %p/Inputs/mips-mgot-1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %p/Inputs/mips-mgot-2.s -o %t2.o
+# RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so
+# RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# CHECK: Contents of section .got:
+# CHECK-NEXT: 60000 00000000 80000000 00010000 00010030
+# CHECK-NEXT: 60010 00000000 00000004 00020000 00030000
+# CHECK-NEXT: 60020 00040000 00050000 00060000 00070000
+# CHECK-NEXT: 60030 00000000 00000000 00000000 00000000
+# CHECK-NEXT: 60040 00000000 00000000 00000000
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000000 l .tdata 00000000 loc0
+# CHECK: 00010000 .text 00000000 foo0
+# CHECK: 00000000 g .tdata 00000000 tls0
+# CHECK: 00010020 .text 00000000 foo1
+# CHECK: 00000004 g .tdata 00000000 tls1
+# CHECK: 00010030 .text 00000000 foo2
+# CHECK: 00000008 g .tdata 00000000 tls2
+
+# GOT: Relocations [
+# GOT-NEXT: Section (7) .rel.dyn {
+# GOT-NEXT: 0x60018 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x6001C R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60020 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60024 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60028 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x6002C R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60030 R_MIPS_REL32 foo0 0x0
+# GOT-NEXT: 0x60034 R_MIPS_REL32 foo2 0x0
+# GOT-NEXT: 0x60044 R_MIPS_TLS_DTPMOD32 - 0x0
+# GOT-NEXT: 0x60010 R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT: 0x60038 R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT: 0x6003C R_MIPS_TLS_DTPMOD32 tls0 0x0
+# GOT-NEXT: 0x60040 R_MIPS_TLS_DTPREL32 tls0 0x0
+# GOT-NEXT: 0x60014 R_MIPS_TLS_TPREL32 tls1 0x0
+# GOT-NEXT: }
+# GOT-NEXT: ]
+
+# GOT: DynamicSymbols [
+# GOT: Symbol {
+# GOT: Name: foo0
+# GOT-NEXT: Value: 0x10000
+# GOT: }
+# GOT-NEXT: Symbol {
+# GOT-NEXT: Name: foo2
+# GOT-NEXT: Value: 0x10030
+# GOT: }
+# GOT-NEXT: ]
+
+# GOT: Primary GOT {
+# GOT-NEXT: Canonical gp value: 0x67FF0
+# GOT-NEXT: Reserved entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32752
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Purpose: Lazy resolver
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# 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: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32744
+# GOT-NEXT: Initial: 0x10000
+# GOT-NEXT: Value: 0x10000
+# GOT-NEXT: Type: None
+# GOT-NEXT: Section: .text
+# GOT-NEXT: Name: foo0
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32740
+# GOT-NEXT: Initial: 0x10030
+# GOT-NEXT: Value: 0x10030
+# GOT-NEXT: Type: None
+# GOT-NEXT: Section: .text
+# GOT-NEXT: Name: foo2
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Number of TLS and multi-GOT entries: 15
+# GOT-NEXT: }
+
+ .text
+ .global foo0
+foo0:
+ lw $2, %got(.data)($gp) # page entry
+ addi $2, $2, %lo(.data)
+ lw $2, %call16(foo0)($gp) # global entry
+ addiu $2, $2, %tlsgd(tls0) # tls gd entry
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+ addiu $2, $2, %tlsldm(loc0) # tls ld entry
+
+ .data
+ .space 0x20000
+
+ .section .tdata,"awT",%progbits
+ .global tls0
+tls0:
+loc0:
+ .word 0
diff --git a/test/ELF/mips-micro-got.s b/test/ELF/mips-micro-got.s
index 8d077f2800f1..a881e0ae5fcb 100644
--- a/test/ELF/mips-micro-got.s
+++ b/test/ELF/mips-micro-got.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check microMIPS GOT relocations for O32 ABI.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
@@ -8,8 +9,6 @@
# RUN: ld.lld %t1.o %t.so -o %t.exe
# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Local entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
diff --git a/test/ELF/mips-micro-got64.s b/test/ELF/mips-micro-got64.s
deleted file mode 100644
index 653bfbfbe8ce..000000000000
--- a/test/ELF/mips-micro-got64.s
+++ /dev/null
@@ -1,48 +0,0 @@
-# Check microMIPS GOT relocations for N64 ABI.
-
-# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
-# RUN: %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
-# 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-readobj -mips-plt-got %t.exe | FileCheck %s
-
-# REQUIRES: mips
-
-# CHECK: Local entries [
-# CHECK-NEXT: Entry {
-# CHECK-NEXT: Address:
-# CHECK-NEXT: Access: -32736
-# CHECK-NEXT: Initial: 0x30000
-# CHECK-NEXT: }
-# CHECK-NEXT: Entry {
-# CHECK-NEXT: Address:
-# CHECK-NEXT: Access: -32728
-# CHECK-NEXT: Initial: 0x40000
-# CHECK-NEXT: }
-# CHECK-NEXT: ]
-# CHECK-NEXT: Global entries [
-# CHECK-NEXT: Entry {
-# CHECK-NEXT: Address:
-# CHECK-NEXT: Access: -32720
-# CHECK-NEXT: Initial: 0x0
-# CHECK-NEXT: Value: 0x0
-# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Section: Undefined
-# CHECK-NEXT: Name: foo0
-# CHECK-NEXT: }
-# CHECK-NEXT: ]
-
- .text
- .global __start
-__start:
- lui $28, %hi(%neg(%gp_rel(foo0)))
- addiu $28, $28, %lo(%neg(%gp_rel(foo0)))
- lw $4, %got_page(data)($28)
- addiu $4, $4, %got_ofst(data)
- lw $25, %call16(foo0)($28)
-
- .data
-data:
- .word 0
diff --git a/test/ELF/mips-micro-jal.s b/test/ELF/mips-micro-jal.s
index 83826126f766..18d41cf13cbc 100644
--- a/test/ELF/mips-micro-jal.s
+++ b/test/ELF/mips-micro-jal.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check PLT creation for microMIPS to microMIPS calls.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -45,8 +46,6 @@
# RUN: llvm-objdump -d -mattr=micromips %teb.exe \
# RUN: | FileCheck --check-prefix=MIXED %s
-# REQUIRES: mips
-
# EB: Disassembly of section .plt:
# EB-NEXT: .plt:
# EB-NEXT: 20010: 79 80 3f fd addiupc $3, 65524
diff --git a/test/ELF/mips-micro-plt.s b/test/ELF/mips-micro-plt.s
index 5671dc420c55..6dcd6fbeec2d 100644
--- a/test/ELF/mips-micro-plt.s
+++ b/test/ELF/mips-micro-plt.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check less-significant bit setup for microMIPS PLT.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -7,13 +8,12 @@
# RUN: -mattr=micromips %s -o %t-exe.o
# RUN: ld.lld %t-exe.o %t.so -o %t.exe
# RUN: llvm-readobj -t -dt -mips-plt-got %t.exe | FileCheck %s
-
-# REQUIRES: mips
+# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck --check-prefix=ASM %s
# CHECK: Symbols [
# CHECK: Symbol {
# CHECK: Name: foo
-# CHECK-NEXT: Value: 0x20008
+# CHECK-NEXT: Value: 0x20010
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Local
# CHECK-NEXT: Type: None
@@ -36,22 +36,28 @@
# CHECK-NEXT: }
# CHECK: Symbol {
# CHECK: Name: foo0
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x20040
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STO_MIPS_MICROMIPS
+# CHECK-NEXT: STO_MIPS_PLT
+# CHECK-NEXT: ]
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK: DynamicSymbols [
# CHECK: Symbol {
# CHECK: Name: foo0
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x20041
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STO_MIPS_MICROMIPS
+# CHECK-NEXT: STO_MIPS_PLT
+# CHECK-NEXT: ]
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: ]
@@ -61,7 +67,7 @@
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access:
-# CHECK-NEXT: Initial: 0x20009
+# CHECK-NEXT: Initial: 0x20011
# CHECK-NEXT: }
# CHECK: ]
# CHECK: }
@@ -70,8 +76,8 @@
# CHECK: Entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
-# CHECK-NEXT: Initial: 0x20011
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Initial: 0x20021
+# CHECK-NEXT: Value: 0x20041
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo0@
@@ -79,6 +85,15 @@
# CHECK-NEXT: ]
# CHECK-NEXT: }
+# ASM: __start:
+# ASM-NEXT: 20000: fd 1c 80 18 lw $8, -32744($gp)
+# ASM-NEXT: 20004: 11 08 00 10 addi $8, $8, 16
+# ASM-NEXT: 20008: 41 a8 00 02 lui $8, 2
+# ASM-NEXT: 2000c: 11 08 00 40 addi $8, $8, 64
+#
+# ASM: foo:
+# ASM-NEXT: 20010: f4 01 00 20 jal 131136
+
.text
.set micromips
.global foo
@@ -87,5 +102,7 @@
__start:
lw $t0,%got(foo)($gp)
addi $t0,$t0,%lo(foo)
+ lui $t0,%hi(foo0)
+ addi $t0,$t0,%lo(foo0)
foo:
jal foo0
diff --git a/test/ELF/mips-micro-relocs.s b/test/ELF/mips-micro-relocs.s
index 3986711cc7f7..b539aa946763 100644
--- a/test/ELF/mips-micro-relocs.s
+++ b/test/ELF/mips-micro-relocs.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check handling of microMIPS relocations.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -16,8 +17,6 @@
# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
# RUN: | FileCheck --check-prefixes=EL,SYM %s
-# REQUIRES: mips
-
# EB: __start:
# EB-NEXT: 20010: 41 a3 00 01 lui $3, 1
# EB-NEXT: 20014: 30 63 7f df addiu $3, $3, 32735
diff --git a/test/ELF/mips-micro-thunks.s b/test/ELF/mips-micro-thunks.s
index 18a8fc33f53c..0505361e4a66 100644
--- a/test/ELF/mips-micro-thunks.s
+++ b/test/ELF/mips-micro-thunks.s
@@ -1,44 +1,77 @@
+# REQUIRES: mips
# Check microMIPS thunk generation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -mattr=micromips %s -o %t-eb.o
+# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -position-independent -mattr=micromips \
+# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic.o
# RUN: ld.lld -o %t-eb.exe %t-eb.o %t-eb-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-eb.exe \
-# RUN: | FileCheck --check-prefix=EB %s
+# RUN: | FileCheck --check-prefix=EB-R2 %s
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
-# RUN: -mattr=micromips %s -o %t-el.o
+# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
-# RUN: -position-independent -mattr=micromips \
+# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-el-pic.o
# RUN: ld.lld -o %t-el.exe %t-el.o %t-el-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-el.exe \
-# RUN: | FileCheck --check-prefix=EL %s
+# RUN: | FileCheck --check-prefix=EL-R2 %s
-# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-eb-r6.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \
+# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic-r6.o
+# RUN: ld.lld -o %t-eb-r6.exe %t-eb-r6.o %t-eb-pic-r6.o
+# RUN: llvm-objdump -d -mattr=+micromips %t-eb-r6.exe \
+# RUN: | FileCheck --check-prefix=EB-R6 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-el-r6.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \
+# RUN: %S/Inputs/mips-micro.s -o %t-el-pic-r6.o
+# RUN: ld.lld -o %t-el-r6.exe %t-el-r6.o %t-el-pic-r6.o
+# RUN: llvm-objdump -d -mattr=+micromips %t-el-r6.exe \
+# RUN: | FileCheck --check-prefix=EL-R6 %s
+
+# EB-R2: __start:
+# EB-R2-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo>
+# EB-R2-NEXT: 20004: 00 00 00 00 nop
+
+# EB-R2: __microLA25Thunk_foo:
+# EB-R2-NEXT: 20008: 41 b9 00 02 lui $25, 2
+# EB-R2-NEXT: 2000c: d4 01 00 10 j 131104
+# EB-R2-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33
+# EB-R2-NEXT: 20014: 0c 00 nop
+
+# EL-R2: __start:
+# EL-R2-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo>
+# EL-R2-NEXT: 20004: 00 00 00 00 nop
+
+# EL-R2: __microLA25Thunk_foo:
+# EL-R2-NEXT: 20008: b9 41 02 00 lui $25, 2
+# EL-R2-NEXT: 2000c: 01 d4 10 00 j 131104
+# EL-R2-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33
+# EL-R2-NEXT: 20014: 00 0c nop
+
+# EB-R6: __start:
+# EB-R6-NEXT: 20000: b4 00 00 00 balc 0 <__start>
+
+# EB-R6: __microLA25Thunk_foo:
+# EB-R6-NEXT: 20004: 13 20 00 02 lui $25, 2
+# EB-R6-NEXT: 20008: 33 39 00 11 addiu $25, $25, 17
+# EB-R6-NEXT: 2000c: 94 00 00 00 bc 0 <__microLA25Thunk_foo+0x8>
+
+# EL-R6: __start:
+# EL-R6-NEXT: 20000: 00 b4 00 00 balc 0 <__start>
-# EB: __start:
-# EB-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo>
-# EB-NEXT: 20004: 00 00 00 00 nop
-
-# EB: __microLA25Thunk_foo:
-# EB-NEXT: 20008: 41 b9 00 02 lui $25, 2
-# EB-NEXT: 2000c: d4 01 00 10 j 131104
-# EB-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33
-# EB-NEXT: 20014: 0c 00 nop
-
-# EL: __start:
-# EL-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo>
-# EL-NEXT: 20004: 00 00 00 00 nop
-
-# EL: __microLA25Thunk_foo:
-# EL-NEXT: 20008: b9 41 02 00 lui $25, 2
-# EL-NEXT: 2000c: 01 d4 10 00 j 131104
-# EL-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33
-# EL-NEXT: 20014: 00 0c nop
+# EL-R6: __microLA25Thunk_foo:
+# EL-R6-NEXT: 20004: 20 13 02 00 lui $25, 2
+# EL-R6-NEXT: 20008: 39 33 11 00 addiu $25, $25, 17
+# EL-R6-NEXT: 2000c: 00 94 00 00 bc 0 <__microLA25Thunk_foo+0x8>
.text
.set micromips
diff --git a/test/ELF/mips-micror6-relocs.s b/test/ELF/mips-micror6-relocs.s
new file mode 100644
index 000000000000..ca2c1c064f56
--- /dev/null
+++ b/test/ELF/mips-micror6-relocs.s
@@ -0,0 +1,38 @@
+# REQUIRES: mips
+
+# Check handling of microMIPS R6 relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 \
+# RUN: %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 %s -o %t2eb.o
+# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o
+# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \
+# RUN: | FileCheck --check-prefixes=EB,SYM %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 \
+# RUN: %S/Inputs/mips-micro.s -o %t1el.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 %s -o %t2el.o
+# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o
+# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
+# RUN: | FileCheck --check-prefixes=EL,SYM %s
+
+# EB: __start:
+# EB-NEXT: 20010: 78 47 ff fd lapc $2, -12
+# EB-NEXT: 20014: 80 7f ff f6 beqzc $3, -36
+# EB-NEXT: 20018: b7 ff ff f4 balc -24 <foo>
+
+# EL: __start:
+# EL-NEXT: 20010: 47 78 fd ff lapc $2, -12
+# EL-NEXT: 20014: 7f 80 f6 ff beqzc $3, -36
+# EL-NEXT: 20018: ff b7 f4 ff balc -24 <foo>
+
+# SYM: 00020000 g F .text 00000000 foo
+# SYM: 00020010 .text 00000000 __start
+
+ .text
+ .set micromips
+ .global __start
+__start:
+ addiupc $2, foo+4 # R_MICROMIPS_PC19_S2
+ beqzc $3, foo+4 # R_MICROMIPS_PC21_S1
+ balc foo+4 # R_MICROMIPS_PC26_S1
diff --git a/test/ELF/mips-n32-emul.s b/test/ELF/mips-n32-emul.s
index d0d81cc1c95f..3385d512d968 100644
--- a/test/ELF/mips-n32-emul.s
+++ b/test/ELF/mips-n32-emul.s
@@ -1,10 +1,9 @@
+# REQUIRES: mips
# Check that LLD shows an error when N32 ABI emulation argument
# is combined with non-N32 ABI object files.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
-# RUN: not ld.lld -m elf32btsmipn32 %t.o -o %t.exe 2>&1 | FileCheck %s
-
-# REQUIRES: mips
+# RUN: not ld.lld -m elf32btsmipn32 %t.o -o /dev/null 2>&1 | FileCheck %s
.text
.global __start
diff --git a/test/ELF/mips-n32-rels.s b/test/ELF/mips-n32-rels.s
index 954d4c30a157..b59000c06d86 100644
--- a/test/ELF/mips-n32-rels.s
+++ b/test/ELF/mips-n32-rels.s
@@ -1,29 +1,27 @@
+# REQUIRES: mips
# Check handling of N32 ABI relocation records.
-# For now llvm-mc generates incorrect object files for N32 ABI.
-# We use the binary input file generated by GNU tool.
-# llvm-mc -filetype=obj -triple=mips64-unknown-linux \
-# -target-abi n32 %s -o %t.o
-# RUN: ld.lld %S/Inputs/mips-n32-rels.o -o %t.exe
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: -target-abi n32 -o %t.o %s
+# RUN: ld.lld %t.o -o %t.exe
# RUN: llvm-objdump -t -d -s %t.exe | FileCheck %s
# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=ELF %s
-# REQUIRES: mips
+ .option pic2
+ .text
+ .type __start, @function
+ .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
-# .text
-# .type __start, @function
-# .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
-# .gpword(loc) # R_MIPS_32
+ .section .rodata,"a",@progbits
+ .gpword(loc) # R_MIPS_GPREL32
# CHECK: Disassembly of section .text:
# CHECK-NEXT: __start:
@@ -38,8 +36,8 @@
# ^-- %lo(0x17ff0)
# CHECK: Contents of section .rodata:
-# CHECK-NEXT: {{[0-9a-f]+}} 00020004
-# ^-- loc
+# CHECK-NEXT: {{[0-9a-f]+}} fffe8014
+# ^-- loc - _gp
# CHECK: 00020004 .text 00000000 loc
# CHECK: 00037ff0 .got 00000000 .hidden _gp
@@ -67,5 +65,7 @@
# ELF-NEXT: SectionHeaderOffset:
# ELF-NEXT: Flags [
# ELF-NEXT: EF_MIPS_ABI2
-# ELF-NEXT: EF_MIPS_ARCH_64R2
+# ELF-NEXT: EF_MIPS_ARCH_64
+# ELF-NEXT: EF_MIPS_CPIC
+# ELF-NEXT: EF_MIPS_PIC
# ELF-NEXT: ]
diff --git a/test/ELF/mips-non-zero-gp0.s b/test/ELF/mips-non-zero-gp0.s
new file mode 100644
index 000000000000..9e6b13c70725
--- /dev/null
+++ b/test/ELF/mips-non-zero-gp0.s
@@ -0,0 +1,54 @@
+# REQUIRES: mips
+
+# Check addend adjustment in case of generating a relocatable object
+# if some input files have non-zero GP0 value.
+
+# We have to use GNU as and ld.bfd 2.28 to generate relocatable object
+# files with non-zero GP0 value using the following command lines:
+#
+# as -mips32 -o test.o \
+# && ld.bfd -m elf32btsmip -r test.o -o mips-gp0-non-zero.o
+# as -mips64 -o test.o \
+# && ld.bfd -m elf64btsmip -r test.o -o mips-n64-gp0-non-zero.o
+
+# Source code for mips-gp0-non-zero.o:
+# .text
+# .global __start
+# __start:
+# lw $t0,%call16(__start)($gp)
+# foo:
+# nop
+# bar:
+# nop
+#
+# .section .rodata, "a"
+# v:
+# .gpword foo
+# .gpword bar
+
+# Source code for mips-n64-gp0-non-zero.o and mips-micro-gp0-non-zero.o:
+# .text
+# .global __start
+# __start:
+# foo:
+# lui $gp,%hi(%neg(%gp_rel(foo)))
+
+# RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o
+# RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s
+# RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s
+
+# RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o
+# RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s
+# RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \
+# RUN: | FileCheck --check-prefix=ADDEND64 %s
+
+# GPVAL: GP: 0x0
+
+# ADDEND32: Contents of section .rodata:
+# ADDEND32-NEXT: 0000 00007ff4 00007ff8
+# ^ 4+GP0 ^ 8+GP0
+
+# ADDEND64: File: {{.*}}{{/|\\}}mips-n64-gp0-non-zero.o
+# ADDEND64: .text 0xFFFFFFFFFFFF8011
+# ADDEND64: File: {{.*}}{{/|\\}}mips-non-zero-gp0.s.tmp-64.r
+# ADDEND64: .text 0x0
diff --git a/test/ELF/mips-nonalloc.s b/test/ELF/mips-nonalloc.s
index 7b0aa9469f9f..38d4599c689d 100644
--- a/test/ELF/mips-nonalloc.s
+++ b/test/ELF/mips-nonalloc.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check reading addends for relocations in non-allocatable sections.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
@@ -6,8 +7,6 @@
# 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
diff --git a/test/ELF/mips-options.s b/test/ELF/mips-options.s
index 18f5af8ece6e..ad634171eff7 100644
--- a/test/ELF/mips-options.s
+++ b/test/ELF/mips-options.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS .MIPS.options section generation.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
@@ -9,8 +10,6 @@
# RUN: ld.lld %t1.o %t2.o --gc-sections --script %t.rel.script -shared -o %t.so
# RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s
-# REQUIRES: mips
-
.text
.globl __start
__start:
diff --git a/test/ELF/mips-out-of-bounds-call16-reloc.s b/test/ELF/mips-out-of-bounds-call16-reloc.s
index 64e9ab3aa7e2..cc2494af5948 100644
--- a/test/ELF/mips-out-of-bounds-call16-reloc.s
+++ b/test/ELF/mips-out-of-bounds-call16-reloc.s
@@ -1,8 +1,8 @@
+# REQUIRES: mips
# Check that we create an error on an out-of-bounds R_MIPS_CALL_16
-# REQUIRES: mips
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
-# RUN: not ld.lld %t1.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: relocation R_MIPS_CALL16 out of range: 32768 is not in [-32768, 32767]
diff --git a/test/ELF/mips-pc-relocs.s b/test/ELF/mips-pc-relocs.s
index e0f39e7ed7c4..46c2b75578d9 100644
--- a/test/ELF/mips-pc-relocs.s
+++ b/test/ELF/mips-pc-relocs.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check R_MIPS_PCxxx relocations calculation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -7,8 +8,6 @@
# 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:
diff --git a/test/ELF/mips-plt-copy.s b/test/ELF/mips-plt-copy.s
index 58883d884563..e035c5bd588c 100644
--- a/test/ELF/mips-plt-copy.s
+++ b/test/ELF/mips-plt-copy.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check creating of R_MIPS_COPY and R_MIPS_JUMP_SLOT dynamic relocations
# and corresponding PLT entries.
@@ -8,16 +9,14 @@
# 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-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-DAG: 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-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
+# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/mips-plt-n32.s b/test/ELF/mips-plt-n32.s
new file mode 100644
index 000000000000..06699fc1d045
--- /dev/null
+++ b/test/ELF/mips-plt-n32.s
@@ -0,0 +1,43 @@
+# REQUIRES: mips
+
+# Check PLT entries generation in case of using N32 ABI.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: -target-abi n32 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: -target-abi n32 %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 --check-prefixes=DEFAULT,CHECK
+# RUN: ld.lld %t2.o -shared -o %t.so -z hazardplt
+# RUN: ld.lld %t1.o %t.so -o %t.exe -z hazardplt
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120
+# ^-- 0x20030 gotplt[foo0]
+# CHECK-NEXT: 20004: 00 00 00 00 nop
+#
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3
+# CHECK-NEXT: 20014: 8d d9 00 04 lw $25, 4($14)
+# CHECK-NEXT: 20018: 25 ce 00 04 addiu $14, $14, 4
+# CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14
+# CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra
+# CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2
+# DEFAULT: 20028: 03 20 f8 09 jalr $25
+# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25
+# CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2
+
+# CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3
+# CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15)
+# DEFAULT: 20038: 03 20 00 08 jr $25
+# HAZARDPLT: 20038: 03 20 04 08 jr.hb $25
+# CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12
+
+ .text
+ .global __start
+__start:
+ jal foo0 # R_MIPS_26 against 'foo0' from DSO
diff --git a/test/ELF/mips-plt-r6.s b/test/ELF/mips-plt-r6.s
index 4bab21c32eb9..b0ceb8214f02 100644
--- a/test/ELF/mips-plt-r6.s
+++ b/test/ELF/mips-plt-r6.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check PLT entries generation in case of R6 ABI version.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -6,9 +7,10 @@
# RUN: -mcpu=mips32r6 %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
-
-# REQUIRES: mips
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=DEFAULT,CHECK
+# RUN: ld.lld %t2.o -shared -o %t.so -z hazardplt
+# RUN: ld.lld %t1.o %t.so -o %t.exe -z hazardplt
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK
# CHECK: Disassembly of section .text:
# CHECK-NEXT: __start:
@@ -24,12 +26,14 @@
# CHECK-NEXT: 2001c: 03 1c c0 23 subu $24, $24, $gp
# CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra
# CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2
-# CHECK-NEXT: 20028: 03 20 f8 09 jalr $25
+# DEFAULT: 20028: 03 20 f8 09 jalr $25
+# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25
# CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2
# CHECK-NEXT: 20030: 3c 0f 00 03 aui $15, $zero, 3
# CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15)
-# CHECK-NEXT: 20038: 03 20 00 09 jr $25
+# DEFAULT: 20038: 03 20 00 09 jr $25
+# HAZARDPLT: 20038: 03 20 04 09 jr.hb $25
# CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12
.text
diff --git a/test/ELF/mips-reginfo.s b/test/ELF/mips-reginfo.s
index 4024a2f6634f..049950d7424b 100644
--- a/test/ELF/mips-reginfo.s
+++ b/test/ELF/mips-reginfo.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS .reginfo section generation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
@@ -6,8 +7,6 @@
# RUN: ld.lld %t1.o %t2.o --gc-sections -shared -o %t.so
# RUN: llvm-readobj -symbols -mips-reginfo %t.so | FileCheck %s
-# REQUIRES: mips
-
.text
.globl __start
__start:
diff --git a/test/ELF/mips-relocatable.s b/test/ELF/mips-relocatable.s
index 168ddf736e1e..0ab62774a4d8 100644
--- a/test/ELF/mips-relocatable.s
+++ b/test/ELF/mips-relocatable.s
@@ -1,11 +1,10 @@
+# REQUIRES: mips
# Check linking MIPS code in case of -r linker's option.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld -r -o %t-r.o %t.o
# RUN: llvm-objdump -s -t %t-r.o | FileCheck %s
-# REQUIRES: mips
-
.text
.global __start
__start:
diff --git a/test/ELF/mips-sto-pic-flag.s b/test/ELF/mips-sto-pic-flag.s
index 3960ba322387..ae496979f7c6 100644
--- a/test/ELF/mips-sto-pic-flag.s
+++ b/test/ELF/mips-sto-pic-flag.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# In case of linking PIC and non-PIC code together and generation
# of a relocatable object, all PIC symbols should have STO_MIPS_PIC
# flag in the symbol table of the ouput file.
@@ -8,8 +9,6 @@
# RUN: ld.lld -r %t-npic.o %t-pic.o -o %t-rel.o
# RUN: llvm-readobj -t %t-rel.o | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Symbol {
# CHECK: Name: main
# CHECK-NEXT: Value:
diff --git a/test/ELF/mips-sto-plt.s b/test/ELF/mips-sto-plt.s
index bd8de416680a..b4d3ee391414 100644
--- a/test/ELF/mips-sto-plt.s
+++ b/test/ELF/mips-sto-plt.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check assigning STO_MIPS_PLT flag to symbol needs a pointer equality.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -7,8 +8,6 @@
# 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
@@ -18,9 +17,9 @@
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
-# CHECK: Symbol {
-# CHECK: Name: foo1@
-# CHECK-NEXT: Value: 0x20050
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: foo1@
+# CHECK-NEXT: Value: 0x[[FOO1:[0-9A-F]+]]
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
@@ -48,7 +47,7 @@
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Initial:
-# CHECK-NEXT: Value: 0x20050
+# CHECK-NEXT: Value: 0x[[FOO1]]
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo1
diff --git a/test/ELF/mips-tls-64-pic-local-variable.s b/test/ELF/mips-tls-64-pic-local-variable.s
new file mode 100644
index 000000000000..04d916f42c6c
--- /dev/null
+++ b/test/ELF/mips-tls-64-pic-local-variable.s
@@ -0,0 +1,49 @@
+# REQUIRES: mips
+# MIPS TLS variables that are marked as local by a version script were previously
+# writing values to the GOT that caused runtime crashes. This was happending when
+# linking jemalloc_tsd.c in FreeBSD libc. Check that we do the right thing now:
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+# RUN: echo "{ global: foo; local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-objdump --section=.got -s %t.so | FileCheck %s -check-prefix GOT
+# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix RELOCS
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 20000 00000000 00000000 80000000 00000000
+# GOT-NEXT: 20010 00000000 00000000 00000000 00000000
+# GOT-NEXT: 20020 ffffffff ffff8000
+
+# RELOCS: Section ({{.+}}) .rel.dyn {
+# RELOCS-NEXT: 0x20018 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE
+# RELOCS-NEXT: }
+
+# Test case generated using clang -mcpu=mips4 -target mips64-unknown-freebsd12.0 -fpic -O -G0 -EB -mabi=n64 -msoft-float -std=gnu99 -S %s -o %t.s
+# from the following source:
+#
+# _Thread_local int x;
+# int foo() { return x; }
+#
+ .text
+ .globl foo
+ .p2align 3
+ .type foo,@function
+ .ent foo
+foo:
+ lui $1, %hi(%neg(%gp_rel(foo)))
+ daddu $1, $1, $25
+ daddiu $gp, $1, %lo(%neg(%gp_rel(foo)))
+ ld $25, %call16(__tls_get_addr)($gp)
+ jalr $25
+ daddiu $4, $gp, %tlsgd(x)
+ .end foo
+
+ .type x,@object
+ .section .tbss,"awT",@nobits
+ .globl x
+ .p2align 2
+x:
+ .4byte 0
+ .size x, 4
+
+
diff --git a/test/ELF/mips-tls-64.s b/test/ELF/mips-tls-64.s
index db29789ee117..f000755b4e82 100644
--- a/test/ELF/mips-tls-64.s
+++ b/test/ELF/mips-tls-64.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS TLS 64-bit relocations handling.
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
@@ -13,31 +14,29 @@
# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s
-# REQUIRES: mips
-
# DIS: __start:
-# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736
-# DIS-NEXT: 20004: 24 62 80 30 addiu $2, $3, -32720
-# DIS-NEXT: 20008: 24 62 80 38 addiu $2, $3, -32712
-# DIS-NEXT: 2000c: 24 62 80 48 addiu $2, $3, -32696
-# DIS-NEXT: 20010: 24 62 80 58 addiu $2, $3, -32680
+# DIS-NEXT: 20000: 24 62 80 30 addiu $2, $3, -32720
+# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736
+# DIS-NEXT: 20008: 24 62 80 40 addiu $2, $3, -32704
+# DIS-NEXT: 2000c: 24 62 80 50 addiu $2, $3, -32688
+# DIS-NEXT: 20010: 24 62 80 28 addiu $2, $3, -32728
# DIS: Contents of section .got:
# DIS-NEXT: 30010 00000000 00000000 80000000 00000000
-# DIS-NEXT: 30020 00000000 00000000 00000000 00000000
-# DIS-NEXT: 30030 00000000 00000000 00000000 00000001
-# DIS-NEXT: 30040 00000000 00000000 00000000 00000001
-# DIS-NEXT: 30050 ffffffff ffff8004 ffffffff ffff9004
+# DIS-NEXT: 30020 00000000 00000000 ffffffff ffff9004
+# DIS-NEXT: 30030 00000000 00000000 00000000 00000000
+# DIS-NEXT: 30040 00000000 00000001 00000000 00000000
+# DIS-NEXT: 30050 00000000 00000001 ffffffff ffff8004
# DIS: 0000000000000000 l .tdata 00000000 loc
# DIS: 0000000000000004 g .tdata 00000000 bar
# DIS: 0000000000000000 g *UND* 00000000 foo
# CHECK: Relocations [
-# CHECK-NEXT: Section (7) .rela.dyn {
-# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT: 0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT: 0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: Section (7) .rel.dyn {
+# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: 0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Primary GOT {
@@ -49,31 +48,31 @@
# CHECK-NEXT: Global entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
-# ^-- -32728 R_MIPS_TLS_DTPREL64 foo
-# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
-# ^-- -32712 R_MIPS_TLS_LDM 1 loc
-# ^-- -32704 0 loc
-# ^-- -32696 R_MIPS_TLS_GD 1 bar
-# ^-- -32688 VA - 0x8000 bar
-# ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
+# ^-- -32728 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
+# ^-- -32712 R_MIPS_TLS_DTPREL64 foo
+# ^-- -32704 R_MIPS_TLS_LDM 1 loc
+# ^-- -32696 0 loc
+# ^-- -32688 R_MIPS_TLS_GD 1 bar
+# ^-- -32680 VA - 0x8000 bar
# DIS-SO: Contents of section .got:
# DIS-SO-NEXT: 20000 00000000 00000000 80000000 00000000
-# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000004
# DIS-SO-NEXT: 20020 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20030 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20040 00000000 00000000 00000000 00000000
# SO: Relocations [
-# SO-NEXT: Section (7) .rela.dyn {
-# SO-NEXT: 0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
-# SO-NEXT: 0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT: 0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT: 0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: Section (7) .rel.dyn {
+# SO-NEXT: 0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# SO-NEXT: 0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT: 0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT: 0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
# SO-NEXT: }
# SO-NEXT: ]
# SO-NEXT: Primary GOT {
@@ -85,14 +84,14 @@
# SO-NEXT: Global entries [
# SO-NEXT: ]
# SO-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
-# ^-- -32728 R_MIPS_TLS_DTPREL64 foo
-# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
-# ^-- -32712 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc
-# ^-- -32704 0 loc
-# ^-- -32696 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar
-# ^-- -32688 R_MIPS_TLS_DTPREL64 bar
-# ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar
+# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
+# ^-- -32728 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
+# ^-- -32712 R_MIPS_TLS_DTPREL64 foo
+# ^-- -32704 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc
+# ^-- -32696 0 loc
+# ^-- -32688 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar
+# ^-- -32680 R_MIPS_TLS_DTPREL64 bar
.text
.global __start
diff --git a/test/ELF/mips-tls-hilo.s b/test/ELF/mips-tls-hilo.s
index 47fadaa34b80..ae54602327a9 100644
--- a/test/ELF/mips-tls-hilo.s
+++ b/test/ELF/mips-tls-hilo.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS R_MIPS_TLS_DTPREL_HI16/LO16 and R_MIPS_TLS_TPREL_HI16/LO16
# relocations handling.
@@ -9,8 +10,6 @@
# 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) --^
diff --git a/test/ELF/mips-tls-static-64.s b/test/ELF/mips-tls-static-64.s
index 6f88e86a3f44..04f18fa57585 100644
--- a/test/ELF/mips-tls-static-64.s
+++ b/test/ELF/mips-tls-static-64.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check handling TLS related relocations and symbols when linking
# a 64-bit static executable.
@@ -5,8 +6,6 @@
# RUN: ld.lld -static %t -o %t.exe
# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Contents of section .data:
# CHECK-NEXT: 30000 00020004 ffffffff ffff8004 ffffffff
# CHECK-NEXT: 30010 ffff9004
diff --git a/test/ELF/mips-tls-static.s b/test/ELF/mips-tls-static.s
index 84b56cb42240..b09f5516bc89 100644
--- a/test/ELF/mips-tls-static.s
+++ b/test/ELF/mips-tls-static.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check handling TLS related relocations and symbols when linking
# a static executable.
@@ -5,13 +6,11 @@
# RUN: ld.lld -static %t -o %t.exe
# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Contents of section .data:
# CHECK-NEXT: 30000 0002000c ffff8004 ffff9004
# CHECK: Contents of section .got:
-# CHECK-NEXT: 30010 00000000 80000000 00000001 ffff8000
-# CHECK-NEXT: 30020 00000001 00000000 ffff9000
+# CHECK-NEXT: 30010 00000000 80000000 ffff9000 00000001
+# CHECK-NEXT: 30020 ffff8000 00000001 00000000
#
# CHECK: SYMBOL TABLE:
# CHECK: 0002000c .text 00000000 __tls_get_addr
diff --git a/test/ELF/mips-tls.s b/test/ELF/mips-tls.s
index b64f8db75731..ece55c69b303 100644
--- a/test/ELF/mips-tls.s
+++ b/test/ELF/mips-tls.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check MIPS TLS relocations handling.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -13,19 +14,17 @@
# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s
-# REQUIRES: mips
-
# DIS: __start:
-# DIS-NEXT: 20000: 24 62 80 18 addiu $2, $3, -32744
-# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736
-# DIS-NEXT: 20008: 24 62 80 24 addiu $2, $3, -32732
-# DIS-NEXT: 2000c: 24 62 80 2c addiu $2, $3, -32724
-# DIS-NEXT: 20010: 24 62 80 34 addiu $2, $3, -32716
+# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736
+# DIS-NEXT: 20004: 24 62 80 18 addiu $2, $3, -32744
+# DIS-NEXT: 20008: 24 62 80 28 addiu $2, $3, -32728
+# DIS-NEXT: 2000c: 24 62 80 30 addiu $2, $3, -32720
+# DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740
# DIS: Contents of section .got:
-# DIS-NEXT: 30010 00000000 80000000 00000000 00000000
-# DIS-NEXT: 30020 00000000 00000001 00000000 00000001
-# DIS-NEXT: 30030 ffff8004 ffff9004
+# DIS-NEXT: 30010 00000000 80000000 00000000 ffff9004
+# DIS-NEXT: 30020 00000000 00000000 00000001 00000000
+# DIS-NEXT: 30030 00000001 ffff8004
# DIS: 00000000 l .tdata 00000000 loc
# DIS: 00000004 g .tdata 00000000 bar
@@ -33,9 +32,9 @@
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
-# CHECK-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0
-# CHECK-NEXT: 0x3001C R_MIPS_TLS_DTPREL32 foo 0x0
-# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT: 0x30018 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Primary GOT {
@@ -47,29 +46,29 @@
# CHECK-NEXT: Global entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
-# ^-- -32740 R_MIPS_TLS_DTPREL32 foo
-# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
-# ^-- -32732 R_MIPS_TLS_LDM 1 loc
-# ^-- -32728 0 loc
-# ^-- -32724 R_MIPS_TLS_GD 1 bar
-# ^-- -32720 VA - 0x8000 bar
-# ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
+# ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
+# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
+# ^-- -32728 R_MIPS_TLS_LDM 1 loc
+# ^-- -32724 0 loc
+# ^-- -32720 R_MIPS_TLS_GD 1 bar
+# ^-- -32716 VA - 0x8000 bar
# DIS-SO: Contents of section .got:
-# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000000
+# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000004
# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20020 00000000 00000000
# SO: Relocations [
# SO-NEXT: Section (7) .rel.dyn {
-# SO-NEXT: 0x20014 R_MIPS_TLS_DTPMOD32 - 0x0
-# SO-NEXT: 0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0
-# SO-NEXT: 0x20020 R_MIPS_TLS_DTPREL32 bar 0x0
-# SO-NEXT: 0x20024 R_MIPS_TLS_TPREL32 bar 0x0
-# SO-NEXT: 0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0
-# SO-NEXT: 0x2000C R_MIPS_TLS_DTPREL32 foo 0x0
-# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT: 0x20018 R_MIPS_TLS_DTPMOD32 - 0x0
+# SO-NEXT: 0x2000C R_MIPS_TLS_TPREL32 bar 0x0
+# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0
+# SO-NEXT: 0x20024 R_MIPS_TLS_DTPREL32 bar 0x0
+# SO-NEXT: 0x20008 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# SO-NEXT: 0x20014 R_MIPS_TLS_DTPREL32 foo 0x0
# SO-NEXT: }
# SO-NEXT: ]
# SO-NEXT: Primary GOT {
@@ -81,14 +80,14 @@
# SO-NEXT: Global entries [
# SO-NEXT: ]
# SO-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
-# ^-- -32740 R_MIPS_TLS_DTPREL32 foo
-# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
-# ^-- -32732 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc
-# ^-- -32728 0 loc
-# ^-- -32724 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar
-# ^-- -32720 R_MIPS_TLS_DTPREL32 bar
-# ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar
+# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
+# ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar
+# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
+# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
+# ^-- -32728 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc
+# ^-- -32724 0 loc
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar
+# ^-- -32716 R_MIPS_TLS_DTPREL32 bar
.text
.global __start
diff --git a/test/ELF/mips-xgot-order.s b/test/ELF/mips-xgot-order.s
index 911731c713cd..c44cf64edd5a 100644
--- a/test/ELF/mips-xgot-order.s
+++ b/test/ELF/mips-xgot-order.s
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check that GOT entries accessed via 16-bit indexing are allocated
# in the beginning of the GOT.
@@ -5,8 +6,6 @@
# RUN: ld.lld %t.o -o %t.exe
# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Disassembly of section .text:
# CHECK-NEXT: __start:
# CHECK-NEXT: 20000: 3c 02 00 00 lui $2, 0
diff --git a/test/ELF/mips64-eh-abs-reloc.s b/test/ELF/mips64-eh-abs-reloc.s
index 7bc500137992..7c31e1b51eda 100644
--- a/test/ELF/mips64-eh-abs-reloc.s
+++ b/test/ELF/mips64-eh-abs-reloc.s
@@ -1,5 +1,5 @@
-# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD
# REQUIRES: mips
+# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ
# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o
@@ -20,8 +20,8 @@
# OBJ-NEXT: }
# PIC-RELOCS: Relocations [
-# PIC-RELOCS-NEXT: Section (7) .rela.dyn {
-# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000
+# PIC-RELOCS-NEXT: Section (7) .rel.dyn {
+# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x0
# PIC-RELOCS-NEXT: }
# PIC-RELOCS-NEXT:]
diff --git a/test/ELF/multiple-cu.s b/test/ELF/multiple-cu.s
new file mode 100644
index 000000000000..996a7bcd06d4
--- /dev/null
+++ b/test/ELF/multiple-cu.s
@@ -0,0 +1,38 @@
+# 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/multiple-cu.s -o %t2.o
+# RUN: ld.lld -r -o %t.o %t1.o %t2.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: foo
+# CHECK-NEXT: referenced by test1.c:2
+
+# CHECK: error: undefined symbol: bar
+# CHECK-NEXT: referenced by test2.c:2
+
+ .globl _start
+_start:
+ .file 1 "test1.c"
+ .loc 1 2 0
+ jmp foo
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+ .long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+ .long .debug_line # DW_AT_stmt_list
+.Lend0:
+ .section .debug_line,"",@progbits
diff --git a/test/ELF/new-dtags.test b/test/ELF/new-dtags.test
index 1ae328c6b502..bceea4bd6d65 100644
--- a/test/ELF/new-dtags.test
+++ b/test/ELF/new-dtags.test
@@ -1,8 +1,12 @@
# REQUIRES: x86
// 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: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2
+// RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s
+
+// RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags --enable-new-dtags -o %t2
// RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s
// DISABLE: DynamicSection [
diff --git a/test/ELF/no-augmentation.s b/test/ELF/no-augmentation.s
index 31cd92e39b1c..f4912ba68366 100644
--- a/test/ELF/no-augmentation.s
+++ b/test/ELF/no-augmentation.s
@@ -1,7 +1,6 @@
-// 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
+// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o /dev/null | FileCheck -allow-empty %s
// CHECK-NOT: corrupted or unsupported CIE information
// CHECK-NOT: corrupted CIE
diff --git a/test/ELF/no-dynamic-linker.s b/test/ELF/no-dynamic-linker.s
deleted file mode 100644
index f5c7f4b8d072..000000000000
--- a/test/ELF/no-dynamic-linker.s
+++ /dev/null
@@ -1,12 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %tso.o
-# RUN: ld.lld -shared %tso.o -o %t.so
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-
-# RUN: ld.lld -dynamic-linker foo --no-dynamic-linker %t.o %t.so -o %t
-# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=NODL
-# NODL-NOT: PT_INTERP
-
-# RUN: ld.lld --no-dynamic-linker -dynamic-linker foo %t.o %t.so -o %t
-# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=WITHDL
-# WITHDL: PT_INTERP
diff --git a/test/ELF/no-inhibit-exec.s b/test/ELF/no-inhibit-exec.s
index afb7aed94c12..1535f6e7b87e 100644
--- a/test/ELF/no-inhibit-exec.s
+++ b/test/ELF/no-inhibit-exec.s
@@ -1,9 +1,9 @@
+# REQUIRES: x86
# 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
# RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=RELOC
-# REQUIRES: x86
# CHECK: Disassembly of section .text:
# CHECK-NEXT: _start
diff --git a/test/ELF/no-line-parser-errors-if-empty-section.s b/test/ELF/no-line-parser-errors-if-empty-section.s
new file mode 100644
index 000000000000..808052e7ff0b
--- /dev/null
+++ b/test/ELF/no-line-parser-errors-if-empty-section.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# LLD uses the debug data to get information for error messages, if possible.
+# However, if the debug line section is empty, we should not attempt to parse
+# it, as that would result in errors from the parser.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+# CHECK: error: undefined symbol: undefined
+# CHECK-NEXT: {{.*}}.o:(.text+0x1)
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+
+.globl _start
+_start:
+ callq undefined
+
+.section .debug_line,"",@progbits
diff --git a/test/ELF/no-line-parser-errors-if-no-section.s b/test/ELF/no-line-parser-errors-if-no-section.s
new file mode 100644
index 000000000000..4624601315d6
--- /dev/null
+++ b/test/ELF/no-line-parser-errors-if-no-section.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# LLD uses the debug data to get information for error messages, if possible.
+# However, if there is no debug line section, we should not attempt to parse
+# it, as that would result in errors from the parser.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+# CHECK: error: undefined symbol: undefined
+# CHECK-NEXT: {{.*}}.o:(.text+0x1)
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+
+.globl _start
+_start:
+ callq undefined
diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s
index 693cdf1e9d3f..1a4bf98c181e 100644
--- a/test/ELF/no-obj.s
+++ b/test/ELF/no-obj.s
@@ -1,7 +1,7 @@
// REQUIRES: x86
// 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
+// RUN: not ld.lld -o /dev/null -u _start %t.a 2>&1 | FileCheck %s
// CHECK: target emulation unknown: -m or at least one .o file required
diff --git a/test/ELF/no-symtab.s b/test/ELF/no-symtab.s
index af9df13e9768..2468c4f05fc4 100644
--- a/test/ELF/no-symtab.s
+++ b/test/ELF/no-symtab.s
@@ -1,5 +1,5 @@
// REQUIRES: x86
// 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
+// RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o /dev/null
.global _start
_start:
diff --git a/test/ELF/no-undefined.s b/test/ELF/no-undefined.s
index 493a38987091..854114b6a072 100644
--- a/test/ELF/no-undefined.s
+++ b/test/ELF/no-undefined.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# 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
+# RUN: not ld.lld --no-undefined -shared %t -o /dev/null
+# RUN: ld.lld -shared %t -o /dev/null
.globl _shared
_shared:
diff --git a/test/ELF/non-abs-reloc.s b/test/ELF/non-abs-reloc.s
index 454104cca076..ac69915b1b53 100644
--- a/test/ELF/non-abs-reloc.s
+++ b/test/ELF/non-abs-reloc.s
@@ -1,11 +1,21 @@
// 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
-// CHECK: {{.*}}:(.dummy+0x0): has non-ABS relocation R_X86_64_GOTPCREL against symbol 'foo'
+// RUN: ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: (.nonalloc+0x1): has non-ABS relocation R_X86_64_PC32 against symbol '_start'
+// CHECK: (.nonalloc+0x6): has non-ABS relocation R_X86_64_PC32 against symbol '_start'
+
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DISASM %s
+// DISASM: Disassembly of section .nonalloc:
+// DISASM-NEXT: .nonalloc:
+// DISASM-NEXT: 0: {{.*}} callq {{.*}} <_start>
+// DISASM-NEXT: 5: {{.*}} callq {{.*}} <_start>
.globl _start
_start:
nop
-.section .dummy
- .long foo@gotpcrel
+.section .nonalloc
+ .byte 0xe8
+ .long _start - . - 4
+ .byte 0xe8
+ .long _start - . - 4
diff --git a/test/ELF/non-alloc-link-order-gc.s b/test/ELF/non-alloc-link-order-gc.s
new file mode 100644
index 000000000000..8147c45090d9
--- /dev/null
+++ b/test/ELF/non-alloc-link-order-gc.s
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1 --gc-sections
+# RUN: llvm-objdump -section-headers -D %t1 | FileCheck %s
+
+## Check that we are able to GC non-allocatable metadata sections without crash.
+
+# CHECK: Disassembly of section .stack_sizes:
+# CHECK-NEXT: .stack_sizes:
+# CHECK-NEXT: 01
+
+# CHECK: Name Size
+# CHECK: .stack_sizes 00000001
+
+.section .text.live,"ax",@progbits
+.globl live
+live:
+ nop
+
+.section .stack_sizes,"o",@progbits,.text.live,unique,0
+.byte 1
+
+.section .text.dead,"ax",@progbits
+.globl dead
+dead:
+ nop
+
+.section .stack_sizes,"o",@progbits,.text.dead,unique,1
+.byte 2
+
+.section .text.main,"ax",@progbits
+.globl _start
+_start:
+ callq live@PLT
diff --git a/test/ELF/note-contiguous.s b/test/ELF/note-contiguous.s
index f49d0b68ca33..7b04e9849320 100644
--- a/test/ELF/note-contiguous.s
+++ b/test/ELF/note-contiguous.s
@@ -1,24 +1,42 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: echo "SECTIONS { \
-// RUN: .note : { *(.note.a) *(.note.b) } \
-// RUN: }" > %t.script
-// RUN: ld.lld %t.o --script %t.script -o %t
-// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -program-headers %t1 | FileCheck %s
// CHECK: Type: PT_NOTE
-// CHECK-NEXT: Offset: 0x1000
-// CHECK-NEXT: VirtualAddress: 0x0
-// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress:
+// CHECK-NEXT: PhysicalAddress:
// CHECK-NEXT: FileSize: 16
// CHECK-NEXT: MemSize: 16
-// CHECK-NEXT: Flags [
+// CHECK-NEXT: Flags [
// CHECK-NEXT: PF_R
// CHECK-NEXT: ]
// CHECK-NEXT: Alignment: 1
+// CHECK-NOT: Type: PT_NOTE
+
+// RUN: echo "SECTIONS { .note : { *(.note.a) *(.note.b) } }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t2
+// RUN: llvm-readobj -program-headers %t2 | FileCheck -check-prefix=SCRIPT %s
+
+// SCRIPT: Type: PT_NOTE
+// SCRIPT-NEXT: Offset:
+// SCRIPT-NEXT: VirtualAddress:
+// SCRIPT-NEXT: PhysicalAddress:
+// SCRIPT-NEXT: FileSize: 16
+// SCRIPT-NEXT: MemSize: 16
+// SCRIPT-NEXT: Flags [
+// SCRIPT-NEXT: PF_R
+// SCRIPT-NEXT: ]
+// SCRIPT-NEXT: Alignment: 1
+// SCRIPT-NOT: Type: PT_NOTE
.section .note.a, "a", @note
.quad 0
+.section .foo, "a"
+.quad 0
+
.section .note.b, "a", @note
.quad 0
diff --git a/test/ELF/note-loadaddr.c b/test/ELF/note-loadaddr.s
index 6d2ebaeeaa0a..6d2ebaeeaa0a 100644
--- a/test/ELF/note-loadaddr.c
+++ b/test/ELF/note-loadaddr.s
diff --git a/test/ELF/note-noalloc.s b/test/ELF/note-noalloc.s
new file mode 100644
index 000000000000..80c7a4d23a03
--- /dev/null
+++ b/test/ELF/note-noalloc.s
@@ -0,0 +1,38 @@
+// 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 -sections %t | FileCheck %s
+
+// PR37361: A note without SHF_ALLOC should not be included into a PT_NOTE program header.
+
+// CHECK: Section {
+// CHECK: Index:
+// CHECK: Name: .note.a
+// CHECK-NEXT: Type: SHT_NOTE
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x[[ADDR:.*]]
+
+// Check we still emit the non-alloc SHT_NOTE section and keep its type.
+
+// CHECK: Name: .note.b
+// CHECK-NEXT: Type: SHT_NOTE
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+
+// CHECK: ProgramHeader {
+// CHECK: Type: PT_NOTE
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress: 0x[[ADDR]]
+// CHECK-NEXT: PhysicalAddress: 0x[[ADDR]]
+// CHECK-NEXT: FileSize: 16
+// CHECK-NEXT: MemSize: 16
+// CHECK-NOT: PT_NOTE
+
+.section .note.a,"a",@note
+.quad 1
+.quad 2
+
+.section .note.b,"",@note
+.quad 3
diff --git a/test/ELF/note-noalloc2.s b/test/ELF/note-noalloc2.s
new file mode 100644
index 000000000000..3705799d45cb
--- /dev/null
+++ b/test/ELF/note-noalloc2.s
@@ -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
+# RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+## Check we do not create a PT_NOTE segment for non-allocatable note section.
+
+# CHECK-NOT: PT_NOTE
+
+.section .note,"",@note
+.quad 0
diff --git a/test/ELF/oformat-binary.s b/test/ELF/oformat-binary.s
index acd95c7cef36..44c7b5ac2d8d 100644
--- a/test/ELF/oformat-binary.s
+++ b/test/ELF/oformat-binary.s
@@ -15,7 +15,7 @@
# RUN: ld.lld -o %t2.out --script %t.script %t --oformat binary
# RUN: od -t x1 -v %t2.out | FileCheck %s
-# RUN: not ld.lld -o %t3.out %t --oformat foo 2>&1 \
+# RUN: not ld.lld -o /dev/null %t --oformat foo 2>&1 \
# RUN: | FileCheck %s --check-prefix ERR
# ERR: unknown --oformat value: foo
diff --git a/test/ELF/output-section.s b/test/ELF/output-section.s
index 68505254686c..2a119d998218 100644
--- a/test/ELF/output-section.s
+++ b/test/ELF/output-section.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/pack-dyn-relocs.s b/test/ELF/pack-dyn-relocs.s
index cb8674318ec6..b37729dd890b 100644
--- a/test/ELF/pack-dyn-relocs.s
+++ b/test/ELF/pack-dyn-relocs.s
@@ -5,12 +5,10 @@
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.a32
// RUN: ld.lld -pie --pack-dyn-relocs=none %t.a32 %t.a32.so -o %t2.a32
// RUN: llvm-readobj -relocations %t2.a32 | FileCheck --check-prefix=UNPACKED32 %s
-// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32
-// RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=PACKED32-HEADERS %s
-// RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=PACKED32 %s
// Unpacked should have the relative relocations in their natural order.
-// UNPACKED32: 0x1000 R_ARM_RELATIVE - 0x0
+// UNPACKED32: Section ({{.+}}) .rel.dyn {
+// UNPACKED32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0
// UNPACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0
// UNPACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0
// UNPACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0
@@ -37,70 +35,146 @@
// UNPACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0
// UNPACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0
+// UNPACKED32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0
// UNPACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0
// UNPACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0
+// UNPACKED32-NEXT: }
+
+// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32
+// RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=ANDROID32-HEADERS %s
+// RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=ANDROID32 %s
+
+// ANDROID32-HEADERS: Index: 1
+// ANDROID32-HEADERS-NEXT: Name: .dynsym
+
+// ANDROID32-HEADERS: Name: .rel.dyn
+// ANDROID32-HEADERS-NEXT: Type: SHT_ANDROID_REL
+// ANDROID32-HEADERS-NEXT: Flags [ (0x2)
+// ANDROID32-HEADERS-NEXT: SHF_ALLOC (0x2)
+// ANDROID32-HEADERS-NEXT: ]
+// ANDROID32-HEADERS-NEXT: Address: [[ADDR:.*]]
+// ANDROID32-HEADERS-NEXT: Offset: [[ADDR]]
+// ANDROID32-HEADERS-NEXT: Size: [[SIZE:.*]]
+// ANDROID32-HEADERS-NEXT: Link: 1
+// ANDROID32-HEADERS-NEXT: Info: 0
+// ANDROID32-HEADERS-NEXT: AddressAlignment: 4
+// ANDROID32-HEADERS-NEXT: EntrySize: 1
-// PACKED32-HEADERS: Index: 1
-// PACKED32-HEADERS-NEXT: Name: .dynsym
-
-// PACKED32-HEADERS: Name: .rel.dyn
-// PACKED32-HEADERS-NEXT: Type: SHT_ANDROID_REL
-// PACKED32-HEADERS-NEXT: Flags [ (0x2)
-// PACKED32-HEADERS-NEXT: SHF_ALLOC (0x2)
-// PACKED32-HEADERS-NEXT: ]
-// PACKED32-HEADERS-NEXT: Address: [[ADDR:.*]]
-// PACKED32-HEADERS-NEXT: Offset: [[ADDR]]
-// PACKED32-HEADERS-NEXT: Size: [[SIZE:.*]]
-// PACKED32-HEADERS-NEXT: Link: 1
-// PACKED32-HEADERS-NEXT: Info: 0
-// PACKED32-HEADERS-NEXT: AddressAlignment: 4
-// PACKED32-HEADERS-NEXT: EntrySize: 1
-
-// PACKED32-HEADERS: 0x6000000F ANDROID_REL [[ADDR]]
-// PACKED32-HEADERS: 0x60000010 ANDROID_RELSZ [[SIZE]]
+// ANDROID32-HEADERS: 0x6000000F ANDROID_REL [[ADDR]]
+// ANDROID32-HEADERS: 0x60000010 ANDROID_RELSZ [[SIZE]]
// Packed should have the larger groups of relative relocations first,
// i.e. the 8 and 9 followed by the 7.
-// PACKED32: 0x1000 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x101C R_ARM_RELATIVE - 0x0
-
-// PACKED32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x104C R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x105C R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0
-
-// PACKED32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x102C R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0
-// PACKED32-NEXT: 0x103C R_ARM_RELATIVE - 0x0
-
-// PACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0
-// PACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0
+// ANDROID32: Section ({{.+}}) .rel.dyn {
+// ANDROID32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x100C R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x101C R_ARM_RELATIVE - 0x0
+
+// ANDROID32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x104C R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x105C R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0
+
+// ANDROID32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x102C R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x103C R_ARM_RELATIVE - 0x0
+
+// ANDROID32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0
+// ANDROID32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0
+// ANDROID32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0
+// ANDROID32-NEXT: }
+
+// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a32 %t.a32.so -o %t4.a32
+// RUN: llvm-readobj -s -dynamic-table %t4.a32 | FileCheck --check-prefix=RELR32-HEADERS %s
+// RUN: llvm-readobj -relocations -raw-relr %t4.a32 | FileCheck --check-prefix=RAW-RELR32 %s
+// RUN: llvm-readobj -relocations %t4.a32 | FileCheck --check-prefix=RELR32 %s
+
+// RELR32-HEADERS: Index: 1
+// RELR32-HEADERS-NEXT: Name: .dynsym
+
+// RELR32-HEADERS: Name: .relr.dyn
+// RELR32-HEADERS-NEXT: Type: SHT_RELR
+// RELR32-HEADERS-NEXT: Flags [ (0x2)
+// RELR32-HEADERS-NEXT: SHF_ALLOC (0x2)
+// RELR32-HEADERS-NEXT: ]
+// RELR32-HEADERS-NEXT: Address: [[ADDR:.*]]
+// RELR32-HEADERS-NEXT: Offset: [[ADDR]]
+// RELR32-HEADERS-NEXT: Size: 8
+// RELR32-HEADERS-NEXT: Link: 0
+// RELR32-HEADERS-NEXT: Info: 0
+// RELR32-HEADERS-NEXT: AddressAlignment: 4
+// RELR32-HEADERS-NEXT: EntrySize: 4
+
+// RELR32-HEADERS: 0x00000024 RELR [[ADDR]]
+// RELR32-HEADERS: 0x00000023 RELRSZ 0x8
+// RELR32-HEADERS: 0x00000025 RELRENT 0x4
+
+// SHT_RELR section contains address/bitmap entries
+// encoding the offsets for relative relocation.
+// RAW-RELR32: Section ({{.+}}) .relr.dyn {
+// RAW-RELR32-NEXT: 0x1000
+// RAW-RELR32-NEXT: 0x3FEFEFF
+// RAW-RELR32-NEXT: }
+
+// Decoded SHT_RELR section is same as UNPACKED,
+// but contains only the relative relocations.
+// Any relative relocations with odd offset stay in SHT_REL.
+// RELR32: Section ({{.+}}) .rel.dyn {
+// RELR32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0
+// RELR32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0
+// RELR32-NEXT: }
+// RELR32-NEXT: Section ({{.+}}) .relr.dyn {
+// RELR32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x100C R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x101C R_ARM_RELATIVE - 0x0
+
+// RELR32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x102C R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x103C R_ARM_RELATIVE - 0x0
+
+// RELR32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x104C R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x105C R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0
+// RELR32-NEXT: }
// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/shared2.s -o %t.a64.so.o
// RUN: ld.lld -shared %t.a64.so.o -o %t.a64.so
// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.a64
// RUN: ld.lld -pie --pack-dyn-relocs=none %t.a64 %t.a64.so -o %t2.a64
// RUN: llvm-readobj -relocations %t2.a64 | FileCheck --check-prefix=UNPACKED64 %s
-// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64
-// RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=PACKED64-HEADERS %s
-// RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=PACKED64 %s
-// UNPACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1
+// UNPACKED64: Section ({{.+}}) .rela.dyn {
+// UNPACKED64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1
// UNPACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2
// UNPACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3
// UNPACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4
@@ -127,59 +201,138 @@
// UNPACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8
// UNPACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9
+// UNPACKED64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA
// UNPACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1
// UNPACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0
+// UNPACKED64-NEXT: }
+
+// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64
+// RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=ANDROID64-HEADERS %s
+// RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=ANDROID64 %s
+
+// ANDROID64-HEADERS: Index: 1
+// ANDROID64-HEADERS-NEXT: Name: .dynsym
+
+// ANDROID64-HEADERS: Name: .rela.dyn
+// ANDROID64-HEADERS-NEXT: Type: SHT_ANDROID_RELA
+// ANDROID64-HEADERS-NEXT: Flags [ (0x2)
+// ANDROID64-HEADERS-NEXT: SHF_ALLOC (0x2)
+// ANDROID64-HEADERS-NEXT: ]
+// ANDROID64-HEADERS-NEXT: Address: [[ADDR:.*]]
+// ANDROID64-HEADERS-NEXT: Offset: [[ADDR]]
+// ANDROID64-HEADERS-NEXT: Size: [[SIZE:.*]]
+// ANDROID64-HEADERS-NEXT: Link: 1
+// ANDROID64-HEADERS-NEXT: Info: 0
+// ANDROID64-HEADERS-NEXT: AddressAlignment: 8
+// ANDROID64-HEADERS-NEXT: EntrySize: 1
+
+// ANDROID64-HEADERS: 0x0000000060000011 ANDROID_RELA [[ADDR]]
+// ANDROID64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]]
+
+// ANDROID64: Section ({{.+}}) .rela.dyn {
+// ANDROID64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1
+// ANDROID64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2
+// ANDROID64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3
+// ANDROID64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4
+// ANDROID64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5
+// ANDROID64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6
+// ANDROID64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7
+// ANDROID64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8
+
+// ANDROID64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1
+// ANDROID64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2
+// ANDROID64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3
+// ANDROID64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4
+// ANDROID64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5
+// ANDROID64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6
+// ANDROID64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7
+// ANDROID64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8
+// ANDROID64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9
+
+// ANDROID64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1
+// ANDROID64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2
+// ANDROID64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3
+// ANDROID64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4
+// ANDROID64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5
+// ANDROID64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6
+// ANDROID64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7
+
+// ANDROID64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA
+// ANDROID64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1
+// ANDROID64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0
+// ANDROID64-NEXT: }
+
+// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a64 %t.a64.so -o %t4.a64
+// RUN: llvm-readobj -s -dynamic-table %t4.a64 | FileCheck --check-prefix=RELR64-HEADERS %s
+// RUN: llvm-readobj -relocations -raw-relr %t4.a64 | FileCheck --check-prefix=RAW-RELR64 %s
+// RUN: llvm-readobj -relocations %t4.a64 | FileCheck --check-prefix=RELR64 %s
+
+// RELR64-HEADERS: Index: 1
+// RELR64-HEADERS-NEXT: Name: .dynsym
+
+// RELR64-HEADERS: Name: .relr.dyn
+// RELR64-HEADERS-NEXT: Type: SHT_RELR
+// RELR64-HEADERS-NEXT: Flags [ (0x2)
+// RELR64-HEADERS-NEXT: SHF_ALLOC (0x2)
+// RELR64-HEADERS-NEXT: ]
+// RELR64-HEADERS-NEXT: Address: [[ADDR:.*]]
+// RELR64-HEADERS-NEXT: Offset: [[ADDR]]
+// RELR64-HEADERS-NEXT: Size: 16
+// RELR64-HEADERS-NEXT: Link: 0
+// RELR64-HEADERS-NEXT: Info: 0
+// RELR64-HEADERS-NEXT: AddressAlignment: 8
+// RELR64-HEADERS-NEXT: EntrySize: 8
+
+// RELR64-HEADERS: 0x0000000000000024 RELR [[ADDR]]
+// RELR64-HEADERS: 0x0000000000000023 RELRSZ 0x10
+// RELR64-HEADERS: 0x0000000000000025 RELRENT 0x8
+
+// SHT_RELR section contains address/bitmap entries
+// encoding the offsets for relative relocation.
+// RAW-RELR64: Section ({{.+}}) .relr.dyn {
+// RAW-RELR64-NEXT: 0x10000
+// RAW-RELR64-NEXT: 0x3FEFEFF
+// RAW-RELR64-NEXT: }
+
+// Decoded SHT_RELR section is same as UNPACKED,
+// but contains only the relative relocations.
+// Any relative relocations with odd offset stay in SHT_RELA.
+// RELR64: Section ({{.+}}) .rela.dyn {
+// RELR64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA
+// RELR64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1
+// RELR64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0
+// RELR64-NEXT: }
+// RELR64-NEXT: Section ({{.+}}) .relr.dyn {
+// RELR64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x0
+
+// RELR64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x0
-// PACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1
-// PACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2
-// PACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3
-// PACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4
-// PACKED64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5
-// PACKED64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6
-// PACKED64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7
-// PACKED64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8
-
-// PACKED64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1
-// PACKED64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2
-// PACKED64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3
-// PACKED64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4
-// PACKED64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5
-// PACKED64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6
-// PACKED64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7
-// PACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8
-// PACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9
-
-// PACKED64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1
-// PACKED64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2
-// PACKED64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3
-// PACKED64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4
-// PACKED64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5
-// PACKED64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6
-// PACKED64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7
-
-// PACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1
-// PACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0
-
-// PACKED64-HEADERS: Index: 1
-// PACKED64-HEADERS-NEXT: Name: .dynsym
-
-// PACKED64-HEADERS: Name: .rela.dyn
-// PACKED64-HEADERS-NEXT: Type: SHT_ANDROID_RELA
-// PACKED64-HEADERS-NEXT: Flags [ (0x2)
-// PACKED64-HEADERS-NEXT: SHF_ALLOC (0x2)
-// PACKED64-HEADERS-NEXT: ]
-// PACKED64-HEADERS-NEXT: Address: [[ADDR:.*]]
-// PACKED64-HEADERS-NEXT: Offset: [[ADDR]]
-// PACKED64-HEADERS-NEXT: Size: [[SIZE:.*]]
-// PACKED64-HEADERS-NEXT: Link: 1
-// PACKED64-HEADERS-NEXT: Info: 0
-// PACKED64-HEADERS-NEXT: AddressAlignment: 8
-// PACKED64-HEADERS-NEXT: EntrySize: 1
-
-// PACKED64-HEADERS: 0x0000000060000011 ANDROID_RELA [[ADDR]]
-// PACKED64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]]
+// RELR64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x0
+// RELR64-NEXT: }
.data
+.align 2
.dc.a __ehdr_start + 1
.dc.a __ehdr_start + 2
.dc.a __ehdr_start + 3
@@ -208,3 +361,5 @@
.dc.a __ehdr_start + 7
.dc.a __ehdr_start + 8
.dc.a __ehdr_start + 9
+.byte 00
+.dc.a __ehdr_start + 10
diff --git a/test/ELF/pack-dyn-relocs2.s b/test/ELF/pack-dyn-relocs2.s
new file mode 100644
index 000000000000..20c7176a6061
--- /dev/null
+++ b/test/ELF/pack-dyn-relocs2.s
@@ -0,0 +1,85 @@
+// REQUIRES: arm, aarch64
+
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-shared.s -o %t.so.o
+// RUN: ld.lld -shared %t.so.o -o %t.so
+
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.o %t.so -o %t.exe
+// RUN: llvm-readobj -relocations %t.exe | FileCheck %s
+
+// CHECK: Section (5) .relr.dyn {
+// CHECK-NEXT: 0x1000 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1004 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1008 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x100C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1010 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1014 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1018 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x101C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1020 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1024 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1028 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x102C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1030 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1034 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1038 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x103C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1040 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1044 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1048 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x104C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1050 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1054 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1058 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x105C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1060 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1064 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1068 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x106C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1070 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1074 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1078 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x107C R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1080 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: 0x1084 R_ARM_RELATIVE - 0x0
+// CHECK-NEXT: }
+
+// RUN: llvm-readobj -s -dynamic-table %t.exe | FileCheck --check-prefix=HEADER %s
+// HEADER: 0x00000023 RELRSZ 0xC
+
+.data
+.align 2
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
+.dc.a __ehdr_start
diff --git a/test/ELF/pie.s b/test/ELF/pie.s
index 5964db5c9399..ccab1623cd5c 100644
--- a/test/ELF/pie.s
+++ b/test/ELF/pie.s
@@ -48,7 +48,9 @@
# CHECK: Type: PT_DYNAMIC
## Check -nopie
-# RUN: ld.lld -nopie %t1.o -o %t2
+# RUN: ld.lld -no-pie %t1.o -o %t2
+# RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE
+# RUN: ld.lld -no-pic-executable %t1.o -o %t2
# RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE
# NOPIE-NOT: Type: SharedObject
diff --git a/test/ELF/plt-aarch64.s b/test/ELF/plt-aarch64.s
index 372186b4b1f4..8f637bf593f4 100644
--- a/test/ELF/plt-aarch64.s
+++ b/test/ELF/plt-aarch64.s
@@ -1,3 +1,4 @@
+// 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/plt-aarch64.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
@@ -10,8 +11,6 @@
// 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 [
diff --git a/test/ELF/plt-i686.s b/test/ELF/plt-i686.s
index 9a2c7f53dc59..c24cab20e769 100644
--- a/test/ELF/plt-i686.s
+++ b/test/ELF/plt-i686.s
@@ -1,3 +1,4 @@
+// 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: ld.lld -shared %t2.o -o %t2.so
@@ -9,7 +10,6 @@
// 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
diff --git a/test/ELF/plt.s b/test/ELF/plt.s
index 4ab81aaaed91..cce60d732063 100644
--- a/test/ELF/plt.s
+++ b/test/ELF/plt.s
@@ -1,3 +1,4 @@
+// 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/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
@@ -8,8 +9,6 @@
// 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 [
diff --git a/test/ELF/ppc-rela.s b/test/ELF/ppc-rela.s
new file mode 100644
index 000000000000..430c5a748181
--- /dev/null
+++ b/test/ELF/ppc-rela.s
@@ -0,0 +1,11 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2 -shared
+# RUN: llvm-readobj -r %t2 | FileCheck %s
+
+.data
+ .long foo
+
+// CHECK: Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT: 0x1000 R_PPC_ADDR32 foo 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/ppc-relocs.s b/test/ELF/ppc-relocs.s
index 5aa3474e6339..26810008bd12 100644
--- a/test/ELF/ppc-relocs.s
+++ b/test/ELF/ppc-relocs.s
@@ -1,7 +1,7 @@
+# REQUIRES: ppc
# 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
diff --git a/test/ELF/ppc64-abi-version.s b/test/ELF/ppc64-abi-version.s
new file mode 100644
index 000000000000..806a71ed8fa1
--- /dev/null
+++ b/test/ELF/ppc64-abi-version.s
@@ -0,0 +1,11 @@
+# REQUIRES: ppc
+
+# RUN: echo '.abiversion 1' | llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux - -o %t1.o
+# RUN: not ld.lld -o /dev/null %t1.o 2>&1 | FileCheck -check-prefix=ERR1 %s
+
+# ERR1: ABI version 1 is not supported
+
+# RUN: echo '.abiversion 3' | llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux - -o %t1.o
+# RUN: not ld.lld -o /dev/null %t1.o 2>&1 | FileCheck -check-prefix=ERR2 %s
+
+# ERR2: unrecognized e_flags: 3
diff --git a/test/ELF/ppc64-addr16-error.s b/test/ELF/ppc64-addr16-error.s
index f16ca69957a3..5ffca587d6e5 100644
--- a/test/ELF/ppc64-addr16-error.s
+++ b/test/ELF/ppc64-addr16-error.s
@@ -1,7 +1,12 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s
+
// 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
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s
.short sym+65539
diff --git a/test/ELF/ppc64-dtprel.s b/test/ELF/ppc64-dtprel.s
new file mode 100644
index 000000000000..43922fa80382
--- /dev/null
+++ b/test/ELF/ppc64-dtprel.s
@@ -0,0 +1,204 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisLE %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisBE %s
+
+ .text
+ .abiversion 2
+ .globl test
+ .p2align 4
+ .type test,@function
+test:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, i@got@tlsld@ha
+ addi 3, 3, i@got@tlsld@l
+ bl __tls_get_addr(i@tlsld)
+ nop
+ addi 4, 3, i@dtprel
+ lwa 4, i@dtprel(3)
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl test_64
+ .p2align 4
+ .type test_64,@function
+
+ .globl test_adjusted
+ .p2align 4
+ .type test_adjusted,@function
+test_adjusted:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test_adjusted, .Lfunc_lep1-.Lfunc_gep1
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, k@got@tlsld@ha
+ addi 3, 3, k@got@tlsld@l
+ bl __tls_get_addr(k@tlsld)
+ nop
+ lis 4, k@dtprel@highesta
+ ori 4, 4, k@dtprel@highera
+ lis 5, k@dtprel@ha
+ addi 5, 5, k@dtprel@l
+ sldi 4, 4, 32
+ or 4, 4, 5
+ add 3, 3, 4
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl test_not_adjusted
+ .p2align 4
+ .type test_not_adjusted,@function
+test_not_adjusted:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test_not_adjusted, .Lfunc_lep2-.Lfunc_gep2
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, i@got@tlsld@ha
+ addi 3, 3, i@got@tlsld@l
+ bl __tls_get_addr(k@tlsld)
+ nop
+ lis 4, k@dtprel@highest
+ ori 4, 4, k@dtprel@higher
+ sldi 4, 4, 32
+ oris 4, 4, k@dtprel@h
+ ori 4, 4, k@dtprel@l
+ add 3, 3, 4
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl test_got_dtprel
+ .p2align 4
+ .type test_got_dtprel,@function
+test_got_dtprel:
+ addis 3, 2, i@got@dtprel@ha
+ ld 3, i@got@dtprel@l(3)
+ addis 3, 2, i@got@dtprel@h
+ addi 3, 2, i@got@dtprel
+
+ .section .debug_addr,"",@progbits
+ .quad i@dtprel+32768
+
+ .type i,@object
+ .section .tdata,"awT",@progbits
+ .space 1024
+ .p2align 2
+i:
+ .long 55
+ .size i, 4
+
+ .space 1024 * 1024 * 4
+ .type k,@object
+ .p2align 2
+k:
+ .long 128
+ .size k,4
+
+// Verify the input has all the remaining DTPREL based relocations we want to
+// test.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_DTPREL16 {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_DTPREL16_DS {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_DTPREL16_HIGHESTA {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_HIGHERA {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_HA {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_HIGHEST {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_HIGHER {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_HI {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0
+// InputRelocs: R_PPC64_GOT_DTPREL16_HA {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_GOT_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_GOT_DTPREL16_HI {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_GOT_DTPREL16_DS {{[0-9a-f]+}} i + 0
+// InputRelocs: Relocation section '.rela.debug_addr'
+// InputRelocs: R_PPC64_DTPREL64 {{[0-9a-f]+}} i + 8000
+
+// Expect a single dynamic relocation in the '.rela.dyn section for the module id.
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries:
+// OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+// OutputRelocs-NEXT: R_PPC64_DTPMOD64
+
+
+// i@dtprel --> (1024 - 0x8000) = -31744
+// Dis: test:
+// Dis: addi 4, 3, -31744
+// Dis: lwa 4, -31744(3)
+
+// #k@dtprel(1024 + 4 + 1024 * 1024 * 4) = 0x400404
+
+// #highesta(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 48) & 0xffff = 0
+// #highera(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 32) & 0xffff = 0
+// #ha(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 16) & 0xffff = 64
+// #lo(k@dtprel) --> ((0x400404 - 0x8000) & 0xffff = -31740
+// Dis: test_adjusted:
+// Dis: lis 4, 0
+// Dis: ori 4, 4, 0
+// Dis: lis 5, 64
+// Dis: addi 5, 5, -31740
+
+// #highest(k@dtprel) --> ((0x400404 - 0x8000) >> 48) & 0xffff = 0
+// #higher(k@dtprel) --> ((0x400404 - 0x8000) >> 32) & 0xffff = 0
+// #hi(k@dtprel) --> ((0x400404 - 0x8000) >> 16) & 0xffff = 63
+// #lo(k@dtprel) --> ((0x400404 - 0x8000) & 0xffff = 33796
+// Dis: test_not_adjusted:
+// Dis: lis 4, 0
+// Dis: ori 4, 4, 0
+// Dis: oris 4, 4, 63
+// Dis: ori 4, 4, 33796
+
+// Check for GOT entry for i. There should be a got entry which holds the offset
+// of i relative to the dynamic thread pointer.
+// i@dtprel -> (1024 - 0x8000) = 0xffff8400
+// GotDisBE: Disassembly of section .got:
+// GotDisBE: 4204f8: 00 00 00 00
+// GotDisBE: 4204fc: 00 42 84 f8
+// GotDisBE: 420510: ff ff ff ff
+// GotDisBE: 420514: ff ff 84 00
+
+// GotDisLE: Disassembly of section .got:
+// GotDisLE: 4204f8: f8 84 42 00
+// GotDisLE: 420510: 00 84 ff ff
+// GotDisLE: 420514: ff ff ff ff
+
+// Check that we have the correct offset to the got entry for i@got@dtprel
+// The got entry for i is 0x420510, and the TOC pointer is 0x4284f8.
+// #ha(i@got@dtprel) --> ((0x420510 - 0x4284f8 + 0x8000) >> 16) & 0xffff = 0
+// #lo(i@got@dtprel) --> (0x420510 - 0x4284f8) & 0xffff = -32744
+// #hi(i@got@dtprel) --> ((0x420510 - 0x4284f8) >> 16) & 0xffff = -1
+// i@got@dtprel --> 0x420510 - 0x4284f8 = -32744
+// Dis: test_got_dtprel:
+// Dis: addis 3, 2, 0
+// Dis: ld 3, -32744(3)
+// Dis: addis 3, 2, -1
+// Dis: addi 3, 2, -32744
diff --git a/test/ELF/ppc64-dynamic-relocations.s b/test/ELF/ppc64-dynamic-relocations.s
new file mode 100644
index 000000000000..2d9dfc6f804c
--- /dev/null
+++ b/test/ELF/ppc64-dynamic-relocations.s
@@ -0,0 +1,50 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-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-readobj -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+
+// 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-readobj -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+
+
+// The dynamic relocation for foo should point to 16 bytes past the start of
+// the .plt section.
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0
+
+// There should be 2 reserved doublewords before the first entry. The dynamic
+// linker will fill those in with the address of the resolver entry point and
+// the dynamic object identifier.
+// DIS: Idx Name Size Address Type
+// DIS: .plt 00000018 0000000010030000 BSS
+
+// DT_PLTGOT should point to the start of the .plt section.
+// DT: 0x0000000000000003 PLTGOT 0x10030000
+
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
+ li 0, 1
+ sc
+ .size _start, .-.Lfunc_begin0
diff --git a/test/ELF/ppc64-error-toc-restore.s b/test/ELF/ppc64-error-toc-restore.s
new file mode 100644
index 000000000000..19153b730ce1
--- /dev/null
+++ b/test/ELF/ppc64-error-toc-restore.s
@@ -0,0 +1,20 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// 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: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# Calling external function bar needs a nop
+// CHECK: call lacks nop, can't restore toc
+ .text
+ .abiversion 2
+
+.global _start
+_start:
+ bl foo
diff --git a/test/ELF/ppc64-error-toc-tail-call.s b/test/ELF/ppc64-error-toc-tail-call.s
new file mode 100644
index 000000000000..da8fea26cc23
--- /dev/null
+++ b/test/ELF/ppc64-error-toc-tail-call.s
@@ -0,0 +1,20 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// 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: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# A tail call to an external function without a nop should issue an error.
+// CHECK: call lacks nop, can't restore toc
+ .text
+ .abiversion 2
+
+.global _start
+_start:
+ b foo
diff --git a/test/ELF/ppc64-func-entry-points.s b/test/ELF/ppc64-func-entry-points.s
new file mode 100644
index 000000000000..640c94fe8cfb
--- /dev/null
+++ b/test/ELF/ppc64-func-entry-points.s
@@ -0,0 +1,80 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -48(1)
+ li 3, 1
+ li 4, 1
+ std 30, 32(1) # 8-byte Folded Spill
+ bl foo_external_same
+ nop
+ mr 30, 3
+ li 3, 2
+ li 4, 2
+ bl foo_external_diff
+ nop
+ addis 4, 2, .LC0@toc@ha
+ add 3, 3, 30
+ ld 30, 32(1) # 8-byte Folded Reload
+ ld 4, .LC0@toc@l(4)
+ lwz 4, 0(4)
+ add 3, 3, 4
+ extsw 3, 3
+ addi 1, 1, 48
+ ld 0, 16(1)
+ li 0, 1
+ sc
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob[TC],glob
+ .type glob,@object # @glob
+ .data
+ .globl glob
+ .p2align 2
+glob:
+ .long 10 # 0xa
+ .size glob, 4
+
+# Check that foo_external_diff has a global entry point and we branch to
+# foo_external_diff+8. Also check that foo_external_same has no global entry
+# point and we branch to start of foo_external_same.
+
+// CHECK: _start:
+// CHECK: 10010020: {{.*}} bl .+144
+// CHECK: 10010034: {{.*}} bl .+84
+// CHECK: foo_external_diff:
+// CHECK-NEXT: 10010080: {{.*}} addis 2, 12, 2
+// CHECK-NEXT: 10010084: {{.*}} addi 2, 2, 32640
+// CHECK-NEXT: 10010088: {{.*}} addis 5, 2, 0
+// CHECK: foo_external_same:
+// CHECK-NEXT: 100100b0: {{.*}} add 3, 4, 3
diff --git a/test/ELF/ppc64-gd-to-ie.s b/test/ELF/ppc64-gd-to-ie.s
new file mode 100644
index 000000000000..1a6cc5b5f2a0
--- /dev/null
+++ b/test/ELF/ppc64-gd-to-ie.s
@@ -0,0 +1,104 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld %t.o %t3.so -o %t
+# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld %t.o %t3.so -o %t
+# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, a@got@tlsgd@ha
+ addi 3, 3, a@got@tlsgd@l
+ bl __tls_get_addr(a@tlsgd)
+ nop
+ lwa 3, 0(3)
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+
+ .globl other_reg
+ .p2align 4
+ .type other_reg,@function
+other_reg:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry other_reg, .Lfunc_lep1-.Lfunc_gep1
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 5, 2, a@got@tlsgd@ha
+ addi 3, 5, a@got@tlsgd@l
+ bl __tls_get_addr(a@tlsgd)
+ nop
+ lwa 4, 0(3)
+ addis 30, 2, b@got@tlsgd@ha
+ addi 3, 30, b@got@tlsgd@l
+ bl __tls_get_addr(b@tlsgd)
+ nop
+ lwa 3, 0(3)
+ add 3, 4, 3
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl __tls_get_addr
+ .type __tls_get_addr,@function
+__tls_get_addr:
+
+
+# CheckGot: .got 00000018 00000000100200c0 DATA
+# .got is at 0x100200c0 so the toc-base is 100280c0.
+# `a` is at .got[1], we expect the offsets to be:
+# Ha(a) = ((0x100200c8 - 0x100280c0) + 0x8000) >> 16 = 0
+# Lo(a) = (0x100200c8 - 0x100280c0) = -32760
+
+# Dis-LABEL: _start
+# Dis: addis 3, 2, 0
+# Dis-NEXT: ld 3, -32760(3)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+
+# Dis-LABEL: other_reg
+# Dis: addis 5, 2, 0
+# Dis-NEXT: ld 3, -32760(5)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+# Dis: addis 30, 2, 0
+# Dis: ld 3, -32752(30)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+
+# Verify that the only dynamic relocations we emit are TPREL ones rather then
+# the DTPMOD64/DTPREL64 pair for general-dynamic.
+# OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries:
+# OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} a + 0
+# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} b + 0
diff --git a/test/ELF/ppc64-general-dynamic-tls.s b/test/ELF/ppc64-general-dynamic-tls.s
new file mode 100644
index 000000000000..66dab936575f
--- /dev/null
+++ b/test/ELF/ppc64-general-dynamic-tls.s
@@ -0,0 +1,112 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test
+ .p2align 4
+ .type test,@function
+test:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 31, -8(1)
+ std 0, 16(1)
+ stdu 1, -48(1)
+ mr 31, 1
+ std 30, 32(31)
+ addis 3, 2, i@got@tlsgd@ha
+ addi 3, 3, i@got@tlsgd@l
+ bl __tls_get_addr(i@tlsgd)
+ nop
+ lwz 30, 0(3)
+ extsw 3, 30
+ ld 30, 32(31)
+ addi 1, 1, 48
+ ld 0, 16(1)
+ ld 31, -8(1)
+ mtlr 0
+ blr
+
+
+test_hi:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test2, .Lfunc_lep1-.Lfunc_gep1
+ addis 3, 0, j@got@tlsgd@h
+ blr
+
+test_16:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test16, .Lfunc_lep2-.Lfunc_gep2
+ addi 3, 0, k@got@tlsgd
+ blr
+
+// Verify that the input has every general-dynamic tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} i + 0
+// InputRelocs: R_PPC64_TLSGD {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16_HI {{0+}} j + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16 {{0+}} k + 0
+
+// There is 2 got entries for each tls variable that is accessed with the
+// general-dynamic model. The entries can be though of as a structure to be
+// filled in by the dynamic linker:
+// typedef struct {
+// unsigned long int ti_module; --> R_PPC64_DTPMOD64
+// unsigned long int ti_offset; --> R_PPC64_DTPREL64
+//} tls_index;
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 6 entries:
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} i + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} i + 0
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} j + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} j + 0
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} k + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} k + 0
+
+// Check that the got has 7 entires. (1 for the TOC and 3 structures of
+// 2 entries for the tls variables). Also verify the address so we can check
+// the offsets we calculated for each relocation type.
+// CheckGot: got 00000038 00000000000200f0
+
+// got starts at 0x200f0, so .TOC. will be 0x280f0.
+
+// We are building the address of the first tls_index in the got which starts at
+// 0x200f8 (got[1]).
+// #ha(i@got@tlsgd) --> (0x200f8 - 0x280f0 + 0x8000) >> 16 = 0
+// #lo(i@got@tlsgd) --> (0x200f8 - 0x280f0) & 0xFFFF = -7ff8 = -32760
+// Dis: test:
+// Dis: addis 3, 2, 0
+// Dis: addi 3, 3, -32760
+
+// Second tls_index starts at got[3].
+// #hi(j@got@tlsgd) --> (0x20108 - 0x280f0) >> 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// Third tls index is at got[5].
+// k@got@tlsgd --> (0x20118 - 0x280f0) = -0x7fd8 = -32728
+// Dis: test_16:
+// Dis: li 3, -32728
diff --git a/test/ELF/ppc64-got-indirect.s b/test/ELF/ppc64-got-indirect.s
new file mode 100644
index 000000000000..2837582c4d6b
--- /dev/null
+++ b/test/ELF/ppc64-got-indirect.s
@@ -0,0 +1,115 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-LE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-LE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-BE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# Make sure we calculate the offset correctly for a got-indirect access to a
+# global variable as described by the PPC64 ELF V2 abi.
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ addis 3, 2, .LC0@toc@ha
+ ld 3, .LC0@toc@l(3)
+ li 4, 0
+ stw 4, -12(1)
+ li 0,1
+ lwa 3, 0(3)
+ sc
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob[TC],glob
+ .type glob,@object # @glob
+ .data
+ .globl glob
+ .p2align 2
+glob:
+ .long 55 # 0x37
+ .size glob, 4
+
+# Verify the relocations emitted for glob are through the .toc
+
+# RELOCS-LE: Relocations [
+# RELOCS-LE: .rela.text {
+# RELOCS-LE: 0x0 R_PPC64_REL16_HA .TOC. 0x0
+# RELOCS-LE: 0x4 R_PPC64_REL16_LO .TOC. 0x4
+# RELOCS-LE: 0x8 R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-LE: 0xC R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-LE: }
+# RELOCS-LE: .rela.toc {
+# RELOCS-LE: 0x0 R_PPC64_ADDR64 glob 0x0
+# RELOCS-LE: }
+
+# RELOCS-BE: Relocations [
+# RELOCS-BE: .rela.text {
+# RELOCS-BE: 0x2 R_PPC64_REL16_HA .TOC. 0x2
+# RELOCS-BE: 0x6 R_PPC64_REL16_LO .TOC. 0x6
+# RELOCS-BE: 0xA R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-BE: 0xE R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-BE: }
+# RELOCS-BE: .rela.toc {
+# RELOCS-BE: 0x0 R_PPC64_ADDR64 glob 0x0
+# RELOCS-BE: }
+# RELOCS-BE:]
+
+# Verify that the global variable access is done through the correct
+# toc entry:
+# r2 = .TOC. = 0x10038000.
+# r3 = r2 - 32760 = 0x10030008 -> .toc entry for glob.
+
+# CHECK: _start:
+# CHECK-NEXT: 10010000: {{.*}} addis 2, 12, 3
+# CHECK-NEXT: 10010004: {{.*}} addi 2, 2, -32768
+# CHECK-NEXT: 10010008: {{.*}} addis 3, 2, 0
+# CHECK-NEXT: 1001000c: {{.*}} ld 3, -32760(3)
+# CHECK: 1001001c: {{.*}} lwa 3, 0(3)
+
+# CHECK-LE: Disassembly of section .data:
+# CHECK-LE-NEXT: glob:
+# CHECK-LE-NEXT: 10020000: 37 00 00 00
+
+# CHECK-LE: Disassembly of section .got:
+# CHECK-LE-NEXT: .got:
+# CHECK-LE-NEXT: 10030000: 00 80 03 10
+# CHECK-LE-NEXT: 10030004: 00 00 00 00
+
+# Verify that .toc comes right after .got
+# CHECK-LE: Disassembly of section .toc:
+# CHECK-LE: 10030008: 00 00 02 10
+
+# CHECK-BE: Disassembly of section .data:
+# CHECK-BE-NEXT: glob:
+# CHECK-BE-NEXT: 10020000: 00 00 00 37
+
+# CHECK-BE: Disassembly of section .got:
+# CHECK-BE-NEXT: .got:
+# CHECK-BE-NEXT: 10030000: 00 00 00 00
+# CHECK-BE-NEXT: 10030004: 10 03 80 00
+
+# Verify that .toc comes right after .got
+# CHECK-BE: Disassembly of section .toc:
+# CHECK-BE: 10030008: 00 00 00 00
+# CHECK-BE: 1003000c: 10 02 00 00
diff --git a/test/ELF/ppc64-ifunc.s b/test/ELF/ppc64-ifunc.s
new file mode 100644
index 000000000000..6f2d3318b9c2
--- /dev/null
+++ b/test/ELF/ppc64-ifunc.s
@@ -0,0 +1,87 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-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
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s
+
+# 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
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s
+
+# CHECK: Disassembly of section .text:
+
+# Tocbase + (0 << 16) + 32560
+# 0x100280e0 + 0 + 32560 = 0x10030010 (.plt[2])
+# CHECK: __plt_foo:
+# CHECK-NEXT: std 2, 24(1)
+# CHECK-NEXT: addis 12, 2, 0
+# CHECK-NEXT: ld 12, 32560(12)
+# CHECK-NEXT: mtctr 12
+# CHECK-NEXT: bctr
+
+# Tocbase + (0 << 16) + 32568
+# 0x100280e0 + 0 + 32568 = 0x1003018 (.plt[3])
+# CHECK: __plt_ifunc:
+# CHECK-NEXT: std 2, 24(1)
+# CHECK-NEXT: addis 12, 2, 0
+# CHECK-NEXT: ld 12, 32568(12)
+# CHECK-NEXT: mtctr 12
+# CHECK-NEXT: bctr
+
+# CHECK: ifunc:
+# CHECK-NEXT: 10010028: {{.*}} nop
+
+# CHECK: _start:
+# CHECK-NEXT: addis 2, 12, 2
+# CHECK-NEXT: addi 2, 2, -32588
+# CHECK-NEXT: bl .+67108812
+# CHECK-NEXT: ld 2, 24(1)
+# CHECK-NEXT: bl .+67108824
+# CHECK-NEXT: ld 2, 24(1)
+
+# Check tocbase
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: .got:
+# CHECK-NEXT: 100200e0
+
+# Check .plt address
+# DT_PLTGOT should point to the start of the .plt section.
+# DT: 0x0000000000000003 PLTGOT 0x10030000
+
+# Check that we emit the correct dynamic relocation type for an ifunc
+# DYNREL: 'PLT' relocation section at offset 0x{{[0-9a-f]+}} contains 48 bytes:
+# 48 bytes --> 2 Elf64_Rela relocations
+# DYNREL-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_JMP_SLOT {{0+}} foo + 0
+# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_IRELATIVE 10010028
+
+
+ .text
+ .abiversion 2
+
+.type ifunc STT_GNU_IFUNC
+.globl ifunc
+ifunc:
+ nop
+
+ .global _start
+ .type _start,@function
+
+_start:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
+ bl ifunc
+ nop
diff --git a/test/ELF/ppc64-initial-exec-tls.s b/test/ELF/ppc64-initial-exec-tls.s
new file mode 100644
index 000000000000..5218b68828ee
--- /dev/null
+++ b/test/ELF/ppc64-initial-exec-tls.s
@@ -0,0 +1,102 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .file "intial_exec.c"
+ .globl test_initial_exec # -- Begin function test_initial_exec
+ .p2align 4
+ .type test_initial_exec,@function
+test_initial_exec: # @test_initial_exec
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test_initial_exec, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ li 3, 0
+ stw 3, -12(1)
+ addis 3, 2, a@got@tprel@ha
+ ld 3, a@got@tprel@l(3)
+ lwzx 4, 3, a@tls
+ extsw 3, 4
+ blr
+
+
+test_hi:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test2, .Lfunc_lep1-.Lfunc_gep1
+ addis 3, 0, b@got@tprel@h
+ blr
+
+test_ds:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test16, .Lfunc_lep2-.Lfunc_gep2
+ addi 3, 0, c@got@tprel
+ blr
+
+// Verify that the input has every initial-exec tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} a + 0
+// InputRelocs: R_PPC64_TLS {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_HI {{0+}} b + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} c + 0
+
+// There is a got entry for each tls variable that is accessed with the
+// initial-exec model to be filled in by the dynamic linker.
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries:
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} a + 0
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} b + 0
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} c + 0
+
+// Check that the got has 4 entires. (1 for the TOC and 3 entries for TLS
+// variables). Also verify the address so we can check
+// the offsets we calculated for each relocation type.
+// CheckGot: got 00000020 00000000100200c0
+
+// GOT stats at 0x100200c0, so TOC will be 0x100280c0
+
+// We are building the address of the first TLS got entry which contains the
+// offset of the tls variable relative to the thread pointer.
+// 0x100200c8 (got[1]).
+// #ha(a@got@tprel) --> (0x100200c8 - 0x100280c0 + 0x8000) >> 16 = 0
+// #lo(a@got@tprel)) --> (0x100200c8 - 0x100280c0) & 0xFFFF = -7ff8 = -32760
+// Dis: test_initial_exec:
+// Dis: addis 3, 2, 0
+// Dis: ld 3, -32760(3)
+// Dis: lwzx 4, 3, 13
+
+// Second TLS got entry starts at got[2] 0x100200d0
+// #hi(b@got@tprel) --> (0x100200d0 - 0x100280c0) >> 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// Third TLS got entry starts at got[3] 0x100200d8.
+// c@got@tprel--> (0x100200d8. - 0x100280c0) = -0x7fe8 = 32744
+// Dis: test_ds:
+// Dis: li 3, -32744
diff --git a/test/ELF/ppc64-local-dynamic.s b/test/ELF/ppc64-local-dynamic.s
new file mode 100644
index 000000000000..57f324edbc63
--- /dev/null
+++ b/test/ELF/ppc64-local-dynamic.s
@@ -0,0 +1,128 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test
+ .p2align 4
+ .type test,@function
+test:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, i@got@tlsld@ha
+ addi 3, 3, i@got@tlsld@l
+ bl __tls_get_addr(i@tlsld)
+ nop
+ addis 3, 3, i@dtprel@ha
+ lwa 3, i@dtprel@l(3)
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl test_hi
+ .p2align 4
+ .type test_hi,@function
+test_hi:
+ lis 3, j@got@tlsld@h
+ blr
+
+ .globl test_16
+ .p2align 4
+ .type test_16,@function
+test_16:
+ li 3, k@got@tlsld
+ blr
+
+ .type i,@object
+ .section .tdata,"awT",@progbits
+ .p2align 2
+i:
+ .long 55
+ .size i, 4
+
+ .type j,@object
+ .section .tbss,"awT",@nobits
+ .p2align 2
+j:
+ .long 0
+ .size j, 4
+
+ .type k,@object
+ .section .tdata,"awT",@progbits
+ .p2align 3
+k:
+ .quad 66
+ .size k, 8
+
+// Verify that the input contains all the R_PPC64_GOT_TLSLD16* relocations, as
+// well as the DTPREL relocations used in a typical medium code model
+// local-dynamic variable access.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSLD16_HA {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16_LO {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_TLSLD {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_DTPREL16_HA {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16_HI {{[0-9a-f]+}} j + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16 {{[0-9a-f]+}} k + 0
+
+// The local dynamic version of tls needs to use the same mechanism to look up
+// a variables address as general-dynamic. ie a call to __tls_get_addr with the
+// address of a tls_index struct as the argument. However for local-dynamic
+// variables all will have the same ti_module, and the offset field is left as
+// as 0, so the same struct can be used for every local-dynamic variable
+// used in the shared-object.
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries:
+// OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+// OutputRelocs-NEXT: R_PPC64_DTPMOD64
+
+// Check that the got has 3 entries, 1 for the TOC and 1 stucture of 2 entries
+// for the tls variables. Also verify the address so we can check the offsets
+// we calculate for each relocation type.
+// CheckGot: got 00000018 0000000000020100
+
+// got starts at 0x20100 so .TOC. will be 0x28100, and the tls_index struct is
+// at 0x20108.
+
+// #ha(i@got@tlsld) --> (0x20108 - 0x28100 + 0x8000) >> 16 = 0
+// #lo(i@got@tlsld) --> (0x20108 - 0x28100) = -7ff8 = -32760
+// When calculating offset relative to the dynamic thread pointer we have to
+// adjust by 0x8000 since each DTV pointer points 0x8000 bytes past the start of
+// its TLS block.
+// #ha(i@dtprel) --> (0x0 -0x8000 + 0x8000) >> 16 = 0
+// #lo(i@dtprel) --> (0x0 -0x8000) = -0x8000 = -32768
+// Dis: test:
+// Dis: addis 3, 2, 0
+// Dis-NEXT: addi 3, 3, -32760
+// Dis-NEXT: bl .+67108804
+// Dis-NEXT: ld 2, 24(1)
+// Dis-NEXT: addis 3, 3, 0
+// Dis-NEXT: lwa 3, -32768(3)
+
+
+// #hi(j@got@tlsld) --> (0x20108 - 0x28100 ) > 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// k@got@tlsld --> (0x20108 - 0x28100) = -7ff8 = -32760
+// Dis: test_16:
+// Dis: li 3, -32760
diff --git a/test/ELF/ppc64-local-exec-tls.s b/test/ELF/ppc64-local-exec-tls.s
new file mode 100644
index 000000000000..ff8c2b90102c
--- /dev/null
+++ b/test/ELF/ppc64-local-exec-tls.s
@@ -0,0 +1,163 @@
+// REQUIRES: ppc
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test_local_exec # -- Begin function test_local_exec
+ .p2align 4
+ .type test_local_exec,@function
+test_local_exec: # @test_local_exec
+.Lfunc_begin0:
+# %bb.0: # %entry
+ li 3, 0
+ stw 3, -12(1)
+ addis 3, 13, a@tprel@ha
+ addi 3, 3, a@tprel@l
+ ld 3, 0(3)
+ mr 4, 3
+ extsw 3, 4
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size test_local_exec, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+test_tprel:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test_tprel, .Lfunc_lep1-.Lfunc_gep1
+ addi 3, 13, b@tprel
+ blr
+
+
+test_hi:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test_hi, .Lfunc_lep2-.Lfunc_gep2
+ addis 3, 13, b@tprel@h
+ blr
+
+test_ds:
+.Lfunc_gep3:
+ addis 2, 12, .TOC.-.Lfunc_gep3@ha
+ addi 2, 2, .TOC.-.Lfunc_gep3@l
+.Lfunc_lep3:
+ .localentry test_ds, .Lfunc_lep3-.Lfunc_gep3
+ ld 3, b@tprel, 13
+ blr
+
+test_lo_ds:
+.Lfunc_gep4:
+ addis 2, 12, .TOC.-.Lfunc_gep4@ha
+ addi 2, 2, .TOC.-.Lfunc_gep4@l
+.Lfunc_lep4:
+ .localentry test_lo_ds, .Lfunc_lep4-.Lfunc_gep4
+ ld 3, b@tprel@l, 13
+ blr
+
+test_highest_a:
+.Lfunc_gep5:
+ addis 2, 12, .TOC.-.Lfunc_gep5@ha
+ addi 2, 2, .TOC.-.Lfunc_gep5@l
+.Lfunc_lep5:
+ .localentry test_highest_a, .Lfunc_lep5-.Lfunc_gep5
+ lis 4, b@tprel@highesta
+ ori 4, 4, b@tprel@highera
+ lis 5, b@tprel@ha
+ addi 5, 5, b@tprel@l
+ sldi 4, 4, 32
+ or 4, 4, 5
+ add 3, 13, 4
+ blr
+
+test_highest:
+.Lfunc_gep6:
+ addis 2, 12, .TOC.-.Lfunc_gep6@ha
+ addi 2, 2, .TOC.-.Lfunc_gep6@l
+.Lfunc_lep6:
+ .localentry test_highest, .Lfunc_lep6-.Lfunc_gep6
+ lis 4, b@tprel@highest
+ ori 4, 4, b@tprel@higher
+ sldi 4, 4, 32
+ oris 4, 4, b@tprel@h
+ ori 4, 4, b@tprel@l
+ add 3, 13, 4
+ blr
+
+ .type a,@object # @a
+ .type b,@object # @b
+ .section .tdata,"awT",@progbits
+ .p2align 3
+a:
+ .quad 55 # 0x37
+ .size a, 8
+
+b:
+ .quad 55 # 0x37
+ .size b, 8
+
+// Verify that the input has every initial-exec tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_TPREL16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_TPREL16_LO {{0+}} a + 0
+// InputRelocs: R_PPC64_TPREL16 {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HI {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_DS {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_LO_DS {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHESTA {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHERA {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHEST {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHER {{0+8}} b + 0
+
+// The start of the TLS storage area is 0x7000 bytes before the thread pointer (r13).
+// We are building the address of the first TLS variable, relative to the thread pointer.
+// #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0
+// #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672
+// Dis: test_local_exec:
+// Dis: addis 3, 13, 0
+// Dis: addi 3, 3, -28672
+
+// We are building the offset for the second TLS variable
+// Offset within tls storage - 0x7000
+// b@tprel = 8 - 0x7000 = 28664
+// Dis: test_tprel:
+// Dis: addi 3, 13, -28664
+
+// #hi(b@tprel) --> (8 - 0x7000) >> 16 = -1
+// Dis: test_hi:
+// Dis: addis 3, 13, -1
+
+// b@tprel = 8 - 0x7000 = -28664
+// Dis: test_ds:
+// Dis: ld 3, -28664(13)
+
+// #lo(b@tprel) --> (8 - 0x7000) & 0xFFFF = -28664
+// Dis: test_lo_ds:
+// Dis: ld 3, -28664(13)
+
+// #highesta(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 48) & 0xFFFF = 0
+// #highera(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 32) & 0xFFFF = 0
+// #ha(k@dtprel) --> ((0x8 - 0x7000 + 0x8000) >> 16) & 0xFFFF = 0
+// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = -28664
+// Dis: test_highest_a:
+// Dis: lis 4, 0
+// Dis: ori 4, 4, 0
+// Dis: lis 5, 0
+// Dis: addi 5, 5, -28664
+
+// #highest(b@tprel) --> ((0x8 - 0x7000) >> 48) & 0xFFFF = 0xFFFF = -1
+// #higher(b@tprel) --> ((0x8 - 0x7000) >> 32) & 0xFFFF = 0xFFFF = 65535
+// #hi(k@dtprel) --> ((0x8 - 0x7000) >> 16) & 0xFFFF = 0xFFFF = 65535
+// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = 33796
+// Dis: test_highest:
+// Dis: lis 4, -1
+// Dis: ori 4, 4, 65535
+// Dis: oris 4, 4, 65535
+// Dis: ori 4, 4, 36872
diff --git a/test/ELF/ppc64-plt-stub.s b/test/ELF/ppc64-plt-stub.s
new file mode 100644
index 000000000000..a644f487b8be
--- /dev/null
+++ b/test/ELF/ppc64-plt-stub.s
@@ -0,0 +1,42 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-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
+
+// 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
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: __plt_foo:
+// CHECK-NEXT: std 2, 24(1)
+// CHECK-NEXT: addis 12, 2, 0
+// CHECK-NEXT: ld 12, 32560(12)
+// CHECK-NEXT: mtctr 12
+// CHECK-NEXT: bctr
+
+
+// CHECK: _start:
+// CHECK: bl .+67108824
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
+ li 0, 1
+ sc
+ .size _start, .-.Lfunc_begin0
diff --git a/test/ELF/ppc64-rel-calls.s b/test/ELF/ppc64-rel-calls.s
index f3b309f33dfb..4c79498dc56b 100644
--- a/test/ELF/ppc64-rel-calls.s
+++ b/test/ELF/ppc64-rel-calls.s
@@ -1,32 +1,29 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+
# 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"
+.text
.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
+# CHECK: 10010000: {{.*}} li 0, 1
+# CHECK: 10010004: {{.*}} li 3, 42
+# CHECK: 10010008: {{.*}} sc
-.section ".opd","aw"
.global bar
bar:
-.quad .Lbar,.TOC.@tocbase,0
-
-.text
-.Lbar:
bl _start
nop
bl .Lfoo
@@ -34,9 +31,8 @@ bar:
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
-
+# CHECK: 1001000c: {{.*}} bl .+67108852
+# CHECK: 10010010: {{.*}} nop
+# CHECK: 10010014: {{.*}} bl .+67108844
+# CHECK: 10010018: {{.*}} nop
+# CHECK: 1001001c: {{.*}} blr
diff --git a/test/ELF/ppc64-rel-so-local-calls.s b/test/ELF/ppc64-rel-so-local-calls.s
new file mode 100644
index 000000000000..834dbd50aa90
--- /dev/null
+++ b/test/ELF/ppc64-rel-so-local-calls.s
@@ -0,0 +1,87 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared -z notext %t.o -o %t.so
+// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared -z notext %t.o -o %t.so
+// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s
+
+
+// CHECK-NOT: foo
+// CHECK-NOT: bar
+
+ .text
+ .abiversion 2
+ .globl baz
+ .p2align 4
+ .type baz,@function
+baz:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry baz, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -64(1)
+ std 30, 48(1)
+ std 29, 40(1)
+ mr 30, 3
+ bl foo
+ mr 29, 3
+ mr 3, 30
+ bl bar
+ mullw 3, 3, 29
+ ld 30, 48(1)
+ ld 29, 40(1)
+ extsw 3, 3
+ addi 1, 1, 64
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size baz, .Lfunc_end0-.Lfunc_begin0
+
+ .p2align 4
+ .type foo,@function
+foo:
+.Lfunc_begin1:
+ mullw 3, 3, 3
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end1:
+ .size foo, .Lfunc_end1-.Lfunc_begin1
+
+ .p2align 4
+ .type bar,@function
+bar:
+.Lfunc_begin2:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry bar, .Lfunc_lep2-.Lfunc_gep2
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -48(1)
+ std 30, 32(1)
+ mr 30, 3
+ bl foo
+ mullw 3, 3, 30
+ ld 30, 32(1)
+ extsw 3, 3
+ addi 1, 1, 48
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end2:
+ .size bar, .Lfunc_end2-.Lfunc_begin2
diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s
index cb6177dfe305..88e3d4b13e5d 100644
--- a/test/ELF/ppc64-relocs.s
+++ b/test/ELF/ppc64-relocs.s
@@ -1,22 +1,33 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATALE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
# 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
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATABE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
-.section ".opd","aw"
+.text
.global _start
_start:
-.quad .Lfoo,.TOC.@tocbase,0
-
-.text
.Lfoo:
li 0,1
li 3,42
sc
-.section ".toc","aw"
+.section .rodata,"a",@progbits
+ .p2align 2
+.LJTI0_0:
+ .long .LBB0_2-.LJTI0_0
+
+.section .toc,"aw",@progbits
.L1:
.quad 22, 37, 89, 47
+.LC0:
+ .tc .LJTI0_0[TC],.LJTI0_0
.section .R_PPC64_TOC16_LO_DS,"ax",@progbits
.globl .FR_PPC64_TOC16_LO_DS
@@ -25,7 +36,7 @@ _start:
# 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)
+# CHECK: 1001000c: {{.*}} ld 1, -32768(2)
.section .R_PPC64_TOC16_LO,"ax",@progbits
.globl .FR_PPC64_TOC16_LO
@@ -34,7 +45,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_TOC16_LO:
# CHECK: .FR_PPC64_TOC16_LO:
-# CHECK: 10010010: 38 22 80 00 addi 1, 2, -32768
+# CHECK: 10010010: {{.*}} addi 1, 2, -32768
.section .R_PPC64_TOC16_HI,"ax",@progbits
.globl .FR_PPC64_TOC16_HI
@@ -43,7 +54,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_TOC16_HI:
# CHECK: .FR_PPC64_TOC16_HI:
-# CHECK: 10010014: 3c 22 ff fe addis 1, 2, -2
+# CHECK: 10010014: {{.*}} addis 1, 2, -1
.section .R_PPC64_TOC16_HA,"ax",@progbits
.globl .FR_PPC64_TOC16_HA
@@ -52,7 +63,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_TOC16_HA:
# CHECK: .FR_PPC64_TOC16_HA:
-# CHECK: 10010018: 3c 22 ff ff addis 1, 2, -1
+# CHECK: 10010018: {{.*}} addis 1, 2, 0
.section .R_PPC64_REL24,"ax",@progbits
.globl .FR_PPC64_REL24
@@ -63,7 +74,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_REL24:
# CHECK: .FR_PPC64_REL24:
-# CHECK: 1001001c: 48 00 00 04 b .+4
+# CHECK: 1001001c: {{.*}} b .+4
.section .R_PPC64_ADDR16_LO,"ax",@progbits
.globl .FR_PPC64_ADDR16_LO
@@ -72,7 +83,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_LO:
# CHECK: .FR_PPC64_ADDR16_LO:
-# CHECK: 10010020: 38 20 00 00 li 1, 0
+# CHECK: 10010020: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HI,"ax",@progbits
.globl .FR_PPC64_ADDR16_HI
@@ -81,7 +92,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HI:
# CHECK: .FR_PPC64_ADDR16_HI:
-# CHECK: 10010024: 38 20 10 01 li 1, 4097
+# CHECK: 10010024: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HA
@@ -90,7 +101,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HA:
# CHECK: .FR_PPC64_ADDR16_HA:
-# CHECK: 10010028: 38 20 10 01 li 1, 4097
+# CHECK: 10010028: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HIGHER,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHER
@@ -99,7 +110,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER:
# CHECK: .FR_PPC64_ADDR16_HIGHER:
-# CHECK: 1001002c: 38 20 00 00 li 1, 0
+# CHECK: 1001002c: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHERA
@@ -108,7 +119,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA:
# CHECK: .FR_PPC64_ADDR16_HIGHERA:
-# CHECK: 10010030: 38 20 00 00 li 1, 0
+# CHECK: 10010030: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHEST
@@ -117,7 +128,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST:
# CHECK: .FR_PPC64_ADDR16_HIGHEST:
-# CHECK: 10010034: 38 20 00 00 li 1, 0
+# CHECK: 10010034: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHESTA
@@ -126,5 +137,57 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA:
# CHECK: .FR_PPC64_ADDR16_HIGHESTA:
-# CHECK: 10010038: 38 20 00 00 li 1, 0
-
+# CHECK: 10010038: {{.*}} li 1, 0
+
+.section .R_PPC64_REL32, "ax",@progbits
+.globl .FR_PPC64_REL32
+.FR_PPC64_REL32:
+ addis 5, 2, .LC0@toc@ha
+ ld 5, .LC0@toc@l(5)
+.LBB0_2:
+ add 3, 3, 4
+
+# DATALE: Disassembly of section .rodata:
+# DATALE: .rodata:
+# DATALE: 10000190: b4 fe 00 00
+
+# DATABE: Disassembly of section .rodata:
+# DATABE: .rodata:
+# DATABE: 10000190: 00 00 fe b4
+
+# Address of rodata + value stored at rodata entry
+# should equal address of LBB0_2.
+# 0x10000190 + 0xfeb4 = 0x10010044
+# CHECK: Disassembly of section .R_PPC64_REL32:
+# CHECK: .FR_PPC64_REL32:
+# CHECK: 1001003c: {{.*}} addis 5, 2, 0
+# CHECK: 10010040: {{.*}} ld 5, -32736(5)
+# CHECK: 10010044: {{.*}} add 3, 3, 4
+
+.section .R_PPC64_REL64, "ax",@progbits
+.globl .FR_PPC64_REL64
+.FR_PPC64_REL64:
+ .cfi_startproc
+ .cfi_personality 148, __foo
+ li 0, 1
+ li 3, 55
+ sc
+ .cfi_endproc
+__foo:
+ li 3,0
+
+# Check that address of eh_frame entry + value stored
+# should equal the address of foo. Since it is not aligned,
+# the entry is not stored exactly at 100001a8. It starts at
+# address 0x100001aa and has the value 0xfeaa.
+# 0x100001aa + 0xfeaa = 0x10010054
+# DATALE: Disassembly of section .eh_frame:
+# DATALE: .eh_frame:
+# DATALE: 100001a8: {{.*}} aa fe
+
+# DATABE: Disassembly of section .eh_frame:
+# DATABE: .eh_frame:
+# DATABE: 100001b0: fe aa {{.*}}
+
+# CHECK: __foo
+# CHECK-NEXT: 10010054: {{.*}} li 3, 0
diff --git a/test/ELF/ppc64-shared-rel-toc.s b/test/ELF/ppc64-shared-rel-toc.s
deleted file mode 100644
index 445011bf8e26..000000000000
--- a/test/ELF/ppc64-shared-rel-toc.s
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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: 0x20000 R_PPC64_RELATIVE - 0x10000
-// CHECK: 0x20008 R_PPC64_RELATIVE - 0x8000
-
-// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x20000
-
diff --git a/test/ELF/ppc64-tls-gd-le.s b/test/ELF/ppc64-tls-gd-le.s
new file mode 100644
index 000000000000..c55ae5f670c1
--- /dev/null
+++ b/test/ELF/ppc64-tls-gd-le.s
@@ -0,0 +1,83 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ mflr 0
+ std 31, -8(1)
+ std 0, 16(1)
+ stdu 1, -64(1)
+ mr 31, 1
+ std 30, 48(31) # 8-byte Folded Spill
+ li 3, 0
+ stw 3, 44(31)
+ addis 3, 2, a@got@tlsgd@ha
+ addi 3, 3, a@got@tlsgd@l
+ bl __tls_get_addr(a@tlsgd)
+ nop
+ lwz 30, 0(3)
+ extsw 3, 30
+ ld 30, 48(31) # 8-byte Folded Reload
+ addi 1, 1, 64
+ ld 0, 16(1)
+ ld 31, -8(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+
+.globl __tls_get_addr
+.type __tls_get_addr,@function
+__tls_get_addr:
+
+ # -- End function
+ .type a,@object # @a
+ .section .tdata,"awT",@progbits
+ .globl a
+ .p2align 2
+a:
+ .long 55 # 0x37
+ .size a, 4
+
+// Verify that the input has general-dynamic tls relocation types
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} a + 0
+// InputRelocs: R_PPC64_TLSGD {{0+}} a + 0
+
+// Verify that the general-dynamic sequence is relaxed to local exec.
+// #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0
+// #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672
+// Dis: _start:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: nop
+// Dis: addi 3, 3, -28672
+
+// Verify that no general-dynamic relocations exist for the dynamic linker.
+// OutputRelocs-NOT: R_PPC64_DTPMOD64
+// OutputRelocs-NOT: R_PPC64_DTPREL64
diff --git a/test/ELF/ppc64-tls-ld-le.s b/test/ELF/ppc64-tls-ld-le.s
new file mode 100644
index 000000000000..d42d7b983c84
--- /dev/null
+++ b/test/ELF/ppc64-tls-ld-le.s
@@ -0,0 +1,84 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ mflr 0
+ std 31, -8(1)
+ std 0, 16(1)
+ stdu 1, -64(1)
+ mr 31, 1
+ std 30, 48(31) # 8-byte Folded Spill
+ li 3, 0
+ stw 3, 44(31)
+ addis 3, 2, a@got@tlsld@ha
+ addi 3, 3, a@got@tlsld@l
+ bl __tls_get_addr(a@tlsld)
+ nop
+ addis 3, 3, a@dtprel@ha
+ addi 3, 3, a@dtprel@l
+ lwz 30, 0(3)
+ extsw 3, 30
+ ld 30, 48(31) # 8-byte Folded Reload
+ addi 1, 1, 64
+ ld 0, 16(1)
+ ld 31, -8(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+.globl __tls_get_addr
+.type __tls_get_addr,@function
+__tls_get_addr:
+ .type a,@object # @a
+ .section .tdata,"awT",@progbits
+ .p2align 2
+a:
+ .long 2 # 0x2
+ .size a, 4
+
+// Verify that the input has local-dynamic tls relocation types
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSLD16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16_LO {{0+}} a + 0
+// InputRelocs: R_PPC64_TLSLD {{0+}} a + 0
+
+// Verify that the local-dynamic sequence is relaxed to local exec.
+// Dis: _start:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: nop
+// Dis: addi 3, 3, 4096
+
+// #ha(a@dtprel) --> (0x0 -0x8000 + 0x8000) >> 16 = 0
+// #lo(a@dtprel) --> (0x0 -0x8000) = -0x8000 = -32768
+// Dis: addis 3, 3, 0
+// Dis: addi 3, 3, -32768
+
+// Verify that no local-dynamic relocations exist for the dynamic linker.
+// OutputRelocs-NOT: R_PPC64_DTPMOD64
diff --git a/test/ELF/ppc64-toc-rel.s b/test/ELF/ppc64-toc-rel.s
new file mode 100644
index 000000000000..ac156c78b3a4
--- /dev/null
+++ b/test/ELF/ppc64-toc-rel.s
@@ -0,0 +1,90 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s
+
+# Make sure we calculate the offset correctly for a toc-relative access to a
+# global variable as described by the PPC64 Elf V2 abi.
+.abiversion 2
+
+# int global_a = 55
+ .globl global_a
+ .section ".data"
+ .align 2
+ .type global_a, @object
+ .size global_a, 4
+ .p2align 2
+global_a:
+ .long 41
+
+
+ .section ".text"
+ .align 2
+ .global _start
+ .type _start, @function
+_start:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+
+ addis 3, 2, global_a@toc@ha
+ addi 3, 3, global_a@toc@l
+ li 0,1
+ lwa 3, 0(3)
+ sc
+.size _start,.-_start
+
+# Verify the relocations that get emitted for the global variable are the
+# expected ones.
+# RELOCS: Relocations [
+# RELOCS-NEXT: .rela.text {
+# RELOCS: 0x8 R_PPC64_TOC16_HA global_a 0x0
+# RELOCS: 0xC R_PPC64_TOC16_LO global_a 0x0
+
+# RELOCS-BE: Relocations [
+# RELOCS-BE-NEXT: .rela.text {
+# RELOCS-BE: 0xA R_PPC64_TOC16_HA global_a 0x0
+# RELOCS-NE: 0xE R_PPC64_TOC16_LO global_a 0x0
+
+# Want to check _start for the values used to build the offset from the TOC base
+# to global_a. The .TOC. symbol is expected at address 0x10030000, and the
+# TOC base is address-of(.TOC.) + 0x8000. The expected offset is:
+# 0x10020000(global_a) - 0x10038000(Toc base) = -0x18000(Offset)
+# which gets materialized into r3 as ((-1 << 16) - 32768).
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: _start:
+# CHECK: 10010008: {{.*}} addis 3, 2, -1
+# CHECK-NEXT: 1001000c: {{.*}} addi 3, 3, -32768
+
+# CHECK: Disassembly of section .data:
+# CHECK-NEXT: global_a:
+# CHECK-NEXT: 10020000: {{.*}}
+
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: .got:
+# CHECK-NEXT: 10030000: 00 80 03 10
+
+
+# CHECK-BE: Disassembly of section .text:
+# CHECK-BE-NEXT: _start:
+# CHECK-BE: 10010008: {{.*}} addis 3, 2, -1
+# CHECK-BE-NEXT: 1001000c: {{.*}} addi 3, 3, -32768
+
+# CHECK-BE: Disassembly of section .data:
+# CHECK-BE-NEXT: global_a:
+# CHECK-BE-NEXT: 10020000: {{.*}}
+
+# CHECK-BE: Disassembly of section .got:
+# CHECK-BE-NEXT: .got:
+# CHECK-BE-NEXT: 10030000: 00 00 00 00
+# CHECK-BE-NEXT: 10030004: 10 03 80 00
diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s
index 0c3d30b2d31a..9efe0e81f5e5 100644
--- a/test/ELF/ppc64-toc-restore.s
+++ b/test/ELF/ppc64-toc-restore.s
@@ -1,62 +1,72 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
// 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: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o
// RUN: ld.lld -shared %t2.o -o %t2.so
-// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: ld.lld %t.o %t2.so %t3.o -o %t
// RUN: llvm-objdump -d %t | FileCheck %s
-// REQUIRES: ppc
-// CHECK: Disassembly of section .text:
+ .text
+ .abiversion 2
+.global bar_local
+bar_local:
+ li 3, 2
+ blr
+# Calling external function foo in a shared object needs a nop.
+# Calling local function bar_local doe snot need a nop.
.global _start
_start:
- bl bar
+ bl foo
nop
+ bl bar_local
-// 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: Disassembly of section .text:
+// CHECK: _start:
+// CHECK: 1001001c: {{.*}} bl .+67108836
+// CHECK-NOT: 10010020: {{.*}} nop
+// CHECK: 10010020: {{.*}} ld 2, 24(1)
+// CHECK: 10010024: {{.*}} bl .+67108848
+// CHECK-NOT: 10010028: {{.*}} nop
+// CHECK-NOT: 10010028: {{.*}} ld 2, 24(1)
-// CHECK: noretend:
-// CHECK: 10010010: 48 00 00 11 bl .+16
+# Calling a function in another object file which will have same
+# TOC base does not need a nop. If nop present, do not rewrite to
+# a toc restore
+.global diff_object
+_diff_object:
+ bl foo_not_shared
+ bl foo_not_shared
+ nop
-.global noretb
-noretb:
- b bar
+// CHECK: _diff_object:
+// CHECK-NEXT: 10010028: {{.*}} bl .+24
+// CHECK-NEXT: 1001002c: {{.*}} bl .+20
+// CHECK-NEXT: 10010030: {{.*}} nop
-// CHECK: noretb:
-// CHECK: 10010014: 48 00 00 0c b .+12
+# Branching to a local function does not need a nop
+.global noretbranch
+noretbranch:
+ b bar_local
+// CHECK: noretbranch:
+// CHECK: 10010034: {{.*}} b .+67108832
+// CHECK-NOT: 10010038: {{.*}} nop
+// CHECK-NOT: 1001003c: {{.*}} ld 2, 24(1)
// This should come last to check the end-of-buffer condition.
.global last
last:
- bl bar
+ bl foo
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 02 addis 11, 2, 4098
-// 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
+// CHECK: 10010038: {{.*}} bl .+67108808
+// CHECK-NEXT: 1001003c: {{.*}} ld 2, 24(1)
diff --git a/test/ELF/ppc64-weak-undef-call-shared.s b/test/ELF/ppc64-weak-undef-call-shared.s
index 2c27a27c5a10..db4824762a0f 100644
--- a/test/ELF/ppc64-weak-undef-call-shared.s
+++ b/test/ELF/ppc64-weak-undef-call-shared.s
@@ -1,7 +1,12 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-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
+
# 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
@@ -10,7 +15,7 @@
.text
.Lfoo:
bl weakfunc
+ nop
// 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
index 55443cb55b99..30c168656e20 100644
--- a/test/ELF/ppc64-weak-undef-call.s
+++ b/test/ELF/ppc64-weak-undef-call.s
@@ -1,17 +1,18 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+
# 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"
+.text
.global _start
_start:
-.quad .Lfoo,.TOC.@tocbase,0
-
-.text
-.Lfoo:
bl weakfunc
nop
blr
@@ -22,6 +23,6 @@ _start:
# 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
+# CHECK: 10010000: {{.*}} bl .+0
+# CHECK: 10010004: {{.*}} nop
+# CHECK: 10010008: {{.*}} blr
diff --git a/test/ELF/ppc64_entry_point.s b/test/ELF/ppc64_entry_point.s
new file mode 100644
index 000000000000..a6f426c7eb10
--- /dev/null
+++ b/test/ELF/ppc64_entry_point.s
@@ -0,0 +1,50 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s
+
+.text
+.abiversion 2
+.globl _start
+.p2align 4
+.type _start,@function
+
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ lis 4, .Lfunc_gep0@ha
+ addi 4, 4, .Lfunc_gep0@l
+ # now r4 should contain the address of _start
+
+ lis 5, .TOC.-.Lfunc_gep0@ha
+ addi 5, 5, .TOC.-.Lfunc_gep0@l
+ # now r5 should contain the offset s.t. r4 + r5 = TOC base
+
+ # exit 55
+ li 0, 1
+ li 3, 55
+ sc
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+
+// CHECK: 10010000: {{.*}} lis 4, 4097
+// CHECK-NEXT: 10010004: {{.*}} addi 4, 4, 0
+// CHECK-NEXT: 10010008: {{.*}} lis 5, 2
+// CHECK-NEXT: 1001000c: {{.*}} addi 5, 5, -32768
+// CHECK: Disassembly of section .got:
+// CHECK-NEXT: .got:
+// CHECK-NEXT: 10020000: 00 80 02 10
+
+// CHECK-BE: 10010000: {{.*}} lis 4, 4097
+// CHECK-BE-NEXT: 10010004: {{.*}} addi 4, 4, 0
+// CHECK-BE-NEXT: 10010008: {{.*}} lis 5, 2
+// CHECK-BE-NEXT: 1001000c: {{.*}} addi 5, 5, -32768
+// CHECK-BE: Disassembly of section .got:
+// CHECK-BE-NEXT: .got:
+// CHECK-BE-NEXT: 10020000: 00 00 00 00 {{.*}}
+// CHECK-BE-NEXT: 10020004: 10 02 80 00 {{.*}}
diff --git a/test/ELF/pr34660.s b/test/ELF/pr34660.s
index 7c78bbc11c7b..53998ad0f728 100644
--- a/test/ELF/pr34660.s
+++ b/test/ELF/pr34660.s
@@ -3,7 +3,7 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
# RUN: ld.lld --hash-style=sysv -shared %t.o -o %t
# RUN: llvm-objdump %t -d | FileCheck %s --check-prefix=DISASM
-# RUN: llvm-readobj -elf-output-style=GNU %t -t | FileCheck %s --check-prefix=SYM
+# RUN: llvm-readelf %t -t | FileCheck %s --check-prefix=SYM
# It would be much easier to understand/read this test if llvm-objdump would print
# the immediates in hex.
diff --git a/test/ELF/pr34872.s b/test/ELF/pr34872.s
index c656be2a9279..c6ca81972096 100644
--- a/test/ELF/pr34872.s
+++ b/test/ELF/pr34872.s
@@ -1,8 +1,9 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -filetype=obj -triple=x86_64-pc-linux -o %t.o
# RUN: llvm-mc %p/Inputs/undefined-error.s -filetype=obj \
# RUN: -triple=x86_64-pc-linux -o %t2.o
# RUN: ld.lld -shared %t2.o -o %t2.so
-# RUN: not ld.lld %t2.so %t.o 2>&1 | FileCheck %s
+# RUN: not ld.lld %t2.so %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: undefined symbol: fmod
# Check we're not emitting other diagnostics for this symbol.
diff --git a/test/ELF/pr36475.s b/test/ELF/pr36475.s
new file mode 100644
index 000000000000..0228974b1c45
--- /dev/null
+++ b/test/ELF/pr36475.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS {" > %t.script
+# RUN: echo " ph_text PT_LOAD FLAGS (0x1 | 0x4);" >> %t.script
+# RUN: echo " ph_data PT_LOAD FLAGS (0x2 | 0x4);" >> %t.script
+# RUN: echo "}" >> %t.script
+# RUN: echo "SECTIONS {" >> %t.script
+# RUN: echo " .text : { *(.text*) } : ph_text" >> %t.script
+# RUN: echo " . = ALIGN(0x4000);" >> %t.script
+# RUN: echo " .got.plt : { BYTE(42); *(.got); } : ph_data" >> %t.script
+# RUN: echo "}" >> %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.elf
+# RUN: llvm-readobj -l -elf-output-style=GNU %t.elf | FileCheck %s
+
+# CHECK: Section to Segment mapping:
+# CHECK-NEXT: Segment Sections...
+# CHECK-NEXT: 00 .text executable
+# CHECK-NEXT: 01 .got.plt
+
+.text
+.globl _start
+.type _start,@function
+_start:
+ callq custom_func
+ ret
+
+.section executable,"ax",@progbits
+.type custom_func,@function
+custom_func:
+ ret
diff --git a/test/ELF/pr37735.s b/test/ELF/pr37735.s
new file mode 100644
index 000000000000..7e25d1b6f4df
--- /dev/null
+++ b/test/ELF/pr37735.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t.o
+# RUN: ld.lld -r %t.o %t.o -o %t1.o
+# RUN: llvm-objdump -s -section=.bar %t1.o | FileCheck %s
+
+.section .foo
+ .byte 0
+
+# CHECK: Contents of section .bar:
+# CHECK-NEXT: 0000 00000000 01000000
+.section .bar
+ .dc.a .foo
diff --git a/test/ELF/pre_init_fini_array.s b/test/ELF/pre_init_fini_array.s
index 1192fd0dc851..cf716ab681eb 100644
--- a/test/ELF/pre_init_fini_array.s
+++ b/test/ELF/pre_init_fini_array.s
@@ -1,10 +1,10 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/pre_init_fini_array_missing.s b/test/ELF/pre_init_fini_array_missing.s
index 7dabfa7a6966..d5b998443a24 100644
--- a/test/ELF/pre_init_fini_array_missing.s
+++ b/test/ELF/pre_init_fini_array_missing.s
@@ -1,9 +1,9 @@
+// REQUIRES: x86
// 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
// RUN: ld.lld -pie %t -o %t3
// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=PIE %s
-// REQUIRES: x86
.globl _start
_start:
@@ -14,30 +14,27 @@ _start:
call __fini_array_start
call __fini_array_end
-// With no .init_array section the symbols resolve to 0
-// 0 - (0x201000 + 5) = -2101253
-// 0 - (0x201005 + 5) = -2101258
-// 0 - (0x20100a + 5) = -2101263
-// 0 - (0x20100f + 5) = -2101268
-// 0 - (0x201014 + 5) = -2101273
-// 0 - (0x201019 + 5) = -2101278
+// With no .init_array section the symbols resolve to .text.
+// 0x201000 - (0x201000 + 5) = -5
+// 0x201000 - (0x201005 + 5) = -10
+// ...
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
-// CHECK-NEXT: 201000: e8 fb ef df ff callq -2101253
-// CHECK-NEXT: 201005: e8 f6 ef df ff callq -2101258
-// CHECK-NEXT: 20100a: e8 f1 ef df ff callq -2101263
-// CHECK-NEXT: 20100f: e8 ec ef df ff callq -2101268
-// CHECK-NEXT: 201014: e8 e7 ef df ff callq -2101273
-// CHECK-NEXT: 201019: e8 e2 ef df ff callq -2101278
+// CHECK-NEXT: 201000: e8 fb ff ff ff callq -5
+// CHECK-NEXT: 201005: e8 f6 ff ff ff callq -10
+// CHECK-NEXT: 20100a: e8 f1 ff ff ff callq -15
+// CHECK-NEXT: 20100f: e8 ec ff ff ff callq -20
+// CHECK-NEXT: 201014: e8 e7 ff ff ff callq -25
+// CHECK-NEXT: 201019: e8 e2 ff ff ff callq -30
-// In position-independent binaries, they resolve to the image base.
+// In position-independent binaries, they resolve to .text too.
// PIE: Disassembly of section .text:
// PIE-NEXT: _start:
-// PIE-NEXT: 1000: e8 fb ef ff ff callq -4101
-// PIE-NEXT: 1005: e8 f6 ef ff ff callq -4106
-// PIE-NEXT: 100a: e8 f1 ef ff ff callq -4111
-// PIE-NEXT: 100f: e8 ec ef ff ff callq -4116
-// PIE-NEXT: 1014: e8 e7 ef ff ff callq -4121
-// PIE-NEXT: 1019: e8 e2 ef ff ff callq -4126
+// PIE-NEXT: 1000: e8 fb ff ff ff callq -5
+// PIE-NEXT: 1005: e8 f6 ff ff ff callq -10
+// PIE-NEXT: 100a: e8 f1 ff ff ff callq -15
+// PIE-NEXT: 100f: e8 ec ff ff ff callq -20
+// PIE-NEXT: 1014: e8 e7 ff ff ff callq -25
+// PIE-NEXT: 1019: e8 e2 ff ff ff callq -30
diff --git a/test/ELF/print-icf.s b/test/ELF/print-icf.s
new file mode 100644
index 000000000000..cb6116d51cdc
--- /dev/null
+++ b/test/ELF/print-icf.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+
+# 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/print-icf.s -o %t1
+# RUN: ld.lld %t %t1 -o %t2 --icf=all --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t %t1 -o %t2 --icf=all --no-print-icf-sections --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t %t1 -o %t2 --icf=all --print-icf-sections --no-print-icf-sections | FileCheck -allow-empty -check-prefix=PRINT %s
+
+# CHECK: selected section {{.*}}:(.text.f2)
+# CHECK: removing identical section {{.*}}:(.text.f4)
+# CHECK: removing identical section {{.*}}:(.text.f7)
+# CHECK: selected section {{.*}}:(.text.f1)
+# CHECK: removing identical section {{.*}}:(.text.f3)
+# CHECK: removing identical section {{.*}}:(.text.f5)
+# CHECK: removing identical section {{.*}}:(.text.f6)
+
+# PRINT-NOT: selected
+# PRINT-NOT: removing
+
+.globl _start, f1, f2
+_start:
+ ret
+
+.section .text.f1, "ax"
+f1:
+ mov $60, %rax
+ mov $42, %rdi
+ syscall
+
+ .section .text.f2, "ax"
+f2:
+ mov $0, %rax
+
+.section .text.f3, "ax"
+f3:
+ mov $60, %rax
+ mov $42, %rdi
+ syscall
+
+.section .text.f4, "ax"
+f4:
+ mov $0, %rax
+
+.section .text.f5, "ax"
+f5:
+ mov $60, %rax
+ mov $42, %rdi
+ syscall
diff --git a/test/ELF/program-header-layout.s b/test/ELF/program-header-layout.s
index 57759c946dac..949a96e4f438 100644
--- a/test/ELF/program-header-layout.s
+++ b/test/ELF/program-header-layout.s
@@ -1,7 +1,7 @@
+# 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 -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.
diff --git a/test/ELF/protected-data-access.s b/test/ELF/protected-data-access.s
new file mode 100644
index 000000000000..530710751d6b
--- /dev/null
+++ b/test/ELF/protected-data-access.s
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %p/Inputs/protected-data-access.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t.o
+
+# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: cannot preempt symbol: foo
+
+# RUN: ld.lld --ignore-data-address-equality %t.o %t2.so -o %t
+# RUN: llvm-readobj --dyn-symbols --relocations %t | FileCheck %s
+
+# Check that we have a copy relocation.
+
+# CHECK: R_X86_64_COPY foo 0x0
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value:
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Object
+# CHECK-NEXT: Other:
+# CHECK-NEXT: Section: .bss.rel.ro
+
+.global _start
+_start:
+ .quad foo
+
diff --git a/test/ELF/protected-function-access.s b/test/ELF/protected-function-access.s
new file mode 100644
index 000000000000..2fa682b412fd
--- /dev/null
+++ b/test/ELF/protected-function-access.s
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %p/Inputs/protected-function-access.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t.o
+
+# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: cannot preempt symbol: foo
+
+# RUN: ld.lld --ignore-function-address-equality %t.o %t2.so -o %t
+# RUN: llvm-readobj --dyn-symbols --relocations %t | FileCheck %s
+
+# Check that we have a relocation and an undefined symbol with a non zero address
+
+# CHECK: R_X86_64_JUMP_SLOT foo 0x0
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x201020
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Function
+# CHECK-NEXT: Other:
+# CHECK-NEXT: Section: Undefined
+
+.global _start
+_start:
+ .quad foo
+
diff --git a/test/ELF/push-state.s b/test/ELF/push-state.s
new file mode 100644
index 000000000000..5a01cd2eeedd
--- /dev/null
+++ b/test/ELF/push-state.s
@@ -0,0 +1,36 @@
+// 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/whole-archive.s -o %t2.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %t2.o
+
+// RUN: ld.lld -o %t.exe -push-state -whole-archive %t.a %t1.o -M | \
+// RUN: FileCheck -check-prefix=WHOLE %s
+// WHOLE: _bar
+
+// RUN: ld.lld -o %t.exe -push-state -whole-archive -pop-state %t.a %t1.o -M | \
+// RUN: FileCheck -check-prefix=NO-WHOLE %s
+// NO-WHOLE-NOT: _bar
+
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t3.o
+// RUN: ld.lld -shared %t3.o -soname libfoo -o %t.so
+
+// RUN: ld.lld -o %t.exe -push-state -as-needed %t.so %t1.o
+// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=AS-NEEDED %s
+// AS-NEEDED-NOT: NEEDED Shared library: [libfoo]
+
+// RUN: ld.lld -o %t.exe -push-state -as-needed -pop-state %t.so %t1.o
+// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=NO-AS-NEEDED %s
+// NO-AS-NEEDED: NEEDED Shared library: [libfoo]
+
+
+// RUN: mkdir -p %t.dir
+// RUN: cp %t.so %t.dir/libfoo.so
+// RUN: ld.lld -o %t.exe -L%t.dir -push-state -static -pop-state %t1.o -lfoo
+// RUN: not ld.lld -o %t.exe -L%t.dir -push-state -static %t1.o -lfoo
+
+.globl _start
+_start:
diff --git a/test/ELF/rel-addend-with-rela-input.s b/test/ELF/rel-addend-with-rela-input.s
new file mode 100644
index 000000000000..11eac97ed519
--- /dev/null
+++ b/test/ELF/rel-addend-with-rela-input.s
@@ -0,0 +1,43 @@
+# REQUIRES: mips
+# Check that we correctly write addends if the output use Elf_Rel but the input
+# uses Elf_Rela
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-rela.o
+# RUN: llvm-readobj -h -s -section-data -relocations %t-rela.o | FileCheck -check-prefix INPUT-RELA %s
+# INPUT-RELA: ElfHeader {
+# INPUT-RELA: Class: 64-bit
+# INPUT-RELA: DataEncoding: BigEndian
+# INPUT-RELA: Section {
+# INPUT-RELA: Name: .data
+# INPUT-RELA: SectionData (
+# INPUT-RELA-NEXT: 0000: 00000000 00000000 ABCDEF00 12345678 |.............4Vx|
+# ^--- No addend here since it uses RELA
+# INPUT-RELA: Relocations [
+# INPUT-RELA-NEXT: Section ({{.+}}) .rela.data {
+# INPUT-RELA-NEXT: 0x0 R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE foo 0x5544
+# INPUT-RELA-NEXT: }
+# INPUT-RELA-NEXT: ]
+
+# Previously the addend to the dynamic relocation in the .data section was not copied if
+# the input file used RELA and the output uses REL. Check that it works now:
+# RUN: ld.lld -shared -o %t.so %t-rela.o -verbose
+# RUN: llvm-readobj -h -s -section-data -relocations %t.so | FileCheck -check-prefix RELA-TO-REL %s
+# RELA-TO-REL: ElfHeader {
+# RELA-TO-REL: Class: 64-bit
+# RELA-TO-REL: DataEncoding: BigEndian
+# RELA-TO-REL: Section {
+# RELA-TO-REL: Name: .data
+# RELA-TO-REL: SectionData (
+# RELA-TO-REL-NEXT: 0000: 00000000 00005544 ABCDEF00 12345678 |......UD.....4Vx|
+# ^--- Addend for relocation in .rel.dyn
+# RELA-TO-REL: Relocations [
+# RELA-TO-REL-NEXT: Section ({{.+}}) .rel.dyn {
+# RELA-TO-REL-NEXT: 0x10000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE foo 0x0
+# RELA-TO-REL-NEXT: }
+# RELA-TO-REL-NEXT: ]
+
+.extern foo
+
+.data
+.quad foo + 0x5544
+.quad 0xabcdef0012345678
diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s
index 65d0e8e83984..83190a270048 100644
--- a/test/ELF/relative-dynamic-reloc-ppc64.s
+++ b/test/ELF/relative-dynamic-reloc-ppc64.s
@@ -1,7 +1,11 @@
+// REQUIRES: ppc
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-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
+
// 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.
diff --git a/test/ELF/relocatable-build-id.s b/test/ELF/relocatable-build-id.s
new file mode 100644
index 000000000000..5ac205c2b287
--- /dev/null
+++ b/test/ELF/relocatable-build-id.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld --build-id=0xcafebabe -o %t2.o %t1.o -r
+# RUN: ld.lld --build-id=0xdeadbeef -o %t.exe %t2.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK-NOT: cafebabe
+# CHECK: deadbeef
+
+.global _start
+_start:
+ ret
diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s
index 4c3e7ce7f6d4..bb7a78490fdd 100644
--- a/test/ELF/relocatable-comdat-multiple.s
+++ b/test/ELF/relocatable-comdat-multiple.s
@@ -8,6 +8,8 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Link: 8
+# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: aaa
# CHECK-NEXT: Section(s) in group [
@@ -18,6 +20,8 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Link: 8
+# CHECK-NEXT: Info: 6
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bbb
# CHECK-NEXT: Section(s) in group [
diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s
index 24504d23884f..11aa30c7e6bd 100644
--- a/test/ELF/relocatable-comdat.s
+++ b/test/ELF/relocatable-comdat.s
@@ -30,6 +30,8 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Link: 5
+# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: abc
# CHECK-NEXT: Section(s) in group [
diff --git a/test/ELF/relocatable-comdat2.s b/test/ELF/relocatable-comdat2.s
index 2643e645fda9..27844feae16e 100644
--- a/test/ELF/relocatable-comdat2.s
+++ b/test/ELF/relocatable-comdat2.s
@@ -13,6 +13,8 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Link: 7
+# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bar
# CHECK-NEXT: Section(s) in group [
@@ -22,6 +24,8 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Link: 7
+# CHECK-NEXT: Info: 2
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: zed
# CHECK-NEXT: Section(s) in group [
diff --git a/test/ELF/relocatable-eh-frame.s b/test/ELF/relocatable-eh-frame.s
index c2e5ec63f865..dee906acb87f 100644
--- a/test/ELF/relocatable-eh-frame.s
+++ b/test/ELF/relocatable-eh-frame.s
@@ -5,7 +5,7 @@
# RUN: ld.lld %t -o %t.so -shared
# RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s
-# DSO: .eh_frame 00000030
+# DSO: .eh_frame 00000034
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.eh_frame {
diff --git a/test/ELF/relocatable-many-sections.s b/test/ELF/relocatable-many-sections.s
new file mode 100644
index 000000000000..df22154d0c9f
--- /dev/null
+++ b/test/ELF/relocatable-many-sections.s
@@ -0,0 +1,92 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o
+# RUN: ld.lld -r %t.o -o %t
+# RUN: llvm-readobj -file-headers %t | FileCheck %s
+
+## Check we are able to emit a valid ELF header when
+## sections amount is greater than SHN_LORESERVE.
+# CHECK: ElfHeader {
+# CHECK: SectionHeaderCount: 0 (65541)
+# CHECK-NEXT: StringTableSectionIndex: 65535 (65539)
+
+## Check that 65539 is really the index of .shstrtab section.
+# RUN: llvm-objdump -section-headers -section=.shstrtab %t \
+# RUN: | FileCheck %s --check-prefix=SHSTRTAB
+# SHSTRTAB: Sections:
+# SHSTRTAB-NEXT: Idx Name
+# SHSTRTAB-NEXT: 65539 .shstrtab
+
+.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
+
+gen_sections16384 a
+gen_sections16384 b
+gen_sections16384 c
+gen_sections16384 d
+
+.global _start
+_start:
diff --git a/test/ELF/relocatable-symbols.s b/test/ELF/relocatable-symbols.s
index 79608e7b74f0..46d8ab7395fc 100644
--- a/test/ELF/relocatable-symbols.s
+++ b/test/ELF/relocatable-symbols.s
@@ -174,21 +174,33 @@
.global _start
.text
_start:
- call __start_foo
- call __stop_foo
+ .byte 0xe8
+ .long __start_foo - . -4
+ .byte 0xe8
+ .long __stop_foo - . -4
- call __start_bar
- call __stop_bar
+ .byte 0xe8
+ .long __start_bar - . -4
+ .byte 0xe8
+ .long __stop_bar - . -4
- call __start_doo
- call __stop_doo
+ .byte 0xe8
+ .long __start_doo - . -4
+ .byte 0xe8
+ .long __stop_doo - . -4
- call __preinit_array_start
- call __preinit_array_end
- call __init_array_start
- call __init_array_end
- call __fini_array_start
- call __fini_array_end
+ .byte 0xe8
+ .long __preinit_array_start - . -4
+ .byte 0xe8
+ .long __preinit_array_end - . -4
+ .byte 0xe8
+ .long __init_array_start - . -4
+ .byte 0xe8
+ .long __init_array_end - . -4
+ .byte 0xe8
+ .long __fini_array_start - . -4
+ .byte 0xe8
+ .long __fini_array_end - . -4
.section foo,"ax"
nop
diff --git a/test/ELF/relocatable-versioned.s b/test/ELF/relocatable-versioned.s
new file mode 100644
index 000000000000..2b6c49eb5baa
--- /dev/null
+++ b/test/ELF/relocatable-versioned.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -o %t2.o -r %t1.o
+# RUN: llvm-nm %t2.o | FileCheck %s
+# CHECK: foo@VERSION
+
+.global "foo@VERSION"
+"foo@VERSION":
+ ret
diff --git a/test/ELF/relocation-absolute.s b/test/ELF/relocation-absolute.s
index 20d54eca9205..b882987bb694 100644
--- a/test/ELF/relocation-absolute.s
+++ b/test/ELF/relocation-absolute.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/relocation-common.s b/test/ELF/relocation-common.s
index 28276bfe0750..71b1ac0e2e24 100644
--- a/test/ELF/relocation-common.s
+++ b/test/ELF/relocation-common.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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:
diff --git a/test/ELF/relocation-dtrace.test b/test/ELF/relocation-dtrace.test
index ef2cc4956ca6..9007a265bfaa 100644
--- a/test/ELF/relocation-dtrace.test
+++ b/test/ELF/relocation-dtrace.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t.o
-# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: ld.lld -shared %t.o -o /dev/null
# Test that we can handle R_X86_64_NONE as produced by dtrace.
diff --git a/test/ELF/relocation-i686.s b/test/ELF/relocation-i686.s
index 3986357d66f2..fdec7caa33be 100644
--- a/test/ELF/relocation-i686.s
+++ b/test/ELF/relocation-i686.s
@@ -1,10 +1,10 @@
+// REQUIRES: x86
// 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 --hash-style=sysv %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:
diff --git a/test/ELF/relocation-local.s b/test/ELF/relocation-local.s
index 8173dac0522f..383c5c82f64a 100644
--- a/test/ELF/relocation-local.s
+++ b/test/ELF/relocation-local.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/relocation-nocopy.s b/test/ELF/relocation-nocopy.s
index 533277dc8ec3..70e99334796d 100644
--- a/test/ELF/relocation-nocopy.s
+++ b/test/ELF/relocation-nocopy.s
@@ -2,7 +2,7 @@
// 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: not ld.lld -z nocopyreloc %t.o %t.so -o %t3 2>&1 | FileCheck %s
+// RUN: not ld.lld -z nocopyreloc %t.o %t.so -o /dev/null 2>&1 | FileCheck %s
// CHECK: unresolvable relocation R_X86_64_32S against symbol 'x'
// CHECK: unresolvable relocation R_X86_64_32S against symbol 'y'
diff --git a/test/ELF/relocation-non-alloc.s b/test/ELF/relocation-non-alloc.s
index 1ad15a4e5787..95166fbe0d4a 100644
--- a/test/ELF/relocation-non-alloc.s
+++ b/test/ELF/relocation-non-alloc.s
@@ -1,25 +1,47 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared --apply-dynamic-relocs
+// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s
+
// RUN: ld.lld %t -o %t2 -shared
-// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck %s
+// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s
+// RUN: ld.lld %t -o %t2 -shared --no-apply-dynamic-relocs
+// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %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: 0x1000
-// CHECK-NEXT: Offset: 0x1000
-// 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: )
+// APPLYDYNREL: Name: .data
+// APPLYDYNREL-NEXT: Type: SHT_PROGBITS
+// APPLYDYNREL-NEXT: Flags [
+// APPLYDYNREL-NEXT: SHF_ALLOC
+// APPLYDYNREL-NEXT: SHF_WRITE
+// APPLYDYNREL-NEXT: ]
+// APPLYDYNREL-NEXT: Address: 0x1000
+// APPLYDYNREL-NEXT: Offset: 0x1000
+// APPLYDYNREL-NEXT: Size: 16
+// APPLYDYNREL-NEXT: Link: 0
+// APPLYDYNREL-NEXT: Info: 0
+// APPLYDYNREL-NEXT: AddressAlignment: 1
+// APPLYDYNREL-NEXT: EntrySize: 0
+// APPLYDYNREL-NEXT: SectionData (
+// APPLYDYNREL-NEXT: 0000: 00100000 00000000 00000000 00000000
+// APPLYDYNREL-NEXT: )
+
+// NOAPPLYDYNREL: Name: .data
+// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS
+// NOAPPLYDYNREL-NEXT: Flags [
+// NOAPPLYDYNREL-NEXT: SHF_ALLOC
+// NOAPPLYDYNREL-NEXT: SHF_WRITE
+// NOAPPLYDYNREL-NEXT: ]
+// NOAPPLYDYNREL-NEXT: Address: 0x1000
+// NOAPPLYDYNREL-NEXT: Offset: 0x1000
+// NOAPPLYDYNREL-NEXT: Size: 16
+// NOAPPLYDYNREL-NEXT: Link: 0
+// NOAPPLYDYNREL-NEXT: Info: 0
+// NOAPPLYDYNREL-NEXT: AddressAlignment: 1
+// NOAPPLYDYNREL-NEXT: EntrySize: 0
+// NOAPPLYDYNREL-NEXT: SectionData (
+// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 00000000 00000000
+// NOAPPLYDYNREL-NEXT: )
// CHECK: Name: foo
// CHECK-NEXT: Type: SHT_PROGBITS
diff --git a/test/ELF/relocation-none-aarch64.test b/test/ELF/relocation-none-aarch64.test
index dd67c8c0fb2e..e77989a54a83 100644
--- a/test/ELF/relocation-none-aarch64.test
+++ b/test/ELF/relocation-none-aarch64.test
@@ -1,7 +1,7 @@
# REQUIRES: aarch64
# RUN: yaml2obj %s -o %t.o
-# RUN: ld.lld %t.o -o %t.out
+# RUN: ld.lld %t.o -o /dev/null
!ELF
FileHeader:
diff --git a/test/ELF/relocation-none-i686.test b/test/ELF/relocation-none-i686.test
index d8eed8f7a129..82dc4e608c03 100644
--- a/test/ELF/relocation-none-i686.test
+++ b/test/ELF/relocation-none-i686.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t.o
-# RUN: ld.lld %t.o -o %t.out
+# RUN: ld.lld %t.o -o /dev/null
# Test that we can handle R_386_NONE.
diff --git a/test/ELF/relocation-past-merge-end.s b/test/ELF/relocation-past-merge-end.s
index d08bde7b9f6c..a3e7b59a415a 100644
--- a/test/ELF/relocation-past-merge-end.s
+++ b/test/ELF/relocation-past-merge-end.s
@@ -1,6 +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.so -shared 2>&1 | FileCheck %s
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): entry is past the end of the section
.data
diff --git a/test/ELF/relocation-relative-absolute.s b/test/ELF/relocation-relative-absolute.s
index 2a343fddca76..21f50025e92b 100644
--- a/test/ELF/relocation-relative-absolute.s
+++ b/test/ELF/relocation-relative-absolute.s
@@ -2,7 +2,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %tinput1.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
# RUN: %S/Inputs/relocation-relative-absolute.s -o %tinput2.o
-# RUN: not ld.lld %tinput1.o %tinput2.o -o %t -pie 2>&1 | FileCheck %s
+# RUN: not ld.lld %tinput1.o %tinput2.o -o /dev/null -pie 2>&1 | FileCheck %s
.globl _start
_start:
diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s
index 4fba7a5683b0..81537cec1ef5 100644
--- a/test/ELF/relocation-shared.s
+++ b/test/ELF/relocation-shared.s
@@ -8,7 +8,7 @@
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x20D
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 8
// CHECK-NEXT: Link: 0
@@ -16,8 +16,8 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 380E0000 00000000
-// 0x1000 - 0x1C8 = 0xE38
+// CHECK-NEXT: 0000: F30D0000 00000000
+// 0x1000 - 0x20D = 0xDF3
// CHECK-NEXT: )
// CHECK: Name: .text
diff --git a/test/ELF/relocation-size-err.s b/test/ELF/relocation-size-err.s
new file mode 100644
index 000000000000..8783fe9568da
--- /dev/null
+++ b/test/ELF/relocation-size-err.s
@@ -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 /dev/null -shared 2>&1 | FileCheck %s
+
+// CHECK: error: can't create dynamic relocation R_X86_64_SIZE64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
+
+ .global foo
+foo:
+ .quad 42
+ .size foo, 8
+
+ .quad foo@SIZE
diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s
index cea9e64d58ed..f60f0929e705 100644
--- a/test/ELF/relocation-size-shared.s
+++ b/test/ELF/relocation-size-shared.s
@@ -1,3 +1,4 @@
+// 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/relocation-size-shared.s -o %tso.o
// RUN: ld.lld -shared %tso.o -o %tso
diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s
index 419b8a17fad9..525b1e1d1331 100644
--- a/test/ELF/relocation-size.s
+++ b/test/ELF/relocation-size.s
@@ -1,3 +1,4 @@
+// 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-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
diff --git a/test/ELF/relocation-undefined-weak.s b/test/ELF/relocation-undefined-weak.s
index 6aa84ec483f4..7ea247fd5d6e 100644
--- a/test/ELF/relocation-undefined-weak.s
+++ b/test/ELF/relocation-undefined-weak.s
@@ -1,8 +1,8 @@
+// REQUIRES: x86
// 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.
diff --git a/test/ELF/relocation.s b/test/ELF/relocation.s
index 3359a8badda6..00b75d25f968 100644
--- a/test/ELF/relocation.s
+++ b/test/ELF/relocation.s
@@ -1,10 +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/shared.s -o %t2
-// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t2 -soname fixed-length-string.so -o %t2.so -shared
// RUN: ld.lld --hash-style=sysv %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
@@ -113,17 +113,16 @@ R_X86_64_64:
.quad R_X86_64_64
// CHECK: Contents of section .R_X86_64_64:
-// CHECK-NEXT: 2001c8 c8012000 00000000
+// CHECK-NEXT: 2002c0 c0022000 00000000
.section .R_X86_64_GOTPCREL,"a",@progbits
.global R_X86_64_GOTPCREL
R_X86_64_GOTPCREL:
.long zed@gotpcrel
-// 0x2020F8 - 0x2001D8 = 7952
-// 7952 = 0x101f0000 in little endian
+// 0x2030F0(.got) - 0x2002c8(.R_X86_64_GOTPCREL) = 0x2e28
// CHECK: Contents of section .R_X86_64_GOTPCREL
-// CHECK-NEXT: 2001d0 202f0000
+// CHECK-NEXT: 2002c8 282e0000
.section .R_X86_64_GOT32,"a",@progbits
.global R_X86_64_GOT32
diff --git a/test/ELF/relro-non-contiguous.s b/test/ELF/relro-non-contiguous.s
index ce6680860edf..8fdf64a37456 100644
--- a/test/ELF/relro-non-contiguous.s
+++ b/test/ELF/relro-non-contiguous.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-in-shared.s -o %t2.o
// RUN: ld.lld -shared %t.o %t2.o -o %t.so
@@ -15,7 +16,6 @@
// RUN: not ld.lld %t3.o %t.so -z relro -o %t --script=%t.script 2>&1 | FileCheck %s
// No error when we do not request relro.
// RUN: ld.lld %t3.o %t.so -z norelro -o %t --script=%t.script
-// REQUIRES: x86
// CHECK: error: section: .bss.rel.ro is not contiguous with other relro sections
.section .text, "ax", @progbits
diff --git a/test/ELF/relro-omagic.s b/test/ELF/relro-omagic.s
index 97c3a812406d..ba0ca72e219b 100644
--- a/test/ELF/relro-omagic.s
+++ b/test/ELF/relro-omagic.s
@@ -1,3 +1,4 @@
+# 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/shared.s -o %t2.o
# RUN: ld.lld -shared %t2.o -o %t2.so -soname relro-omagic.s.tmp2.so
@@ -13,8 +14,8 @@
# NORELRO-NEXT: 3 .dynstr 00000021 0000000000200188
# NORELRO-NEXT: 4 .rela.dyn 00000018 00000000002001b0
# NORELRO-NEXT: 5 .rela.plt 00000018 00000000002001c8
-# NORELRO-NEXT: 6 .text 0000000a 00000000002001e0 TEXT DATA
-# NORELRO-NEXT: 7 .plt 00000020 00000000002001f0 TEXT DATA
+# NORELRO-NEXT: 6 .text 0000000a 00000000002001e0 TEXT
+# NORELRO-NEXT: 7 .plt 00000020 00000000002001f0 TEXT
# NORELRO-NEXT: 8 .data 00000008 0000000000200210 DATA
# NORELRO-NEXT: 9 .foo 00000004 0000000000200218 DATA
# NORELRO-NEXT: 10 .dynamic 000000f0 0000000000200220
diff --git a/test/ELF/relro-script.s b/test/ELF/relro-script.s
index f0dca67a3422..c71c8e5decdc 100644
--- a/test/ELF/relro-script.s
+++ b/test/ELF/relro-script.s
@@ -16,7 +16,7 @@
// RUN: .got.plt : { *(.got.plt) } \
// RUN: } " > %t.script
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t3.o
-// RUN: ld.lld %t3.o %t.so -o %t --script=%t.script --print-map | FileCheck %s
+// RUN: ld.lld %t3.o %t.so -o /dev/null --script=%t.script --print-map | FileCheck %s
// CHECK: .data.rel.ro
// CHECK-NEXT: <internal>:(.bss.rel.ro)
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
index b21e514303ab..0f721318c784 100644
--- a/test/ELF/relro.s
+++ b/test/ELF/relro.s
@@ -1,13 +1,17 @@
+// 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/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: ld.lld %t.o %t2.so -z now -z norelro -z relro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s
-// RUN: ld.lld %t.o %t2.so -z relro -o %t
+
+// RUN: ld.lld %t.o %t2.so -z norelro -z relro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s
+
// RUN: ld.lld %t.o %t2.so -z norelro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=NORELRO %s
-// REQUIRES: x86
// CHECK: Program Headers:
// CHECK-NEXT: Type
diff --git a/test/ELF/reproduce-backslash.s b/test/ELF/reproduce-backslash.s
index 53feb5ff3223..7a9964db62aa 100644
--- a/test/ELF/reproduce-backslash.s
+++ b/test/ELF/reproduce-backslash.s
@@ -2,8 +2,8 @@
# Test that we don't erroneously replace \ with / on UNIX, as it's
# legal for a filename to contain backslashes.
-# RUN: llvm-mc %s -o foo\\.o -filetype=obj -triple=x86_64-pc-linux
-# RUN: ld.lld foo\\.o --reproduce repro.tar
-# RUN: tar tf repro.tar | FileCheck %s
+# RUN: llvm-mc %s -o %T/foo\\.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: ld.lld %T/foo\\.o --reproduce %T/repro.tar -o /dev/null
+# RUN: tar tf %T/repro.tar | FileCheck %s
# CHECK: repro/{{.*}}/foo\\.o
diff --git a/test/ELF/reproduce-error.s b/test/ELF/reproduce-error.s
index e2de8a4feeba..3a99815d7708 100644
--- a/test/ELF/reproduce-error.s
+++ b/test/ELF/reproduce-error.s
@@ -1,5 +1,5 @@
-# Extracting the tar archive can get over the path limit on windows.
# REQUIRES: shell
+# Extracting the tar archive can get over the path limit on windows.
# RUN: rm -rf %t.dir
# RUN: mkdir -p %t.dir
diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s
index 69671a088473..bfab2e87e80b 100644
--- a/test/ELF/reproduce.s
+++ b/test/ELF/reproduce.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
+# REQUIRES: shell
# Extracting the tar archive can get over the path limit on windows.
-# REQUIRES: shell
# RUN: rm -rf %t.dir
# RUN: mkdir -p %t.dir/build1
diff --git a/test/ELF/resolution-end.s b/test/ELF/resolution-end.s
index 26858372ce09..c8c5a044e602 100644
--- a/test/ELF/resolution-end.s
+++ b/test/ELF/resolution-end.s
@@ -1,9 +1,9 @@
+# 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/resolution-end.s -o %t2.o
# RUN: ld.lld -shared -o %t2.so %t2.o
# RUN: ld.lld --hash-style=sysv %t1.o %t2.so -o %t
# RUN: llvm-readobj -t -s -section-data %t | FileCheck %s
-# REQUIRES: x86
# Test that we resolve _end to the this executable.
diff --git a/test/ELF/resolution-shared.s b/test/ELF/resolution-shared.s
index e1eac070e5af..2d61d268c6f9 100644
--- a/test/ELF/resolution-shared.s
+++ b/test/ELF/resolution-shared.s
@@ -1,9 +1,9 @@
+// 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/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:
diff --git a/test/ELF/resolution.s b/test/ELF/resolution.s
index 4a42d941eab6..f72f487e68ea 100644
--- a/test/ELF/resolution.s
+++ b/test/ELF/resolution.s
@@ -1,8 +1,8 @@
+// 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/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
diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s
index 441e5c395e7c..49d59cec4a6a 100644
--- a/test/ELF/rodynamic.s
+++ b/test/ELF/rodynamic.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux
diff --git a/test/ELF/section-align-0.test b/test/ELF/section-align-0.test
index 35783f5a894b..8827ecf740b3 100644
--- a/test/ELF/section-align-0.test
+++ b/test/ELF/section-align-0.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t
-# RUN: ld.lld %t -o %tout
+# RUN: ld.lld %t -o /dev/null
# Verify that lld can handle sections with an alignment of zero.
diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s
index 7febec85a629..0832109fa898 100644
--- a/test/ELF/section-layout.s
+++ b/test/ELF/section-layout.s
@@ -1,7 +1,7 @@
+# REQUIRES: x86
# 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.
@@ -26,9 +26,10 @@ _start:
.section e,"awT"
.section d,"ax",@nobits
.section c,"ax"
-.section b,"a",@nobits
-.section a,"a"
+.section a,"a",@nobits
+.section b,"a"
+// For non-executable and non-writable sections, PROGBITS appear after others.
// CHECK: Name: a
// CHECK: Name: b
// CHECK: Name: c
diff --git a/test/ELF/section-metadata-err.s b/test/ELF/section-metadata-err.s
index 1bcbedfbab71..c9104303e434 100644
--- a/test/ELF/section-metadata-err.s
+++ b/test/ELF/section-metadata-err.s
@@ -1,9 +1,9 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: error: a section with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err.s.tmp.o:(.foo)
+# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err.s.tmp.o:(.foo)
.global _start
_start:
@@ -12,4 +12,4 @@ _start:
.section .foo,"aM",@progbits,8
.quad 0
-.section bar,"ao",@progbits,.foo
+.section .bar,"ao",@progbits,.foo
diff --git a/test/ELF/section-metadata-err2.s b/test/ELF/section-metadata-err2.s
new file mode 100644
index 000000000000..3191c1f4d3b6
--- /dev/null
+++ b/test/ELF/section-metadata-err2.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+## Check we do not crash and report proper errors.
+# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err2.s.tmp.o:(.foo)
+# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err2.s.tmp.o:(.foo)
+
+.section .foo,"aM",@progbits,8
+.quad 0
+
+.section .bar,"ao",@progbits,.foo,unique,1
+.quad 0
+
+.section .bar,"ao",@progbits,.foo,unique,2
+.quad 1
diff --git a/test/ELF/section-metadata-err3.s b/test/ELF/section-metadata-err3.s
new file mode 100644
index 000000000000..5c4875b9da5e
--- /dev/null
+++ b/test/ELF/section-metadata-err3.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: incompatible section flags for .bar
+# CHECK-NEXT: >>> {{.*}}section-metadata-err3.s.tmp.o:(.bar): 0x2
+# CHECK-NEXT: >>> output section .bar: 0x82
+
+.section .foo,"a",@progbits
+.quad 0
+
+.section .bar,"ao",@progbits,.foo,unique,1
+.quad 0
+
+.section .bar,"a",@progbits,unique,2
+.quad 1
diff --git a/test/ELF/section-name.s b/test/ELF/section-name.s
index caf574f2c106..4f010c81963c 100644
--- a/test/ELF/section-name.s
+++ b/test/ELF/section-name.s
@@ -1,7 +1,7 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld %t -o %tout
# RUN: llvm-objdump --section-headers %tout | FileCheck %s
-# REQUIRES: x86
.global _start
.text
diff --git a/test/ELF/section-symbol.s b/test/ELF/section-symbol.s
index 5cf71aceec72..495c38db5da9 100644
--- a/test/ELF/section-symbol.s
+++ b/test/ELF/section-symbol.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/section-symbols.test b/test/ELF/section-symbols.test
index 2ef77a828b65..973b1102fdf3 100644
--- a/test/ELF/section-symbols.test
+++ b/test/ELF/section-symbols.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t
-# RUN: ld.lld -shared %t -o %tout
+# RUN: ld.lld -shared %t -o /dev/null
# Verify that lld can handle STT_SECTION symbols associated
# with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
diff --git a/test/ELF/sectionstart-noallochdr.s b/test/ELF/sectionstart-noallochdr.s
index e9267a5372a5..be8e0c568e1e 100644
--- a/test/ELF/sectionstart-noallochdr.s
+++ b/test/ELF/sectionstart-noallochdr.s
@@ -7,7 +7,7 @@
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT DATA
+# CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT
# CHECK-NEXT: 2 .data 00000004 0000000000000020 DATA
# CHECK-NEXT: 3 .bss 00000004 0000000000000030 BSS
diff --git a/test/ELF/sectionstart.s b/test/ELF/sectionstart.s
index 23574c14748a..be8b5f0cfb40 100644
--- a/test/ELF/sectionstart.s
+++ b/test/ELF/sectionstart.s
@@ -1,13 +1,13 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld %t.o --section-start .text=0x100000 \
-# RUN: --section-start .data=0x110000 --section-start .bss=0x200000 -o %t
+# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000 -o %t
# RUN: llvm-objdump -section-headers %t | FileCheck %s
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT DATA
+# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT
# CHECK-NEXT: 2 .data 00000004 0000000000110000 DATA
# CHECK-NEXT: 3 .bss 00000004 0000000000200000 BSS
@@ -35,11 +35,11 @@
# RUN: llvm-objdump -section-headers %t4 | FileCheck %s
## Errors:
-# RUN: not ld.lld %t.o --section-start .text100000 -o %t2 2>&1 \
+# RUN: not ld.lld %t.o --section-start .text100000 -o /dev/null 2>&1 \
# RUN: | FileCheck -check-prefix=ERR1 %s
# ERR1: invalid argument: --section-start .text100000
-# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o %t3 2>&1 \
+# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o /dev/null 2>&1 \
# RUN: | FileCheck -check-prefix=ERR2 %s
# ERR2: invalid argument: --section-start .text=1Q0000
diff --git a/test/ELF/shared-lazy.s b/test/ELF/shared-lazy.s
index bc1e61c3c949..36b8f16e1794 100644
--- a/test/ELF/shared-lazy.s
+++ b/test/ELF/shared-lazy.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
// RUN: rm -f %t1.a
// RUN: llvm-ar rc %t1.a %t1.o
diff --git a/test/ELF/shared-be.s b/test/ELF/shared-ppc64.s
index 0b941d373720..f2280a1e8c1c 100644
--- a/test/ELF/shared-be.s
+++ b/test/ELF/shared-ppc64.s
@@ -1,9 +1,16 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-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
+
// 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
diff --git a/test/ELF/shared.s b/test/ELF/shared.s
index 65ad2c61359b..3a8fedec9240 100644
--- a/test/ELF/shared.s
+++ b/test/ELF/shared.s
@@ -1,3 +1,4 @@
+// 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: ld.lld --hash-style=sysv -shared %t2.o -o %t2.so
@@ -6,7 +7,6 @@
// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -hash-table %t | FileCheck %s
// RUN: ld.lld --hash-style=sysv %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
@@ -73,8 +73,8 @@
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 4
// CHECK-NEXT: EntrySize: 4
-
-// CHECK: Index: [[DYNSTR]]
+// CHECK: Section {
+// CHECK-NEXT: Index: [[DYNSTR]]
// CHECK-NEXT: Name: .dynstr
// CHECK-NEXT: Type: SHT_STRTAB
// CHECK-NEXT: Flags [
@@ -87,9 +87,6 @@
// 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
diff --git a/test/ELF/shlib-undefined-archive.s b/test/ELF/shlib-undefined-archive.s
new file mode 100644
index 000000000000..940d8d7bc0c5
--- /dev/null
+++ b/test/ELF/shlib-undefined-archive.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# Undefined symbols in a DSO should pull out object files from archives
+# to resolve them.
+
+# RUN: echo '.globl foo' | llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o -
+# RUN: ld.lld -shared -o %t.so %t1.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s
+# RUN: rm -f %t.a
+# RUN: llvm-ar cru %t.a %t2.o
+# RUN: ld.lld -o %t.exe %t.so %t.a
+# RUN: llvm-nm -D %t.exe | FileCheck %s
+
+# CHECK: T foo
+
+.globl foo
+foo:
+ ret
diff --git a/test/ELF/shlib-undefined-local.s b/test/ELF/shlib-undefined-local.s
new file mode 100644
index 000000000000..8fceec1bf60f
--- /dev/null
+++ b/test/ELF/shlib-undefined-local.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o %S/Inputs/shlib-undefined-ref.s
+# RUN: ld.lld -shared -o %t.so %t1.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld -version-script %t.script -o %t %t2.o %t.so
+# RUN: llvm-nm -g %t | FileCheck -allow-empty %s
+
+# CHECK-NOT: should_not_be_exported
+
+.globl should_not_be_exported
+should_not_be_exported:
+ ret
+
+.globl _start
+_start:
+ ret
diff --git a/test/ELF/shlib-undefined-shared.s b/test/ELF/shlib-undefined-shared.s
new file mode 100644
index 000000000000..6d60d01bfabe
--- /dev/null
+++ b/test/ELF/shlib-undefined-shared.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o %S/Inputs/shlib-undefined-ref.s
+# RUN: ld.lld -shared -o %t1.so %t1.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld -shared -version-script %t.script -o %t2.so %t2.o %t1.so
+# RUN: llvm-nm -g %t2.so | FileCheck -allow-empty %s
+
+# CHECK-NOT: should_not_be_exported
+
+.globl should_not_be_exported
+should_not_be_exported:
+ ret
diff --git a/test/ELF/sht-group-gold-r.test b/test/ELF/sht-group-gold-r.test
index 3a3889eabd81..d1757eee6e7d 100644
--- a/test/ELF/sht-group-gold-r.test
+++ b/test/ELF/sht-group-gold-r.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# GNU gold 1.14 (the newest version as of July 2017) seems to create
# non-standard-compliant SHT_GROUP sections when the -r option is given.
#
diff --git a/test/ELF/silent-ignore.test b/test/ELF/silent-ignore.test
index 6655754ace58..adfc2442d4ed 100644
--- a/test/ELF/silent-ignore.test
+++ b/test/ELF/silent-ignore.test
@@ -1,6 +1,5 @@
RUN: ld.lld --version \
RUN: -allow-shlib-undefined \
-RUN: -cref \
RUN: -g \
RUN: -no-add-needed \
RUN: -no-allow-shlib-undefined \
diff --git a/test/ELF/soname.s b/test/ELF/soname.s
index a26bb30f7a17..25c969dab745 100644
--- a/test/ELF/soname.s
+++ b/test/ELF/soname.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/soname2.s b/test/ELF/soname2.s
index 9fb8da519bfb..67a9c24af5cd 100644
--- a/test/ELF/soname2.s
+++ b/test/ELF/soname2.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/sort-norosegment.s b/test/ELF/sort-norosegment.s
index bd74f2eb330a..cd4fc9ebae16 100644
--- a/test/ELF/sort-norosegment.s
+++ b/test/ELF/sort-norosegment.s
@@ -1,13 +1,13 @@
# 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 %s -o %t.o
-# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t1 %t -shared
-# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t %t.o -shared
+# RUN: llvm-readelf -s %t | FileCheck %s
-# CHECK: .text {{.*}} AX
-# CHECK-NEXT: .dynsym {{.*}} A
+# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .hash {{.*}} A
# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: .text {{.*}} AX
# CHECK-NEXT: foo {{.*}} WA
# CHECK-NEXT: .dynamic {{.*}} WA
diff --git a/test/ELF/splitstacks.s b/test/ELF/splitstacks.s
deleted file mode 100644
index 3b7e67e5c2b0..000000000000
--- a/test/ELF/splitstacks.s
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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: .o: object file compiled with -fsplit-stack is not supported
-
-.globl _start
-_start:
- nop
-
-.section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/start-lib.s b/test/ELF/start-lib.s
index 013a2b206a1f..b79d9efc325a 100644
--- a/test/ELF/start-lib.s
+++ b/test/ELF/start-lib.s
@@ -21,5 +21,14 @@
// TEST3-NOT: Name: bar
// TEST3-NOT: Name: foo
+// RUN: not ld.lld %t1.o --start-lib --start-lib 2>&1 | FileCheck -check-prefix=NESTED-LIB %s
+// NESTED-LIB: nested --start-lib
+
+// RUN: not ld.lld %t1.o --start-group --start-lib 2>&1 | FileCheck -check-prefix=LIB-IN-GROUP %s
+// LIB-IN-GROUP: may not nest --start-lib in --start-group
+
+// RUN: not ld.lld --end-lib 2>&1 | FileCheck -check-prefix=END %s
+// END: stray --end-lib
+
.globl _start
_start:
diff --git a/test/ELF/startstop-shared.s b/test/ELF/startstop-shared.s
index 80ccf3df0aad..4d3192a35734 100644
--- a/test/ELF/startstop-shared.s
+++ b/test/ELF/startstop-shared.s
@@ -11,18 +11,30 @@
.quad __start_bar
.section bar,"a"
-// Test that we are able to hide the symbol.
-// CHECK: R_X86_64_RELATIVE - 0x[[ADDR:.*]]
+// CHECK: Relocations [
+// CHECK-NEXT: Section {{.*}} .rela.dyn {
+// CHECK-NEXT: R_X86_64_RELATIVE
+// CHECK-NEXT: R_X86_64_RELATIVE
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
-// By default the symbol is visible and we need a dynamic reloc.
-// CHECK: R_X86_64_64 __start_foo 0x0
+// Test that we are able to hide the symbol.
+// By default the symbol is protected.
// CHECK: Name: __start_bar
-// CHECK-NEXT: Value: 0x[[ADDR]]
+// CHECK-NEXT: Value:
// CHECK-NEXT: Size:
// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK: Name: __start_foo
// CHECK-NEXT: Value:
// CHECK-NEXT: Size:
// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_PROTECTED
+// CHECK-NEXT: ]
diff --git a/test/ELF/startstop.s b/test/ELF/startstop.s
index 1e75042a0c8c..470298eee37d 100644
--- a/test/ELF/startstop.s
+++ b/test/ELF/startstop.s
@@ -19,13 +19,12 @@
// DISASM: 1013: 90 nop
// DISASM: 1014: 90 nop
-
// SYMBOL: Relocations [
// SYMBOL-NEXT: Section ({{.*}}) .rela.dyn {
-// SYMBOL-NEXT: 0x2010 R_X86_64_64 __stop_zed1 0x0
-// SYMBOL-NEXT: 0x2018 R_X86_64_64 __stop_zed1 0x1
-// SYMBOL-NEXT: 0x2000 R_X86_64_64 __stop_zed2 0x0
-// SYMBOL-NEXT: 0x2008 R_X86_64_64 __stop_zed2 0x1
+// SYMBOL-NEXT: R_X86_64_RELATIVE
+// SYMBOL-NEXT: R_X86_64_RELATIVE
+// SYMBOL-NEXT: R_X86_64_RELATIVE
+// SYMBOL-NEXT: R_X86_64_RELATIVE
// SYMBOL-NEXT: }
// SYMBOL-NEXT: ]
@@ -45,20 +44,20 @@
// SYMBOL: Symbol {
// SYMBOL: Name: __stop_foo
// SYMBOL: Value: 0x1012
-// STMBOL: STV_HIDDEN
+// SYMBOL: STV_HIDDEN
// SYMBOL: Section: foo
// SYMBOL: }
// SYMBOL: Symbol {
// SYMBOL: Name: __stop_zed1
// SYMBOL: Value: 0x2010
-// STMBOL: Other: 0
+// SYMBOL: STV_PROTECTED
// SYMBOL: Section: zed1
// SYMBOL: }
// SYMBOL: Symbol {
// SYMBOL: Name: __stop_zed2
// SYMBOL: Value: 0x2020
-// STMBOL: Other: 0
+// SYMBOL: STV_PROTECTED
// SYMBOL: Section: zed2
// SYMBOL: }
diff --git a/test/ELF/static-with-export-dynamic.s b/test/ELF/static-with-export-dynamic.s
index 8634835d9aa7..f0c67df22623 100644
--- a/test/ELF/static-with-export-dynamic.s
+++ b/test/ELF/static-with-export-dynamic.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-cloudabi %s -o %t.o
// RUN: ld.lld --export-dynamic %t.o -o %t
// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
-// REQUIRES: x86
// Ensure that a dynamic symbol table is present when --export-dynamic
// is passed in, even when creating statically linked executables.
diff --git a/test/ELF/string-gc.s b/test/ELF/string-gc.s
index 96c75e9236f4..8e4ee14e0f47 100644
--- a/test/ELF/string-gc.s
+++ b/test/ELF/string-gc.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/string-table.s b/test/ELF/string-table.s
index 490c4d574cf1..2a975501d951 100644
--- a/test/ELF/string-table.s
+++ b/test/ELF/string-table.s
@@ -1,7 +1,7 @@
+// 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 %t2 | FileCheck %s
-// REQUIRES: x86
.global _start
_start:
diff --git a/test/ELF/symbol-ordering-file-icf.s b/test/ELF/symbol-ordering-file-icf.s
new file mode 100644
index 000000000000..93e377cb53b0
--- /dev/null
+++ b/test/ELF/symbol-ordering-file-icf.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "zed" > %t.order
+# RUN: echo "bar" >> %t.order
+# RUN: echo "foo" >> %t.order
+# RUN: ld.lld --icf=all --symbol-ordering-file %t.order -shared %t.o -o %t.so
+# RUN: llvm-nm %t.so | FileCheck %s
+
+## Check that after ICF merges 'foo' and 'zed' we still
+## place them before 'bar', in according to ordering file.
+# CHECK-DAG: 0000000000001000 T foo
+# CHECK-DAG: 0000000000001000 T zed
+# CHECK-DAG: 0000000000001004 T bar
+
+.section .text.foo,"ax",@progbits
+.align 4
+.global foo
+foo:
+ retq
+
+.section .text.bar,"ax",@progbits
+.align 4
+.global bar
+bar:
+ nop
+ retq
+
+.section .text.zed,"ax",@progbits
+.align 4
+.global zed
+zed:
+ retq
diff --git a/test/ELF/symbol-ordering-file-warnings.s b/test/ELF/symbol-ordering-file-warnings.s
new file mode 100644
index 000000000000..71414bf58098
--- /dev/null
+++ b/test/ELF/symbol-ordering-file-warnings.s
@@ -0,0 +1,165 @@
+# 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 %S/Inputs/symbol-ordering-file-warnings1.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symbol-ordering-file-warnings2.s -o %t3.o
+# RUN: ld.lld -shared %t2.o -o %t.so
+
+# Check that a warning is emitted for entries in the file that are not present in any used input.
+# RUN: echo "missing" > %t-order-missing.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MISSING
+
+# Check that the warning can be disabled.
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \
+# RUN: --unresolved-symbols=ignore-all --no-warn-symbol-ordering 2>&1 | \
+# RUN: FileCheck %s --check-prefixes=WARN --allow-empty
+
+# Check that the warning can be re-enabled
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \
+# RUN: --unresolved-symbols=ignore-all --no-warn-symbol-ordering --warn-symbol-ordering 2>&1 | \
+# RUN: FileCheck %s --check-prefixes=WARN,MISSING
+
+# Check that a warning is emitted for undefined symbols.
+# RUN: echo "undefined" > %t-order-undef.txt
+# RUN: ld.lld %t1.o %t3.o -o %t --symbol-ordering-file %t-order-undef.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,UNDEFINED
+
+# Check that a warning is emitted for imported shared symbols.
+# RUN: echo "shared" > %t-order-shared.txt
+# RUN: ld.lld %t1.o %t.so -o %t --symbol-ordering-file %t-order-shared.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SHARED
+
+# Check that a warning is emitted for absolute symbols.
+# RUN: echo "absolute" > %t-order-absolute.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-absolute.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,ABSOLUTE
+
+# Check that a warning is emitted for symbols discarded due to --gc-sections.
+# RUN: echo "gc" > %t-order-gc.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-gc.txt --gc-sections \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,GC
+
+# Check that a warning is not emitted for the symbol removed due to --icf.
+# RUN: echo "icf1" > %t-order-icf.txt
+# RUN: echo "icf2" >> %t-order-icf.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-icf.txt --icf=all \
+# RUN: --unresolved-symbols=ignore-all --fatal-warnings
+
+# RUN: echo "_GLOBAL_OFFSET_TABLE_" > %t-order-synthetic.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-synthetic.txt --icf=all \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SYNTHETIC
+
+# Check that a warning is emitted for symbols discarded due to a linker script /DISCARD/ section.
+# RUN: echo "discard" > %t-order-discard.txt
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.text.discard) } }" > %t.script
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-discard.txt -T %t.script \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,DISCARD
+
+# Check that LLD does not warn for discarded COMDAT symbols, if they are present in the kept instance.
+# RUN: echo "comdat" > %t-order-comdat.txt
+# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-comdat.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN --allow-empty
+
+# Check that if a COMDAT was unused and discarded via --gc-sections, warn for each instance.
+# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-comdat.txt --gc-sections \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,COMDAT
+
+# Check that if a weak symbol is not kept, because of an equivalent global symbol, no warning is emitted.
+# RUN: echo "glob_or_wk" > %t-order-weak.txt
+# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-weak.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN --allow-empty
+
+# Check that symbols only in unused archive members result in a warning.
+# RUN: rm -f %t.a
+# RUN: llvm-ar rc %t.a %t3.o
+# RUN: ld.lld %t1.o %t.a -o %t --symbol-ordering-file %t-order-missing.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MISSING --allow-empty
+
+# Check that a warning for each same-named symbol with an issue.
+# RUN: echo "multi" > %t-order-same-name.txt
+# RUN: ld.lld %t1.o %t2.o %t3.o -o %t --symbol-ordering-file %t-order-same-name.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MULTI
+
+# Check that a warning is emitted if the same symbol is mentioned multiple times in the ordering file.
+# RUN: echo "_start" > %t-order-multiple-same.txt
+# RUN: echo "_start" >> %t-order-multiple-same.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-multiple-same.txt \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM
+
+# Check that all warnings can be emitted from the same input.
+# RUN: echo "missing_sym" > %t-order-multi.txt
+# RUN: echo "undefined" >> %t-order-multi.txt
+# RUN: echo "_start" >> %t-order-multi.txt
+# RUN: echo "shared" >> %t-order-multi.txt
+# RUN: echo "absolute" >> %t-order-multi.txt
+# RUN: echo "gc" >> %t-order-multi.txt
+# RUN: echo "discard" >> %t-order-multi.txt
+# RUN: echo "_GLOBAL_OFFSET_TABLE_" >> %t-order-multi.txt
+# RUN: echo "_start" >> %t-order-multi.txt
+# RUN: ld.lld %t1.o %t3.o %t.so -o %t --symbol-ordering-file %t-order-multi.txt --gc-sections -T %t.script \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM,ABSOLUTE,SHARED,UNDEFINED,GC,DISCARD,MISSING2,SYNTHETIC
+
+# WARN-NOT: warning:
+# SAMESYM: warning: {{.*}}.txt: duplicate ordered symbol: _start
+# WARN-NOT: warning:
+# SYNTHETIC: warning: <internal>: unable to order synthetic symbol: _GLOBAL_OFFSET_TABLE_
+# WARN-NOT: warning:
+# DISCARD: warning: {{.*}}1.o: unable to order discarded symbol: discard
+# WARN-NOT: warning:
+# GC: warning: {{.*}}1.o: unable to order discarded symbol: gc
+# WARN-NOT: warning:
+# SHARED: warning: {{.*}}.so: unable to order shared symbol: shared
+# WARN-NOT: warning:
+# UNDEFINED: warning: {{.*}}3.o: unable to order undefined symbol: undefined
+# WARN-NOT: warning:
+# ABSOLUTE: warning: {{.*}}1.o: unable to order absolute symbol: absolute
+# WARN-NOT: warning:
+# MISSING: warning: symbol ordering file: no such symbol: missing
+# MISSING2: warning: symbol ordering file: no such symbol: missing_sym
+# COMDAT: warning: {{.*}}1.o: unable to order discarded symbol: comdat
+# MULTI: warning: {{.*}}3.o: unable to order undefined symbol: multi
+# MULTI-NEXT: warning: {{.*}}2.o: unable to order absolute symbol: multi
+# WARN-NOT: warning:
+
+absolute = 0x1234
+
+.section .text.gc,"ax",@progbits
+.global gc
+gc:
+ nop
+
+.section .text.discard,"ax",@progbits
+.global discard
+discard:
+ nop
+
+.section .text.comdat,"axG",@progbits,comdat,comdat
+.weak comdat
+comdat:
+ nop
+
+.section .text.glob_or_wk,"ax",@progbits
+.weak glob_or_wk
+glob_or_wk:
+ nop
+
+.section .text._start,"ax",@progbits
+.global _start
+_start:
+ movq %rax, absolute
+ callq shared
+
+.section .text.icf1,"ax",@progbits
+.global icf1
+icf1:
+ ret
+
+.section .text.icf2,"ax",@progbits
+.global icf2
+icf2:
+ ret
+
+# This is a "good" instance of the symbol
+.section .text.multi,"ax",@progbits
+multi:
+ .quad _GLOBAL_OFFSET_TABLE_
diff --git a/test/ELF/symbol-ordering-file.s b/test/ELF/symbol-ordering-file.s
index 5a88b8c0827f..34d67701933e 100644
--- a/test/ELF/symbol-ordering-file.s
+++ b/test/ELF/symbol-ordering-file.s
@@ -5,6 +5,8 @@
# BEFORE: Contents of section .foo:
# BEFORE-NEXT: 201000 11223344 5566
+# BEFORE: Contents of section .init:
+# BEFORE-NEXT: 201006 1122
# RUN: echo "_foo4 " > %t_order.txt
# RUN: echo " _foo3" >> %t_order.txt
@@ -14,12 +16,18 @@
# RUN: echo "_foo4" >> %t_order.txt
# RUN: echo "_bar1" >> %t_order.txt
# RUN: echo "_foo1" >> %t_order.txt
+# RUN: echo "_init2" >> %t_order.txt
+# RUN: echo "_init1" >> %t_order.txt
# RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out
# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER
+# RUN: ld.lld --symbol-ordering-file=%t_order.txt %t.o -o %t2.out
+# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER
# AFTER: Contents of section .foo:
# AFTER-NEXT: 201000 44335566 2211
+# AFTER: Contents of section .init:
+# AFTER-NEXT: 201006 1122
.section .foo,"ax",@progbits,unique,1
_foo1:
@@ -42,3 +50,11 @@ _foo5:
.byte 0x55
_bar1:
.byte 0x66
+
+.section .init,"ax",@progbits,unique,1
+_init1:
+ .byte 0x11
+
+.section .init,"ax",@progbits,unique,2
+_init2:
+ .byte 0x22
diff --git a/test/ELF/symbol-override.s b/test/ELF/symbol-override.s
index 8b62d8749aa0..2c3573381c1c 100644
--- a/test/ELF/symbol-override.s
+++ b/test/ELF/symbol-override.s
@@ -1,3 +1,4 @@
+// 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/symbol-override.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
diff --git a/test/ELF/symbols.s b/test/ELF/symbols.s
index 54dfcbd087cd..e87b6438494a 100644
--- a/test/ELF/symbols.s
+++ b/test/ELF/symbols.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s
index be50503a3f5d..3e22dd24b66d 100644
--- a/test/ELF/symver-archive.s
+++ b/test/ELF/symver-archive.s
@@ -4,7 +4,7 @@
# RUN: llvm-ar rcs %t.a %t1
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o
-# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a
+# RUN: ld.lld -o /dev/null %t2.o %t3.o %t.a
.text
.globl x
diff --git a/test/ELF/sysroot.s b/test/ELF/sysroot.s
index 6b40c7d3952a..e9d6862b7a32 100644
--- a/test/ELF/sysroot.s
+++ b/test/ELF/sysroot.s
@@ -1,10 +1,10 @@
+// REQUIRES: x86
// 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 \
diff --git a/test/ELF/sysv-hash-no-rosegment.s b/test/ELF/sysv-hash-no-rosegment.s
new file mode 100644
index 000000000000..31b9d2fbec05
--- /dev/null
+++ b/test/ELF/sysv-hash-no-rosegment.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -shared --no-rosegment -o %t %t.o
+# RUN: llvm-readobj -hash-table %t | FileCheck %s
+
+# CHECK: HashTable {
+# CHECK-NEXT: Num Buckets: 2
+# CHECK-NEXT: Num Chains: 2
+# CHECK-NEXT: Buckets: [1, 0]
+# CHECK-NEXT: Chains: [0, 0]
+# CHECK-NEXT: }
+
+callq undef@PLT
diff --git a/test/ELF/text-section-prefix.s b/test/ELF/text-section-prefix.s
new file mode 100644
index 000000000000..e39536da387d
--- /dev/null
+++ b/test/ELF/text-section-prefix.s
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -z keep-text-section-prefix %t -o %t2
+# RUN: llvm-readelf -l %t2 | FileCheck %s
+# RUN: ld.lld %t -o %t3
+# RUN: llvm-readelf -l %t3 | FileCheck --check-prefix=CHECKNO %s
+# RUN: ld.lld -z nokeep-text-section-prefix %t -o %t4
+# RUN: llvm-readelf -l %t4 | FileCheck --check-prefix=CHECKNO %s
+
+# CHECK: .text
+# CHECK: .text.hot
+# CHECK: .text.startup
+# CHECK: .text.exit
+# CHECK: .text.unlikely
+# CHECKNO: .text
+# CHECKNO-NOT: .text.hot
+
+_start:
+ ret
+
+.section .text.f,"ax"
+f:
+ nop
+
+.section .text.hot.f_hot,"ax"
+f_hot:
+ nop
+
+.section .text.startup.f_startup,"ax"
+f_startup:
+ nop
+
+.section .text.exit.f_exit,"ax"
+f_exit:
+ nop
+
+.section .text.unlikely.f_unlikely,"ax"
+f_unlikely:
+ nop
diff --git a/test/ELF/tls-archive.s b/test/ELF/tls-archive.s
index 9a88fddffd36..640e68ac3a7f 100644
--- a/test/ELF/tls-archive.s
+++ b/test/ELF/tls-archive.s
@@ -3,7 +3,7 @@
// 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
+// RUN: ld.lld %t.a %t -o /dev/null
.globl _start,tlsvar
_start:
diff --git a/test/ELF/tls-error.s b/test/ELF/tls-error.s
index b61789901049..989a63eb709b 100644
--- a/test/ELF/tls-error.s
+++ b/test/ELF/tls-error.s
@@ -1,6 +1,6 @@
// 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
+// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s
// CHECK: R_X86_64_TPOFF32 out of range
.global _start
diff --git a/test/ELF/tls-got.s b/test/ELF/tls-got.s
index b1686cd6d5f4..bedaaebeeb3c 100644
--- a/test/ELF/tls-got.s
+++ b/test/ELF/tls-got.s
@@ -1,3 +1,4 @@
+// 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/tls-got.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
@@ -25,13 +26,13 @@
// CHECK: Relocations [
// CHECK-NEXT: Section (4) .rela.dyn {
// CHECK-NEXT: 0x2020B8 R_X86_64_TPOFF64 tls0 0x0
-// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0
+// CHECK-NEXT: 0x2020B0 R_X86_64_TPOFF64 tls1 0x0
// CHECK-NEXT: }
// CHECK-NEXT: ]
-//0x201000 + 4249 + 7 = 0x2020B0
-//0x20100A + 4247 + 7 = 0x2020B8
-//0x201014 + 4237 + 7 = 0x2020B8
+//0x201000 + 4265 + 7 = 0x2020B0
+//0x20100A + 4263 + 7 = 0x2020B8
+//0x201014 + 4253 + 7 = 0x2020B8
//DISASM: Disassembly of section .text:
//DISASM-NEXT: main:
//DISASM-NEXT: 201000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax
diff --git a/test/ELF/tls-in-archive.s b/test/ELF/tls-in-archive.s
index 71f60e380f33..ac1b4cc11ea4 100644
--- a/test/ELF/tls-in-archive.s
+++ b/test/ELF/tls-in-archive.s
@@ -2,7 +2,7 @@
// 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
+// RUN: ld.lld %t2.o %t.a -o /dev/null
.globl _start
_start:
diff --git a/test/ELF/tls-mismatch.s b/test/ELF/tls-mismatch.s
index 21994d19af32..d7ce224c1fbb 100644
--- a/test/ELF/tls-mismatch.s
+++ b/test/ELF/tls-mismatch.s
@@ -1,7 +1,7 @@
// 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
+// RUN: not ld.lld %t %t2 -o /dev/null 2>&1 | FileCheck %s
// CHECK: TLS attribute mismatch: tlsvar
// CHECK: >>> defined in
diff --git a/test/ELF/tls-opt-gdie.s b/test/ELF/tls-opt-gdie.s
index 6e8531257714..6d0eb979149a 100644
--- a/test/ELF/tls-opt-gdie.s
+++ b/test/ELF/tls-opt-gdie.s
@@ -1,3 +1,4 @@
+// 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-opt-gdie.s -o %tso.o
// RUN: ld.lld -shared %tso.o -o %t.so
diff --git a/test/ELF/tls-opt-gdiele-i686.s b/test/ELF/tls-opt-gdiele-i686.s
index 2dc3731eba57..b39f933e2fdb 100644
--- a/test/ELF/tls-opt-gdiele-i686.s
+++ b/test/ELF/tls-opt-gdiele-i686.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
diff --git a/test/ELF/tls-opt-i686.s b/test/ELF/tls-opt-i686.s
index dec45b4e5c41..d8b1d0eca0b7 100644
--- a/test/ELF/tls-opt-i686.s
+++ b/test/ELF/tls-opt-i686.s
@@ -1,3 +1,4 @@
+// REQUIRES: x86
// 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
@@ -11,11 +12,11 @@
// 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: 11007: 8d 74 26 00 leal (%esi,%eiz), %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: 11018: 8d 74 26 00 leal (%esi,%eiz), %esi
// DISASM-NEXT: 1101c: 8d 90 fc ff ff ff leal -4(%eax), %edx
// IE -> LE:
// 4294967288 == 0xFFFFFFF8
diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s
index 02148b5dbff9..50655e34a4ff 100644
--- a/test/ELF/tls-opt-iele-i686-nopic.s
+++ b/test/ELF/tls-opt-iele-i686-nopic.s
@@ -1,3 +1,4 @@
+// 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/tls-opt-iele-i686-nopic.s -o %tso.o
// RUN: ld.lld -shared %tso.o -o %tso
diff --git a/test/ELF/tls-opt-local.s b/test/ELF/tls-opt-local.s
index 633c22b0611c..e937d4d5d972 100644
--- a/test/ELF/tls-opt-local.s
+++ b/test/ELF/tls-opt-local.s
@@ -1,3 +1,4 @@
+// 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-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
diff --git a/test/ELF/tls-opt-no-plt.s b/test/ELF/tls-opt-no-plt.s
index 53655d0934d5..c61388648fb1 100644
--- a/test/ELF/tls-opt-no-plt.s
+++ b/test/ELF/tls-opt-no-plt.s
@@ -1,3 +1,4 @@
+// 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/tls-opt-gdie.s -o %t2.o
// RUN: ld.lld %t2.o -o %t2.so -shared
diff --git a/test/ELF/tls-opt.s b/test/ELF/tls-opt.s
index 6835e06f3402..856e82c4b323 100644
--- a/test/ELF/tls-opt.s
+++ b/test/ELF/tls-opt.s
@@ -1,3 +1,4 @@
+// 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-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
diff --git a/test/ELF/tls-static.s b/test/ELF/tls-static.s
index 338d95c817ee..3e1aead01a30 100644
--- a/test/ELF/tls-static.s
+++ b/test/ELF/tls-static.s
@@ -1,10 +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 %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: ld.lld -static %t %tshared -o %tout
-// REQUIRES: x86
.global _start
_start:
diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s
index c8ba9b21bcdb..b5c1ddc2a558 100644
--- a/test/ELF/trace-symbols.s
+++ b/test/ELF/trace-symbols.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# Test -y symbol and -trace-symbol=symbol
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
@@ -28,7 +29,7 @@
# 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: %t %t2 %t1 -o /dev/null 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
# OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo
@@ -69,12 +70,15 @@
# 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
+# SHLIBRBAR: 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
+## Check we do not crash when trying to trace special symbol.
+# RUN: not ld.lld -trace-symbol=_end %t -o /dev/null
+
.hidden hsymbol
.globl _start
.type _start, @function
diff --git a/test/ELF/typed-undef.s b/test/ELF/typed-undef.s
index d00e07f82518..879a80975bc8 100644
--- a/test/ELF/typed-undef.s
+++ b/test/ELF/typed-undef.s
@@ -3,7 +3,7 @@
# We used to crash on this, check that we don't
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld %t.o -o %t -pie --unresolved-symbols=ignore-all
+# RUN: ld.lld %t.o -o /dev/null -pie --unresolved-symbols=ignore-all
.global _start
_start:
diff --git a/test/ELF/undef-broken-debug.test b/test/ELF/undef-broken-debug.test
index 1238ebe70aca..b93d399f36c2 100644
--- a/test/ELF/undef-broken-debug.test
+++ b/test/ELF/undef-broken-debug.test
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: yaml2obj %s -o %t.o
-# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
# The debug info has a broken relocation. Check that we don't crash
# and still report the undefined symbol.
@@ -40,6 +40,27 @@ Sections:
- Offset: 0x0000000000000029
Symbol: bar
Type: R_X86_64_64
+ - Name: .debug_info
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: 0C000000040000000000080100000000
+ - Name: .rela.debug_info
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .debug_info
+ Relocations:
+ - Offset: 0x0000000000000006
+ Symbol: .debug_abbrev
+ Type: R_X86_64_32
+ - Offset: 0x000000000000000C
+ Symbol: .debug_line
+ Type: R_X86_64_32
+ - Name: .debug_abbrev
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: '0111001017000000'
+
Symbols:
Global:
- Name: _start
diff --git a/test/ELF/undef-shared.s b/test/ELF/undef-shared.s
index bc38b6082765..701f70ea94e6 100644
--- a/test/ELF/undef-shared.s
+++ b/test/ELF/undef-shared.s
@@ -1,5 +1,6 @@
+# REQUIRES: x86
# 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
+# RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
# CHECK: error: undefined symbol: hidden
# CHECK: >>> referenced by {{.*}}:(.data+0x0)
diff --git a/test/ELF/undef-shared2.s b/test/ELF/undef-shared2.s
new file mode 100644
index 000000000000..cae5ea45642d
--- /dev/null
+++ b/test/ELF/undef-shared2.s
@@ -0,0 +1,11 @@
+# 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-shared2.s -o %t2.o
+# RUN: not ld.lld %t.o %t2.o -o %t.so -shared 2>&1 | FileCheck %s
+# RUN: not ld.lld %t2.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: foo
+
+.data
+.quad foo
+.protected foo
diff --git a/test/ELF/undef-start.s b/test/ELF/undef-start.s
index 590d0a80096b..5c591bf70d52 100644
--- a/test/ELF/undef-start.s
+++ b/test/ELF/undef-start.s
@@ -1,3 +1,5 @@
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 2>&1
# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: warning: cannot find entry symbol _start
diff --git a/test/ELF/undef-version-script.s b/test/ELF/undef-version-script.s
index 024ac1dc0727..712589e2444f 100644
--- a/test/ELF/undef-version-script.s
+++ b/test/ELF/undef-version-script.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/ELF/undef.s b/test/ELF/undef.s
index 49f84108f64a..07e3b689a236 100644
--- a/test/ELF/undef.s
+++ b/test/ELF/undef.s
@@ -2,9 +2,10 @@
# 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-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-bad-debug.s -o %t4.o
# RUN: llvm-ar rc %t2.a %t2.o
-# RUN: not ld.lld %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
-# RUN: not ld.lld -pie %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld -pie %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s
# CHECK: error: undefined symbol: foo
# CHECK: >>> referenced by undef.s
@@ -33,6 +34,19 @@
# CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11)
# CHECK: >>> {{.*}}.o:(.text.2+0x0)
+# Show that all line table problems are mentioned as soon as the object's line information
+# is requested, even if that particular part of the line information is not currently required.
+# CHECK: warning: parsing line table prologue at 0x00000000 should have ended at 0x00000038 but it ended at 0x00000037
+# CHECK: warning: last sequence in debug line table is not terminated!
+# CHECK: error: undefined symbol: zed6
+# CHECK: >>> referenced by {{.*}}tmp4.o:(.text+0x0)
+
+# Show that a problem with one line table's information doesn't affect getting information from
+# a different one in the same object.
+# CHECK: error: undefined symbol: zed7
+# CHECK: >>> referenced by undef-bad-debug2.s:11 (dir2{{/|\\}}undef-bad-debug2.s:11)
+# CHECK: >>> {{.*}}tmp4.o:(.text+0x8)
+
# RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \
# RUN: FileCheck -check-prefix=NO-DEMANGLE %s
# NO-DEMANGLE: error: undefined symbol: _Z3fooi
diff --git a/test/ELF/undefined-opt.s b/test/ELF/undefined-opt.s
index d8b793d7bab4..9e93e0fdce4d 100644
--- a/test/ELF/undefined-opt.s
+++ b/test/ELF/undefined-opt.s
@@ -1,3 +1,4 @@
+# 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/abs.s -o %tabs.o
@@ -5,7 +6,6 @@
# 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
diff --git a/test/ELF/unresolved-symbols.s b/test/ELF/unresolved-symbols.s
index 97ecd5014b12..69da3e63c6d4 100644
--- a/test/ELF/unresolved-symbols.s
+++ b/test/ELF/unresolved-symbols.s
@@ -21,7 +21,7 @@
## 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: not ld.lld %t2.o -o /dev/null --unresolved-symbols=ignore-all --no-undefined 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
# ERRUND: error: undefined symbol: undef
# ERRUND: >>> referenced by {{.*}}:(.text+0x1)
@@ -34,11 +34,11 @@
# 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: ld.lld %t1.o %t.so -o /dev/null --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: not ld.lld %t2.o -o /dev/null --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
@@ -60,9 +60,9 @@
# 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: not ld.lld %t2.o -o /dev/null --unresolved-symbols=report-all 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
-# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | FileCheck -check-prefix=ERRUND %s
+# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | 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
index 6c33166d1d4e..a06dbd84ea43 100644
--- a/test/ELF/user_def_init_array_start.s
+++ b/test/ELF/user_def_init_array_start.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: ld.lld %t.o -o %t2.so -shared
+// RUN: ld.lld %t.o -o /dev/null -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.
diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s
index 496a29e3db5a..c8444c4e0663 100644
--- a/test/ELF/verdef-defaultver.s
+++ b/test/ELF/verdef-defaultver.s
@@ -196,6 +196,6 @@
.globl _start
_start:
- callq a
- callq b
- callq c
+ .long a - .
+ .long b - .
+ .long c - .
diff --git a/test/ELF/verneed-local.s b/test/ELF/verneed-local.s
index 208d8ecf8f62..d779a48c024d 100644
--- a/test/ELF/verneed-local.s
+++ b/test/ELF/verneed-local.s
@@ -4,7 +4,7 @@
# RUN: ld.lld -shared %t1.o --version-script %t.script -o %t.so
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: not ld.lld %t.o %t.so -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o %t.so -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: undefined symbol: f3
# CHECK: >>> referenced by {{.*}}:(.text+0x1)
diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s
index 27ab047e8222..6e87f046e304 100644
--- a/test/ELF/verneed.s
+++ b/test/ELF/verneed.s
@@ -10,67 +10,69 @@
# RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s
# CHECK: Section {
-# CHECK: Index: 1
-# CHECK-NEXT: Name: .dynsym
-# CHECK-NEXT: Type: SHT_DYNSYM (0xB)
+# CHECK: Index: 1
+# CHECK-NEXT: Name: .dynsym
+# CHECK-NEXT: Type: SHT_DYNSYM (0xB)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2001C8
+# CHECK-NEXT: Offset: 0x1C8
+# CHECK-NEXT: Size: 96
+# CHECK-NEXT: Link: [[DYNSTR:.*]]
+# CHECK-NEXT: Info: 1
+# CHECK-NEXT: AddressAlignment: 8
+# CHECK-NEXT: EntrySize: 24
+
+# CHECK: Section {
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Name: .gnu.version
+# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF)
# CHECK-NEXT: Flags [ (0x2)
# CHECK-NEXT: SHF_ALLOC (0x2)
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x2001C8
-# 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
-# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF)
-# CHECK-NEXT: Flags [ (0x2)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x200228
-# 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-NEXT: Address: [[VERSYM:.*]]
+# CHECK-NEXT: Offset: [[VERSYM_OFFSET:.*]]
+# 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
-# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE)
-# CHECK-NEXT: Flags [ (0x2)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x200230
-# 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: 0x2002A8
-# 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: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v|
-# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.|
-# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .gnu.version_r
+# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: [[VERNEED:.*]]
+# 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: Index: [[DYNSTR]]
+# CHECK-NEXT: Name: .dynstr
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2002A8
+# 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: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v|
+# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.|
+# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.|
+# CHECK-NEXT: )
+# CHECK-NEXT: }
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
@@ -111,14 +113,14 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
-# CHECK: 0x000000006FFFFFF0 VERSYM 0x200228
-# CHECK-NEXT: 0x000000006FFFFFFE VERNEED 0x200230
+# CHECK: 0x000000006FFFFFF0 VERSYM [[VERSYM]]
+# CHECK-NEXT: 0x000000006FFFFFFE VERNEED [[VERNEED]]
# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM 2
# CHECK: Version symbols {
# CHECK-NEXT: Section Name: .gnu.version
-# CHECK-NEXT: Address: 0x200228
-# CHECK-NEXT: Offset: 0x228
+# CHECK-NEXT: Address: [[VERSYM]]
+# CHECK-NEXT: Offset: [[VERSYM_OFFSET]]
# CHECK-NEXT: Link: 1
# CHECK-NEXT: Symbols [
# CHECK-NEXT: Symbol {
diff --git a/test/ELF/version-exclude-libs.s b/test/ELF/version-exclude-libs.s
new file mode 100644
index 000000000000..7335c2315eba
--- /dev/null
+++ b/test/ELF/version-exclude-libs.s
@@ -0,0 +1,30 @@
+// REQUIRES: x86
+// RUN: llvm-mc %p/Inputs/versiondef.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-ar -r %t.a %t.o
+// RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o %t.a --shared --exclude-libs ALL -o %t.so
+// RUN: llvm-readobj -symbols %t.so | FileCheck %s
+// RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix CHECK-DYN %s
+// RUN: not ld.lld %t2.o %t.a --shared -o %t.so 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
+
+// Test that we do not give an error message for undefined versions when the
+// symbol is not exported to the dynamic symbol table.
+
+// CHECK: Name: func
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local (0x0)
+
+// CHECK-DYN-NOT: func
+
+// CHECK-ERR: symbol func@@VER2 has undefined version VER2
+// CHECK-ERR-NEXT: symbol func@VER has undefined version VER
+
+ .text
+ .globl _start
+ .globl func
+_start:
+ ret
+
+ .data
+ .quad func
diff --git a/test/ELF/version-script-complex-wildcards.s b/test/ELF/version-script-complex-wildcards.s
index 61e1069e2eac..ce001d0b76c3 100644
--- a/test/ELF/version-script-complex-wildcards.s
+++ b/test/ELF/version-script-complex-wildcards.s
@@ -46,7 +46,7 @@
# RUN: llvm-readobj -V %t8.so | FileCheck %s --check-prefix=ABBABC
# RUN: echo "FOO { global: extern \"C++\" { a[; }; };" > %t9.script
-# RUN: not ld.lld --version-script %t9.script -shared %t.o -o %t9.so 2>&1 \
+# RUN: not ld.lld --version-script %t9.script -shared %t.o -o /dev/null 2>&1 \
# RUN: | FileCheck %s --check-prefix=ERROR
# ERROR: invalid glob pattern: a[
diff --git a/test/ELF/version-script-extern-undefined.s b/test/ELF/version-script-extern-undefined.s
new file mode 100644
index 000000000000..518b122ce7cd
--- /dev/null
+++ b/test/ELF/version-script-extern-undefined.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { global: extern \"C++\" { \"abb(int)\"; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s
+
+# CHECK: Symbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 0
+# CHECK-NEXT: Name: @
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Name: _Z3abbi@
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.globl _Z3abbi
diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s
index c63ff817fb40..16f400354356 100644
--- a/test/ELF/version-script-extern.s
+++ b/test/ELF/version-script-extern.s
@@ -7,7 +7,7 @@
# RUN: echo "LIBSAMPLE_2.0 { global:" >> %t.script
# RUN: echo ' extern "C" { _Z3bari; };' >> %t.script
# RUN: echo "};" >> %t.script
-# RUN: ld.lld --hash-style=sysv --version-script %t.script -shared %t.o -o %t.so
+# RUN: ld.lld --hash-style=sysv --version-script %t.script -soname fixed-length-string -shared %t.o -o %t.so
# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
# DSO: DynamicSymbols [
diff --git a/test/ELF/version-script-extern2.s b/test/ELF/version-script-extern2.s
new file mode 100644
index 000000000000..834bbe1122e5
--- /dev/null
+++ b/test/ELF/version-script-extern2.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { global: extern \"C++\" { \"bar\"; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s
+
+# CHECK: Symbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 0
+# CHECK-NEXT: Name: @
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Version: 2
+# CHECK-NEXT: Name: bar@@FOO
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.globl bar
+.type bar,@function
+bar:
+retq
diff --git a/test/ELF/version-script-glob.s b/test/ELF/version-script-glob.s
index 8149ead8292f..d9ead0503d64 100644
--- a/test/ELF/version-script-glob.s
+++ b/test/ELF/version-script-glob.s
@@ -48,7 +48,7 @@ local:
# CHECK-NEXT: ]
# RUN: echo "{ global : local; local: *; };" > %t1.script
-# RUN: ld.lld -shared --version-script %t1.script %t.o -o %t1.so
+# RUN: ld.lld -shared --version-script %t1.script %t.o -o /dev/null
# LOCAL: DynamicSymbols [
# LOCAL-NEXT: Symbol {
diff --git a/test/ELF/version-script-in-search-path.s b/test/ELF/version-script-in-search-path.s
new file mode 100644
index 000000000000..948f33792a9c
--- /dev/null
+++ b/test/ELF/version-script-in-search-path.s
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# Check that we fall back to search paths if a version script was not found
+# This behaviour matches ld.bfd.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: mkdir -p %T/searchpath
+# RUN: echo '{};' > %T/searchpath/%basename_t.script
+# RUN: ld.lld -L%T/searchpath --version-script=%basename_t.script %t.o -o /dev/null
+# RUN: not ld.lld --version-script=%basename_t.script %t.o 2>&1 | FileCheck -check-prefix ERROR %s
+# ERROR: error: cannot find version script
diff --git a/test/ELF/version-script-missing.s b/test/ELF/version-script-missing.s
index ad4786e70cc5..a82a37e41271 100644
--- a/test/ELF/version-script-missing.s
+++ b/test/ELF/version-script-missing.s
@@ -4,4 +4,4 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "{ foobar; };" > %t.script
-# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: ld.lld --version-script %t.script -shared %t.o -o /dev/null
diff --git a/test/ELF/version-script-no-warn.s b/test/ELF/version-script-no-warn.s
index 6a897159d2d0..d99b87bf937b 100644
--- a/test/ELF/version-script-no-warn.s
+++ b/test/ELF/version-script-no-warn.s
@@ -5,7 +5,7 @@
# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
# RUN: echo "foo { global: bar; local: *; };" > %t.script
-# RUN: ld.lld --fatal-warnings --shared --version-script %t.script %t.o %t2.so
+# RUN: ld.lld --fatal-warnings --shared --version-script %t.script %t.o %t2.so -o /dev/null
.global bar
bar:
diff --git a/test/ELF/version-script-no-warn2.s b/test/ELF/version-script-no-warn2.s
index 52beff366bb7..795fbb0b4f28 100644
--- a/test/ELF/version-script-no-warn2.s
+++ b/test/ELF/version-script-no-warn2.s
@@ -1,8 +1,9 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/version-script-no-warn2.s -o %t1.o
# RUN: ld.lld %t1.o -o %t1.so -shared
# RUN: echo "{ global: foo; local: *; };" > %t.script
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
-# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o %t2.so --fatal-warnings
+# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o /dev/null --fatal-warnings
.global foo
foo:
diff --git a/test/ELF/version-script-noundef.s b/test/ELF/version-script-noundef.s
index 247752cac844..0eae1fcdb05a 100644
--- a/test/ELF/version-script-noundef.s
+++ b/test/ELF/version-script-noundef.s
@@ -2,6 +2,8 @@
# RUN: echo "VERSION_1.0 { global: bar; };" > %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 -o %t.so
+# RUN: ld.lld --version-script %t.script -shared --undefined-version %t.o -o %t.so
# 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
diff --git a/test/ELF/version-script-symver.s b/test/ELF/version-script-symver.s
index 0a4eddd46cec..b6355949fad0 100644
--- a/test/ELF/version-script-symver.s
+++ b/test/ELF/version-script-symver.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: ld.lld %t.o -o %t
+# RUN: ld.lld %t.o -o /dev/null
.global _start
.global bar
diff --git a/test/ELF/version-script.s b/test/ELF/version-script.s
index abc716250eba..75083ac9a767 100644
--- a/test/ELF/version-script.s
+++ b/test/ELF/version-script.s
@@ -34,9 +34,9 @@
# RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t6.script
# RUN: echo "VERSION_2.0 { global: foo1; 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: not ld.lld --version-script %t6.script -shared %t.o %t2.so -o /dev/null 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR3 %s
+# ERR3: duplicate symbol 'foo1' in version script
# RUN: echo "{ foo1; foo2; };" > %t.list
# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2
@@ -213,6 +213,9 @@
# ALL-NEXT: }
# ALL-NEXT: ]
+# RUN: echo "VERSION_1.0 { global: foo1; foo1; local: *; };" > %t8.script
+# RUN: ld.lld --version-script %t8.script -shared %t.o -o /dev/null --fatal-warnings
+
.globl foo1
foo1:
call bar@PLT
diff --git a/test/ELF/version-symbol-error.s b/test/ELF/version-symbol-error.s
index fb83b359485b..f916fe7b34f8 100644
--- a/test/ELF/version-symbol-error.s
+++ b/test/ELF/version-symbol-error.s
@@ -1,7 +1,7 @@
// REQUIRES: x86
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
// RUN: echo "V1 {};" > %t.script
-// RUN: not ld.lld -shared -version-script=%t.script %t.o -o %t.so 2>&1 \
+// RUN: not ld.lld -shared -version-script=%t.script %t.o -o /dev/null 2>&1 \
// RUN: | FileCheck %s
// CHECK: .o: symbol foo@V2 has undefined version V2
diff --git a/test/ELF/version-undef-sym.s b/test/ELF/version-undef-sym.s
index 20e92e61f647..13a6dc41fd10 100644
--- a/test/ELF/version-undef-sym.s
+++ b/test/ELF/version-undef-sym.s
@@ -35,7 +35,7 @@
// CHECK: Name: bar
// But now we can successfully find bar.
-// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o %t.exe
+// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o /dev/null
.global _start
_start:
diff --git a/test/ELF/visibility.s b/test/ELF/visibility.s
index 7af29c957b52..0582d718e8ee 100644
--- a/test/ELF/visibility.s
+++ b/test/ELF/visibility.s
@@ -1,8 +1,8 @@
+// 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/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 {
diff --git a/test/ELF/warn-backrefs.s b/test/ELF/warn-backrefs.s
new file mode 100644
index 000000000000..28937e199cae
--- /dev/null
+++ b/test/ELF/warn-backrefs.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo ".globl foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t2.o
+# RUN: rm -f %t2.a
+# RUN: llvm-ar rcs %t2.a %t2.o
+
+# RUN: ld.lld --fatal-warnings -o %t.exe %t1.o %t2.a
+# RUN: ld.lld --fatal-warnings -o %t.exe %t2.a %t1.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o %t2.a
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o --start-lib %t2.o --end-lib
+
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a %t1.o --end-group
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t2.a %t1.o "-)"
+
+# RUN: echo "INPUT(\"%t1.o\" \"%t2.a\")" > %t1.script
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.script
+
+# RUN: echo "GROUP(\"%t2.a\" \"%t1.o\")" > %t2.script
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.script
+
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a %t1.o 2>&1 | FileCheck %s
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a "-(" %t1.o "-)" 2>&1 | FileCheck %s
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a --end-group %t1.o 2>&1 | FileCheck %s
+
+# RUN: echo "GROUP(\"%t2.a\")" > %t3.script
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t3.script %t1.o 2>&1 | FileCheck %s
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t3.script %t1.o "-)"
+
+# CHECK: backward reference detected: foo in {{.*}}1.o refers to {{.*}}2.a
+
+# RUN: not ld.lld --fatal-warnings --start-group --start-group 2>&1 | FileCheck -check-prefix=START %s
+# START: nested --start-group
+
+# RUN: not ld.lld --fatal-warnings --end-group 2>&1 | FileCheck -check-prefix=END %s
+# END: stray --end-group
+
+# RUN: echo ".globl bar; bar:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t3.o
+# RUN: echo ".globl foo; foo: call bar" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs %t1.o --start-lib %t3.o %t4.o --end-lib -o /dev/null
+
+# We don't report backward references to weak symbols as they can be overriden later.
+# RUN: echo ".weak foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t5.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs --start-lib %t5.o --end-lib %t1.o %t2.o -o /dev/null
+
+.globl _start, foo
+_start:
+ call foo
diff --git a/test/ELF/warn-common.s b/test/ELF/warn-common.s
index 783a9ab77b56..ddb4b687a5aa 100644
--- a/test/ELF/warn-common.s
+++ b/test/ELF/warn-common.s
@@ -7,9 +7,7 @@
# 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
+# RUN: ld.lld --fatal-warnings --warn-common --no-warn-common %t1.o %t2.o -o %t.out
## Report if common is overridden
# RUN: ld.lld --warn-common %t1.o %t3.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER
diff --git a/test/ELF/warn-unresolved-symbols-hidden.s b/test/ELF/warn-unresolved-symbols-hidden.s
index 04691f9af948..9e3d9e152104 100644
--- a/test/ELF/warn-unresolved-symbols-hidden.s
+++ b/test/ELF/warn-unresolved-symbols-hidden.s
@@ -1,6 +1,6 @@
# 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 -z defs --warn-unresolved-symbols 2>&1| FileCheck %s
+# RUN: not ld.lld -shared %t.o -o /dev/null -z defs --warn-unresolved-symbols 2>&1| FileCheck %s
# CHECK: warning: undefined symbol: foo
# CHECK: error: undefined symbol: bar
diff --git a/test/ELF/warn-unresolved-symbols.s b/test/ELF/warn-unresolved-symbols.s
index 3342c6ce50a2..608b35580291 100644
--- a/test/ELF/warn-unresolved-symbols.s
+++ b/test/ELF/warn-unresolved-symbols.s
@@ -2,11 +2,11 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
## The link should fail with an undef error by default
-# RUN: not ld.lld %t1.o -o %t3 2>&1 | \
+# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
## --error-unresolved-symbols should generate an error
-# RUN: not ld.lld %t1.o -o %t4 --error-unresolved-symbols 2>&1 | \
+# RUN: not ld.lld %t1.o -o /dev/null --error-unresolved-symbols 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
## --warn-unresolved-symbols should generate a warning
@@ -16,19 +16,19 @@
## Test that the last option wins
# RUN: ld.lld %t1.o -o %t5 --error-unresolved-symbols --warn-unresolved-symbols 2>&1 | \
# RUN: FileCheck -check-prefix=WARNUND %s
-# RUN: not ld.lld %t1.o -o %t6 --warn-unresolved-symbols --error-unresolved-symbols 2>&1 | \
+# RUN: not ld.lld %t1.o -o /dev/null --warn-unresolved-symbols --error-unresolved-symbols 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
## Do not report undefines if linking relocatable or shared.
## And while we're at it, check that we can accept single -
## variants of these options.
-# RUN: ld.lld -r %t1.o -o %t7 -error-unresolved-symbols 2>&1 | \
+# RUN: ld.lld -r %t1.o -o /dev/null -error-unresolved-symbols 2>&1 | \
# RUN: FileCheck -allow-empty -check-prefix=NOERR %s
-# RUN: ld.lld -shared %t1.o -o %t8.so --error-unresolved-symbols 2>&1 | \
+# RUN: ld.lld -shared %t1.o -o /dev/null --error-unresolved-symbols 2>&1 | \
# RUN: FileCheck -allow-empty -check-prefix=NOERR %s
-# RUN: ld.lld -r %t1.o -o %t9 -warn-unresolved-symbols 2>&1 | \
+# RUN: ld.lld -r %t1.o -o /dev/null -warn-unresolved-symbols 2>&1 | \
# RUN: FileCheck -allow-empty -check-prefix=NOWARN %s
-# RUN: ld.lld -shared %t1.o -o %t10.so --warn-unresolved-symbols 2>&1 | \
+# RUN: ld.lld -shared %t1.o -o /dev/null --warn-unresolved-symbols 2>&1 | \
# RUN: FileCheck -allow-empty -check-prefix=NOWARN %s
# ERRUND: error: undefined symbol: undef
diff --git a/test/ELF/weak-and-strong-undef.s b/test/ELF/weak-and-strong-undef.s
index db93470636df..32ce649bb147 100644
--- a/test/ELF/weak-and-strong-undef.s
+++ b/test/ELF/weak-and-strong-undef.s
@@ -1,6 +1,6 @@
# 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/weak-and-strong-undef.s -o %t2.o
+# RUN: echo ".weak foo" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s
# RUN: not ld.lld %t2.o %t1.o -o %t 2>&1 | FileCheck %s
diff --git a/test/ELF/weak-shared-gc.s b/test/ELF/weak-shared-gc.s
new file mode 100644
index 000000000000..2cafbe8dbb08
--- /dev/null
+++ b/test/ELF/weak-shared-gc.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo -e '.globl __cxa_finalize\n__cxa_finalize:' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld %t1.o --as-needed --gc-sections %t2.so -o %t
+# RUN: llvm-readelf -dynamic-table -dyn-symbols %t | FileCheck %s
+
+# The crt files on linux have a weak reference to __cxa_finalize. It
+# is important that a weak undefined reference is produced. Like
+# other weak undefined references, the shared library is not marked as
+# needed.
+
+# CHECK-NOT: NEEDED
+# CHECK: WEAK DEFAULT UND __cxa_finalize
+# CHECK-NOT: NEEDED
+
+ .global _start
+_start:
+ .weak __cxa_finalize
+ call __cxa_finalize@PLT
diff --git a/test/ELF/weak-undef-lazy.s b/test/ELF/weak-undef-lazy.s
index 113013ea2e0f..0a4188fca271 100644
--- a/test/ELF/weak-undef-lazy.s
+++ b/test/ELF/weak-undef-lazy.s
@@ -3,7 +3,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/weak-undef-lazy.s -o %t2.o
# RUN: rm -f %t2.a
# RUN: llvm-ar rc %t2.a %t2.o
-# RUN: ld.lld %t.o %t2.a -o %t --export-dynamic
+# RUN: ld.lld %t.o %t2.a -o /dev/null --export-dynamic
.global _start
_start:
diff --git a/test/ELF/weak-undef-lib.s b/test/ELF/weak-undef-lib.s
new file mode 100644
index 000000000000..e4e7f46ebaa9
--- /dev/null
+++ b/test/ELF/weak-undef-lib.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo -e '.globl foo\nfoo: ret' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+
+# RUN: ld.lld -shared -o %t.so %t1.o --start-lib %t2.o
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Weak
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined
+
+.weak foo
+.data
+.quad foo
diff --git a/test/ELF/weak-undef-rw.s b/test/ELF/weak-undef-rw.s
new file mode 100644
index 000000000000..c75e7d67db3d
--- /dev/null
+++ b/test/ELF/weak-undef-rw.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t --export-dynamic
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: R_X86_64_64 foobar 0x0
+
+ .global _start
+_start:
+ .data
+ .weak foobar
+ .quad foobar
diff --git a/test/ELF/whole-archive-name.s b/test/ELF/whole-archive-name.s
new file mode 100644
index 000000000000..1cf7962e62fd
--- /dev/null
+++ b/test/ELF/whole-archive-name.s
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: mkdir -p %t.dir
+// RUN: rm -f %t.dir/liba.a
+// RUN: llvm-ar rcs %t.dir/liba.a %t.o
+// RUN: ld.lld -L%t.dir --whole-archive -la -o /dev/null -Map=- | FileCheck %s
+
+.globl _start
+_start:
+ nop
+
+// There was a use after free of an archive name.
+// Valgrind/asan would detect it.
+// CHECK: liba.a(whole-archive-name.s.tmp.o):(.text)
+// CHECK-NEXT: _start
diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s
index b96917b7be49..a02592e24ebd 100644
--- a/test/ELF/wrap.s
+++ b/test/ELF/wrap.s
@@ -6,6 +6,8 @@
// 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
+// RUN: ld.lld -o %t3 %t %t2 --wrap foo --wrap foo -wrap=nosuchsym
+// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s
// CHECK: _start:
// CHECK-NEXT: movl $0x11010, %edx
diff --git a/test/ELF/writable-merge.s b/test/ELF/writable-merge.s
index 3006fa387fb5..91a7e07d7ce5 100644
--- a/test/ELF/writable-merge.s
+++ b/test/ELF/writable-merge.s
@@ -1,6 +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
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
// CHECK: writable SHF_MERGE section is not supported
.section .foo,"awM",@progbits,4
diff --git a/test/ELF/writable-sec-plt-reloc.s b/test/ELF/writable-sec-plt-reloc.s
index 97a21b5fac02..c44ca6a696c5 100644
--- a/test/ELF/writable-sec-plt-reloc.s
+++ b/test/ELF/writable-sec-plt-reloc.s
@@ -11,4 +11,4 @@
.section .bar,"awx"
.global _start
_start:
- call foo
+ .long foo - .
diff --git a/test/ELF/x86-64-dyn-rel-error.s b/test/ELF/x86-64-dyn-rel-error.s
index 7a705eb54177..7753a4dc4aec 100644
--- a/test/ELF/x86-64-dyn-rel-error.s
+++ b/test/ELF/x86-64-dyn-rel-error.s
@@ -9,6 +9,8 @@ _start:
.data
.long zed
-// CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
+// CHECK: relocation R_X86_64_32 cannot be used against symbol zed; recompile with -fPIC
-// RUN: ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck %s
+// RUN: ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=WARN %s
+
+// WARN: symbol 'zed' has no type
diff --git a/test/ELF/x86-64-dyn-rel-error2.s b/test/ELF/x86-64-dyn-rel-error2.s
index 9b731e268875..b3259395d245 100644
--- a/test/ELF/x86-64-dyn-rel-error2.s
+++ b/test/ELF/x86-64-dyn-rel-error2.s
@@ -2,9 +2,9 @@
// 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 -shared %t.o %t2.so -o %t 2>&1 | FileCheck %s
+// RUN: not ld.lld -shared %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s
-// CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC
+// CHECK: relocation R_X86_64_PC32 cannot be used against symbol zed; recompile with -fPIC
// CHECK: >>> defined in {{.*}}.so
// CHECK: >>> referenced by {{.*}}.o:(.data+0x0)
diff --git a/test/ELF/x86-64-dyn-rel-error3.s b/test/ELF/x86-64-dyn-rel-error3.s
new file mode 100644
index 000000000000..86cef1426df9
--- /dev/null
+++ b/test/ELF/x86-64-dyn-rel-error3.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -shared -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_8 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_16 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_PC8 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_PC16 cannot be used against symbol foo; recompile with -fPIC
+
+.global foo
+
+.data
+.byte foo # R_X86_64_8
+.short foo # R_X86_64_16
+.byte foo - . # R_X86_64_PC8
+.short foo - . # R_X86_64_PC16
diff --git a/test/ELF/x86-64-plt-high-addr.s b/test/ELF/x86-64-plt-high-addr.s
new file mode 100644
index 000000000000..4acccb63f4a7
--- /dev/null
+++ b/test/ELF/x86-64-plt-high-addr.s
@@ -0,0 +1,24 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t1.o
+// RUN: ld.lld -o %t.so -shared %t1.o
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld -o %t1.exe %t2.o %t.so -image-base=0xcafe00000000
+// RUN: llvm-objdump -s -j .got.plt %t1.exe | FileCheck %s
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: cafe00002000 00300000 feca0000 00000000 00000000
+// CHECK-NEXT: cafe00002010 00000000 00000000 26100000 feca0000
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld -o %t2.exe %t2.o %t.so -image-base=0xcafe00000000 -z retpolineplt
+// RUN: llvm-objdump -s -j .got.plt %t2.exe | FileCheck -check-prefix=RETPOLINE %s
+
+// RETPOLINE: Contents of section .got.plt:
+// RETPOLINE-NEXT: cafe00002000 00300000 feca0000 00000000 00000000
+// RETPOLINE-NEXT: cafe00002010 00000000 00000000 51100000 feca0000
+
+.global _start
+_start:
+ jmp bar@PLT
diff --git a/test/ELF/x86-64-reloc-16.s b/test/ELF/x86-64-reloc-16.s
index 4822ec71757b..5157c3706fef 100644
--- a/test/ELF/x86-64-reloc-16.s
+++ b/test/ELF/x86-64-reloc-16.s
@@ -3,12 +3,12 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
-// RUN: ld.lld -shared %t %t1 -o %t3
+// RUN: ld.lld -shared %t %t1 -o /dev/null
// CHECK: Contents of section .text:
// CHECK-NEXT: 200000 42
-// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
// ERROR: relocation R_X86_64_16 out of range: 65536 is not in [0, 65535]
.short foo
diff --git a/test/ELF/x86-64-reloc-32-fpic.s b/test/ELF/x86-64-reloc-32-fpic.s
index e3e7c6834d21..1c4754f1e2c6 100644
--- a/test/ELF/x86-64-reloc-32-fpic.s
+++ b/test/ELF/x86-64-reloc-32-fpic.s
@@ -1,8 +1,8 @@
# 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
+# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
+# CHECK: relocation R_X86_64_32 cannot be used against symbol _shared; recompile with -fPIC
# CHECK: >>> defined in {{.*}}
# CHECK: >>> referenced by {{.*}}:(.data+0x0)
diff --git a/test/ELF/x86-64-reloc-8.s b/test/ELF/x86-64-reloc-8.s
index 8f6ba5aa14bb..f71bafb7ffb1 100644
--- a/test/ELF/x86-64-reloc-8.s
+++ b/test/ELF/x86-64-reloc-8.s
@@ -3,12 +3,12 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8.s -o %t1
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8-error.s -o %t2
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
-// RUN: ld.lld -shared %t %t1 -o %t3
+// RUN: ld.lld -shared %t %t1 -o /dev/null
// CHECK: Contents of section .text:
// CHECK-NEXT: 200000 42
-// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
// ERROR: relocation R_X86_64_8 out of range: 256 is not in [0, 255]
.byte foo
diff --git a/test/ELF/x86-64-reloc-debug-overflow.s b/test/ELF/x86-64-reloc-debug-overflow.s
new file mode 100644
index 000000000000..d6e6650acd3e
--- /dev/null
+++ b/test/ELF/x86-64-reloc-debug-overflow.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# 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 /dev/null 2>&1 | FileCheck %s
+
+# CHECK: (.debug_info+0x0): relocation R_X86_64_32 out of range: 281474976710656 is not in [0, 4294967295]; consider recompiling with -fdebug-types-section to reduce size of debug sections
+
+.section .debug_info,"",@progbits
+ .long .debug_info + 0x1000000000000
diff --git a/test/ELF/x86-64-reloc-error-reporting.s b/test/ELF/x86-64-reloc-error-reporting.s
new file mode 100644
index 000000000000..bb9c8be8accb
--- /dev/null
+++ b/test/ELF/x86-64-reloc-error-reporting.s
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// 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
+
+// We have some code in error reporting to check that
+// section belongs to the output section. Without that
+// check, the linker would crash, so it is useful to test it.
+// And the easy way to do that is to trigger GC. That way .text.dumb
+// be collected and mentioned check will execute.
+
+// RUN: not ld.lld -gc-sections -shared %tabs %t -o /dev/null
+
+.section .text.dumb,"ax"
+ nop
+
+.section .text,"ax"
+.globl _start
+_start:
+ movl $big, %edx
diff --git a/test/ELF/x86-64-reloc-error.s b/test/ELF/x86-64-reloc-error.s
index cb600d9bf1e3..0c3bebef04b5 100644
--- a/test/ELF/x86-64-reloc-error.s
+++ b/test/ELF/x86-64-reloc-error.s
@@ -1,7 +1,7 @@
+// REQUIRES: x86
// 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
+// RUN: not ld.lld -shared %tabs %t -o /dev/null 2>&1 | FileCheck %s
movl $big, %edx
movq $foo - 0x1000000000000, %rdx
diff --git a/test/ELF/x86-64-reloc-error2.s b/test/ELF/x86-64-reloc-error2.s
new file mode 100644
index 000000000000..d49b67522654
--- /dev/null
+++ b/test/ELF/x86-64-reloc-error2.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+## Check we are able to find a function symbol that encloses
+## a given location when reporting error messages.
+# CHECK: {{.*}}.o:(function func): relocation R_X86_64_32S out of range: -281474974609408 is not in [-2147483648, 2147483647]
+
+.section .text.func, "ax", %progbits
+.globl func
+.type func,@function
+.size func, 0x10
+func:
+ movq func - 0x1000000000000, %rdx
diff --git a/test/ELF/x86-64-reloc-gotoff64.s b/test/ELF/x86-64-reloc-gotoff64.s
new file mode 100644
index 000000000000..697ac17917a2
--- /dev/null
+++ b/test/ELF/x86-64-reloc-gotoff64.s
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+// 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-readelf -s %t.so | FileCheck %s -check-prefix=SECTION
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+// SECTION: .dynamic DYNAMIC 0000000000003000
+// SECTION: .got PROGBITS 0000000000003070 003070 000000
+
+// All the _GLOBAL_OFFSET_TABLE_ occurrences below refer to the address
+// of GOT base, not the address of the symbol _GLOBAL_OFFSET_TABLE_. These
+// instructions are special and produce GOT base relative relocations. We
+// currently use .got end as the GOT base, which is not equal to
+// the address of the special symbol _GLOBAL_OFFSET_TABLE_.
+
+// The assembly is generated by
+// gcc -O2 -S -mcmodel=medium -fPIC a.c
+// This computes the pc-relative address (runtime address) of _DYNAMIC.
+//
+// extern long _DYNAMIC[] __attribute__((visibility("hidden")));
+// long* dynamic() { return _DYNAMIC; }
+
+// 0x3070 (.got end) - 0x1007 = 8297
+// 0x3000 (_DYNAMIC) - 0x3070 (.got end) = -112
+// CHECK: 1000: {{.*}} leaq 8297(%rip), %rdx
+// CHECK-NEXT: 1007: {{.*}} movabsq $-112, %rax
+.global dynamic
+dynamic:
+ leaq _GLOBAL_OFFSET_TABLE_(%rip), %rdx
+ movabsq $_DYNAMIC@GOTOFF, %rax
+ addq %rdx, %rax
+ ret
diff --git a/test/ELF/x86-64-reloc-gotpc64.s b/test/ELF/x86-64-reloc-gotpc64.s
new file mode 100644
index 000000000000..f07376f41218
--- /dev/null
+++ b/test/ELF/x86-64-reloc-gotpc64.s
@@ -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 -shared -o %t.so
+// RUN: llvm-readelf -s %t.so | FileCheck %s -check-prefix=SECTION
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+// SECTION: .got PROGBITS 0000000000003070 003070 000000
+
+// 0x3070 (.got end) - 0x1000 = 8304
+// CHECK: gotpc64:
+// CHECK-NEXT: 1000: {{.*}} movabsq $8304, %r11
+.global gotpc64
+gotpc64:
+ movabsq $_GLOBAL_OFFSET_TABLE_-., %r11
diff --git a/test/ELF/x86-64-reloc-pc32-fpic.s b/test/ELF/x86-64-reloc-pc32-fpic.s
index 399bf604f806..2dfd1bfb444c 100644
--- a/test/ELF/x86-64-reloc-pc32-fpic.s
+++ b/test/ELF/x86-64-reloc-pc32-fpic.s
@@ -1,10 +1,11 @@
# 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
+# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC
+# CHECK: relocation R_X86_64_PC32 cannot be used against symbol _shared; recompile with -fPIC
# CHECK: >>> defined in {{.*}}
# CHECK: >>> referenced by {{.*}}:(.data+0x1)
.data
-call _shared
+ .byte 0xe8
+ .long _shared - .
diff --git a/test/ELF/x86-64-reloc-range-debug-loc.s b/test/ELF/x86-64-reloc-range-debug-loc.s
new file mode 100644
index 000000000000..8be4df3c5202
--- /dev/null
+++ b/test/ELF/x86-64-reloc-range-debug-loc.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs
+# RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
+# RUN: not ld.lld %tabs %t.o -o /dev/null -shared 2>&1 | FileCheck %s
+
+## Check we are able to report file and location from debug information
+## when reporting such kind of errors.
+# CHECK: error: test.s:3: relocation R_X86_64_32 out of range: 68719476736 is not in [0, 4294967295]
+
+.section .text,"ax",@progbits
+foo:
+.file 1 "test.s"
+.loc 1 3
+ movl $big, %edx
+
+.section .debug_abbrev,"",@progbits
+.byte 1 # Abbreviation Code
+.byte 17 # DW_TAG_compile_unit
+.byte 0 # DW_CHILDREN_no
+.byte 16 # DW_AT_stmt_list
+.byte 23 # DW_FORM_sec_offset
+.byte 0 # EOM(1)
+.byte 0 # EOM(2)
+.byte 0 # EOM(3)
+
+.section .debug_info,"",@progbits
+.long .Lend0 - .Lbegin0 # Length of Unit
+.Lbegin0:
+.short 4 # DWARF version number
+.long .debug_abbrev # Offset Into Abbrev. Section
+.byte 8 # Address Size (in bytes)
+.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+.long .debug_line # DW_AT_stmt_list
+.Lend0:
+
+.section .debug_line,"",@progbits
diff --git a/test/ELF/x86-64-reloc-range.s b/test/ELF/x86-64-reloc-range.s
index 2913458ab5cb..c58a692821ec 100644
--- a/test/ELF/x86-64-reloc-range.s
+++ b/test/ELF/x86-64-reloc-range.s
@@ -1,5 +1,6 @@
+// REQUIRES: x86
// 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
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
// CHECK: {{.*}}:(.text+0x3): relocation R_X86_64_PC32 out of range: 2147483648 is not in [-2147483648, 2147483647]
// CHECK-NOT: relocation
diff --git a/test/ELF/x86-64-reloc-tpoff32-fpic.s b/test/ELF/x86-64-reloc-tpoff32-fpic.s
index 5be3dc317012..edb04c1d4487 100644
--- a/test/ELF/x86-64-reloc-tpoff32-fpic.s
+++ b/test/ELF/x86-64-reloc-tpoff32-fpic.s
@@ -1,8 +1,8 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: not ld.lld %t.o -shared -o %t.so 2>&1 | FileCheck %s
+# RUN: not ld.lld %t.o -shared -o /dev/null 2>&1 | FileCheck %s
-# CHECK: relocation R_X86_64_TPOFF32 cannot be used against shared object; recompile with -fPIC
+# CHECK: relocation R_X86_64_TPOFF32 cannot be used against symbol var; recompile with -fPIC
# CHECK: >>> defined in {{.*}}.o
# CHECK: >>> referenced by {{.*}}.o:(.tdata+0xC)
diff --git a/test/ELF/x86-64-retpoline-linkerscript.s b/test/ELF/x86-64-retpoline-linkerscript.s
new file mode 100644
index 000000000000..82d2ca6374c1
--- /dev/null
+++ b/test/ELF/x86-64-retpoline-linkerscript.s
@@ -0,0 +1,67 @@
+// 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: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .plt : { *(.plt) } \
+// RUN: .got.plt : { *(.got.plt) } \
+// RUN: .dynstr : { *(.dynstr) } \
+// RUN: }" > %t.script
+// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt --script %t.script
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 10: ff 35 72 00 00 00 pushq 114(%rip)
+// CHECK-NEXT: 16: 4c 8b 1d 73 00 00 00 movq 115(%rip), %r11
+// CHECK-NEXT: 1d: e8 0e 00 00 00 callq 14 <.plt+0x20>
+// CHECK-NEXT: 22: f3 90 pause
+// CHECK-NEXT: 24: 0f ae e8 lfence
+// CHECK-NEXT: 27: eb f9 jmp -7 <.plt+0x12>
+// CHECK-NEXT: 29: cc int3
+// CHECK-NEXT: 2a: cc int3
+// CHECK-NEXT: 2b: cc int3
+// CHECK-NEXT: 2c: cc int3
+// CHECK-NEXT: 2d: cc int3
+// CHECK-NEXT: 2e: cc int3
+// CHECK-NEXT: 2f: cc int3
+// CHECK-NEXT: 30: 4c 89 1c 24 movq %r11, (%rsp)
+// CHECK-NEXT: 34: c3 retq
+// CHECK-NEXT: 35: cc int3
+// CHECK-NEXT: 36: cc int3
+// CHECK-NEXT: 37: cc int3
+// CHECK-NEXT: 38: cc int3
+// CHECK-NEXT: 39: cc int3
+// CHECK-NEXT: 3a: cc int3
+// CHECK-NEXT: 3b: cc int3
+// CHECK-NEXT: 3c: cc int3
+// CHECK-NEXT: 3d: cc int3
+// CHECK-NEXT: 3e: cc int3
+// CHECK-NEXT: 3f: cc int3
+// CHECK-NEXT: 40: 4c 8b 1d 51 00 00 00 movq 81(%rip), %r11
+// CHECK-NEXT: 47: e8 e4 ff ff ff callq -28 <.plt+0x20>
+// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
+// CHECK-NEXT: 51: 68 00 00 00 00 pushq $0
+// CHECK-NEXT: 56: e9 b5 ff ff ff jmp -75 <.plt>
+// CHECK-NEXT: 5b: cc int3
+// CHECK-NEXT: 5c: cc int3
+// CHECK-NEXT: 5d: cc int3
+// CHECK-NEXT: 5e: cc int3
+// CHECK-NEXT: 5f: cc int3
+// CHECK-NEXT: 60: 4c 8b 1d 39 00 00 00 movq 57(%rip), %r11
+// CHECK-NEXT: 67: e8 c4 ff ff ff callq -60 <.plt+0x20>
+// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
+// CHECK-NEXT: 71: 68 01 00 00 00 pushq $1
+// CHECK-NEXT: 76: e9 95 ff ff ff jmp -107 <.plt>
+// CHECK-NEXT: 7b: cc int3
+// CHECK-NEXT: 7c: cc int3
+// CHECK-NEXT: 7d: cc int3
+// CHECK-NEXT: 7e: cc int3
+// CHECK-NEXT: 7f: cc int3
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/x86-64-retpoline-znow-linkerscript.s b/test/ELF/x86-64-retpoline-znow-linkerscript.s
new file mode 100644
index 000000000000..20196058d251
--- /dev/null
+++ b/test/ELF/x86-64-retpoline-znow-linkerscript.s
@@ -0,0 +1,54 @@
+// 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: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .plt : { *(.plt) } \
+// RUN: .got.plt : { *(.got.plt) } \
+// RUN: .dynstr : { *(.dynstr) } \
+// RUN: }" > %t.script
+// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now --script %t.script
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 10: e8 0b 00 00 00 callq 11 <.plt+0x10>
+// CHECK-NEXT: 15: f3 90 pause
+// CHECK-NEXT: 17: 0f ae e8 lfence
+// CHECK-NEXT: 1a: eb f9 jmp -7 <.plt+0x5>
+// CHECK-NEXT: 1c: cc int3
+// CHECK-NEXT: 1d: cc int3
+// CHECK-NEXT: 1e: cc int3
+// CHECK-NEXT: 1f: cc int3
+// CHECK-NEXT: 20: 4c 89 1c 24 movq %r11, (%rsp)
+// CHECK-NEXT: 24: c3 retq
+// CHECK-NEXT: 25: cc int3
+// CHECK-NEXT: 26: cc int3
+// CHECK-NEXT: 27: cc int3
+// CHECK-NEXT: 28: cc int3
+// CHECK-NEXT: 29: cc int3
+// CHECK-NEXT: 2a: cc int3
+// CHECK-NEXT: 2b: cc int3
+// CHECK-NEXT: 2c: cc int3
+// CHECK-NEXT: 2d: cc int3
+// CHECK-NEXT: 2e: cc int3
+// CHECK-NEXT: 2f: cc int3
+// CHECK-NEXT: 30: 4c 8b 1d 31 00 00 00 movq 49(%rip), %r11
+// CHECK-NEXT: 37: e9 d4 ff ff ff jmp -44 <.plt>
+// CHECK-NEXT: 3c: cc int3
+// CHECK-NEXT: 3d: cc int3
+// CHECK-NEXT: 3e: cc int3
+// CHECK-NEXT: 3f: cc int3
+// CHECK-NEXT: 40: 4c 8b 1d 29 00 00 00 movq 41(%rip), %r11
+// CHECK-NEXT: 47: e9 c4 ff ff ff jmp -60 <.plt>
+// CHECK-NEXT: 4c: cc int3
+// CHECK-NEXT: 4d: cc int3
+// CHECK-NEXT: 4e: cc int3
+// CHECK-NEXT: 4f: cc int3
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/x86-64-retpoline-znow.s b/test/ELF/x86-64-retpoline-znow.s
new file mode 100644
index 000000000000..6464e2c0971f
--- /dev/null
+++ b/test/ELF/x86-64-retpoline-znow.s
@@ -0,0 +1,53 @@
+// 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 -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 1010: e8 0b 00 00 00 callq 11 <.plt+0x10>
+// CHECK-NEXT: 1015: f3 90 pause
+// CHECK-NEXT: 1017: 0f ae e8 lfence
+// CHECK-NEXT: 101a: eb f9 jmp -7 <.plt+0x5>
+// CHECK-NEXT: 101c: cc int3
+// CHECK-NEXT: 101d: cc int3
+// CHECK-NEXT: 101e: cc int3
+// CHECK-NEXT: 101f: cc int3
+// CHECK-NEXT: 1020: 4c 89 1c 24 movq %r11, (%rsp)
+// CHECK-NEXT: 1024: c3 retq
+// CHECK-NEXT: 1025: cc int3
+// CHECK-NEXT: 1026: cc int3
+// CHECK-NEXT: 1027: cc int3
+// CHECK-NEXT: 1028: cc int3
+// CHECK-NEXT: 1029: cc int3
+// CHECK-NEXT: 102a: cc int3
+// CHECK-NEXT: 102b: cc int3
+// CHECK-NEXT: 102c: cc int3
+// CHECK-NEXT: 102d: cc int3
+// CHECK-NEXT: 102e: cc int3
+// CHECK-NEXT: 102f: cc int3
+// CHECK-NEXT: 1030: 4c 8b 1d c1 10 00 00 movq 4289(%rip), %r11
+// CHECK-NEXT: 1037: e9 d4 ff ff ff jmp -44 <.plt>
+// CHECK-NEXT: 103c: cc int3
+// CHECK-NEXT: 103d: cc int3
+// CHECK-NEXT: 103e: cc int3
+// CHECK-NEXT: 103f: cc int3
+// CHECK-NEXT: 1040: 4c 8b 1d b9 10 00 00 movq 4281(%rip), %r11
+// CHECK-NEXT: 1047: e9 c4 ff ff ff jmp -60 <.plt>
+// CHECK-NEXT: 104c: cc int3
+// CHECK-NEXT: 104d: cc int3
+// CHECK-NEXT: 104e: cc int3
+// CHECK-NEXT: 104f: cc int3
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: 20e0 00200000 00000000 00000000 00000000
+// CHECK-NEXT: 20f0 00000000 00000000 00000000 00000000
+// CHECK-NEXT: 2100 00000000 00000000
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/x86-64-retpoline.s b/test/ELF/x86-64-retpoline.s
new file mode 100644
index 000000000000..535f56533193
--- /dev/null
+++ b/test/ELF/x86-64-retpoline.s
@@ -0,0 +1,66 @@
+// 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 -shared %t1.o %t2.so -o %t.exe -z retpolineplt
+// RUN: llvm-objdump -d -s %t.exe | FileCheck %s
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 1010: ff 35 f2 0f 00 00 pushq 4082(%rip)
+// CHECK-NEXT: 1016: 4c 8b 1d f3 0f 00 00 movq 4083(%rip), %r11
+// CHECK-NEXT: 101d: e8 0e 00 00 00 callq 14 <.plt+0x20>
+// CHECK-NEXT: 1022: f3 90 pause
+// CHECK-NEXT: 1024: 0f ae e8 lfence
+// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12>
+// CHECK-NEXT: 1029: cc int3
+// CHECK-NEXT: 102a: cc int3
+// CHECK-NEXT: 102b: cc int3
+// CHECK-NEXT: 102c: cc int3
+// CHECK-NEXT: 102d: cc int3
+// CHECK-NEXT: 102e: cc int3
+// CHECK-NEXT: 102f: cc int3
+// CHECK-NEXT: 1030: 4c 89 1c 24 movq %r11, (%rsp)
+// CHECK-NEXT: 1034: c3 retq
+// CHECK-NEXT: 1035: cc int3
+// CHECK-NEXT: 1036: cc int3
+// CHECK-NEXT: 1037: cc int3
+// CHECK-NEXT: 1038: cc int3
+// CHECK-NEXT: 1039: cc int3
+// CHECK-NEXT: 103a: cc int3
+// CHECK-NEXT: 103b: cc int3
+// CHECK-NEXT: 103c: cc int3
+// CHECK-NEXT: 103d: cc int3
+// CHECK-NEXT: 103e: cc int3
+// CHECK-NEXT: 103f: cc int3
+// CHECK-NEXT: 1040: 4c 8b 1d d1 0f 00 00 movq 4049(%rip), %r11
+// CHECK-NEXT: 1047: e8 e4 ff ff ff callq -28 <.plt+0x20>
+// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
+// CHECK-NEXT: 1051: 68 00 00 00 00 pushq $0
+// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt>
+// CHECK-NEXT: 105b: cc int3
+// CHECK-NEXT: 105c: cc int3
+// CHECK-NEXT: 105d: cc int3
+// CHECK-NEXT: 105e: cc int3
+// CHECK-NEXT: 105f: cc int3
+// CHECK-NEXT: 1060: 4c 8b 1d b9 0f 00 00 movq 4025(%rip), %r11
+// CHECK-NEXT: 1067: e8 c4 ff ff ff callq -60 <.plt+0x20>
+// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
+// CHECK-NEXT: 1071: 68 01 00 00 00 pushq $1
+// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt>
+// CHECK-NEXT: 107b: cc int3
+// CHECK-NEXT: 107c: cc int3
+// CHECK-NEXT: 107d: cc int3
+// CHECK-NEXT: 107e: cc int3
+// CHECK-NEXT: 107f: cc int3
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: 2000 00300000 00000000 00000000 00000000
+// CHECK-NEXT: 2010 00000000 00000000 51100000 00000000
+// CHECK-NEXT: 2020 71100000 00000000
+
+.global _start
+_start:
+ jmp bar@PLT
+ jmp zed@PLT
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-fail.s b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
new file mode 100644
index 000000000000..0ae3de5ea611
--- /dev/null
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
@@ -0,0 +1,31 @@
+# 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/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: not ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+
+# An unknown prologue gives a match failure
+# CHECK: unable to adjust the enclosing function's
+
+# RUN: not ld.lld -r --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s -check-prefix=RELOCATABLE
+# RELOCATABLE: Cannot mix split-stack and non-split-stack in a relocatable link
+
+ .text
+
+ .global unknown_prologue
+ .type unknown_prologue,@function
+unknown_prologue:
+ push %rbp
+ mov %rsp,%rbp
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq non_split
+ leaveq
+ retq
+
+ .size unknown_prologue,. - unknown_prologue
+
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-silent.s b/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
new file mode 100644
index 000000000000..353eabef0de7
--- /dev/null
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
@@ -0,0 +1,32 @@
+# 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/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t 2>&1 | FileCheck %s
+
+# An unknown prologue ordinarily gives a match failure, except that this
+# object file includes a .note.GNU-no-split-stack section, which tells the
+# linker to expect such prologues, and therefore not error.
+
+# CHECK: __morestack
+
+ .text
+
+ .global unknown_prologue
+ .type unknown_prologue,@function
+unknown_prologue:
+ push %rbp
+ mov %rsp,%rbp
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq non_split
+ leaveq
+ retq
+
+ .size unknown_prologue,. - unknown_prologue
+ .section .note.GNU-split-stack,"",@progbits
+ .section .note.GNU-no-split-stack,"",@progbits
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-success.s b/test/ELF/x86-64-split-stack-prologue-adjust-success.s
new file mode 100644
index 000000000000..bad26677f3fd
--- /dev/null
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-success.s
@@ -0,0 +1,124 @@
+# 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/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t -z notext
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# Avoid duplicating the prologue for every test via macros.
+
+.macro prologue1 function_to_call
+ .global prologue1_calls_\function_to_call
+ .type prologue1_calls_\function_to_call,@function
+prologue1_calls_\function_to_call:
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ # Various and duplicate calls to ensure every code path is taken.
+ callq \function_to_call
+ callq \function_to_call
+ callq 1b
+ callq non_function_text_symbol
+ retq
+ .size prologue1_calls_\function_to_call,. - prologue1_calls_\function_to_call
+.endm
+
+.macro prologue2 function_to_call register
+ .global prologue2_calls_\function_to_call\register
+ .type prologue2_calls_\function_to_call\register,@function
+prologue2_calls_\function_to_call\register:
+ lea -0x200(%rsp),%\register
+ cmp %fs:0x70,%\register
+ jae 1f
+ callq __morestack
+ retq
+1:
+ # Various and duplicate calls to ensure every code path is taken.
+ callq \function_to_call
+ callq \function_to_call
+ callq 1b
+ callq non_function_text_symbol
+ retq
+ .size prologue2_calls_\function_to_call\register,. - prologue2_calls_\function_to_call\register
+.endm
+
+ .local foo
+foo:
+ .section .text,"ax",@progbits
+ .quad foo
+
+ .text
+
+# For split-stack code calling split-stack code, ensure prologue v1 still
+# calls plain __morestack, and that any raw bytes written to the prologue
+# make sense.
+# CHECK: prologue1_calls_split:
+# CHECK-NEXT: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%rsp
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue1 split
+
+# For split-stack code calling split-stack code, ensure prologue v2 still
+# calls plain __morestack, that any raw bytes written to the prologue
+# make sense, and that the register number is preserved.
+# CHECK: prologue2_calls_splitr10:
+# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r10
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
+# CHECK: jae{{.*}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue2 split r10
+
+# CHECK: prologue2_calls_splitr11:
+# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r11
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
+# CHECK: jae{{.*}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue2 split r11
+
+# For split-stack code calling non-split-stack code, ensure prologue v1
+# calls __morestack_non_split, and that any raw bytes written to the prologue
+# make sense.
+# CHECK: prologue1_calls_non_split:
+# CHECK-NEXT: stc{{.*$}}
+# CHECK-NEXT: nopl{{.*$}}
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue1 non_split
+
+# For split-stack code calling non-split-stack code, ensure prologue v2
+# calls __morestack_non_split, that any raw bytes written to the prologue
+# make sense, and that the register number is preserved
+# CHECK: prologue2_calls_non_splitr10:
+# CHECK-NEXT: lea{{.*$}}
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r10
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue2 non_split r10
+
+# CHECK: prologue2_calls_non_splitr11:
+# CHECK-NEXT: lea{{.*$}}
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r11
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue2 non_split r11
+# call foo@plt # for code-coverage.
+
+
+
+ .global split
+ .type split,@function
+split:
+ retq
+
+ .size split,. - split
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/x86-64-tls-ld-local.s b/test/ELF/x86-64-tls-ld-local.s
new file mode 100644
index 000000000000..6daba638367f
--- /dev/null
+++ b/test/ELF/x86-64-tls-ld-local.s
@@ -0,0 +1,29 @@
+// 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 %t.so | FileCheck %s
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT: R_X86_64_JUMP_SLOT __tls_get_addr 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+
+ data16
+ leaq bar@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
+
+ .section .tdata,"awT",@progbits
+bar:
+ .long 42
diff --git a/test/ELF/zdefs.s b/test/ELF/zdefs.s
index 93c61e14ccb6..21bec77b3bfb 100644
--- a/test/ELF/zdefs.s
+++ b/test/ELF/zdefs.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t1.so
diff --git a/test/ELF/znotext-plt-relocations-protected.s b/test/ELF/znotext-plt-relocations-protected.s
index 03d20b12e352..4fd8065a2873 100644
--- a/test/ELF/znotext-plt-relocations-protected.s
+++ b/test/ELF/znotext-plt-relocations-protected.s
@@ -2,10 +2,10 @@
# 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/znotext-plt-relocations-protected.s -o %t2.o
# RUN: ld.lld %t2.o -o %t2.so -shared
-# RUN: not ld.lld -z notext %t.o %t2.so -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld -z notext %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: cannot preempt symbol: foo
.global _start
_start:
-callq foo
+ .long foo - .
diff --git a/test/ELF/znotext-weak-undef.s b/test/ELF/znotext-weak-undef.s
index d606d872bc4f..72bb6e2d5e18 100644
--- a/test/ELF/znotext-weak-undef.s
+++ b/test/ELF/znotext-weak-undef.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: not ld.lld -z notext -shared %t.o -o %t 2>&1 | FileCheck %s
-# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
+# CHECK: relocation R_X86_64_32 cannot be used against symbol foo; recompile with -fPIC
# RUN: ld.lld -z notext %t.o -o %t
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=EXE
diff --git a/test/ELF/ztext-text-notext.s b/test/ELF/ztext.s
index 964ffe1fa6d8..1757769b29a2 100644
--- a/test/ELF/ztext-text-notext.s
+++ b/test/ELF/ztext.s
@@ -1,7 +1,8 @@
# 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/ztext-text-notext.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ztext.s -o %t2.o
# RUN: ld.lld %t2.o -o %t2.so -shared
+
# RUN: ld.lld -z notext %t.o %t2.so -o %t -shared
# RUN: llvm-readobj -dynamic-table -r %t | FileCheck %s
# RUN: ld.lld -z notext %t.o %t2.so -o %t2 -pie
@@ -9,26 +10,34 @@
# RUN: ld.lld -z notext %t.o %t2.so -o %t3
# RUN: llvm-readobj -dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s
+# RUN: not ld.lld %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+# RUN: not ld.lld -z text %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: can't create dynamic relocation
+
# If the preference is to have text relocations, don't create plt of copy relocations.
# CHECK: Relocations [
-# CHECK-NEXT: Section {{.*}} .rela.dyn {
-# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000
-# CHECK-NEXT: 0x1008 R_X86_64_64 bar 0x0
-# CHECK-NEXT: 0x1010 R_X86_64_PC64 zed 0x0
-# CHECK-NEXT: }
-# CHECK-NEXT: ]
+# CHECK-NEXT: Section {{.*}} .rela.dyn {
+# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000
+# CHECK-NEXT: 0x1008 R_X86_64_64 bar 0x0
+# CHECK-NEXT: 0x1010 R_X86_64_PC64 zed 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
# CHECK: DynamicSection [
-# CHECK: 0x0000000000000016 TEXTREL 0x0
+# CHECK: FLAGS TEXTREL
+# CHECK: TEXTREL 0x0
# STATIC: Relocations [
-# STATIC-NEXT: Section {{.*}} .rela.dyn {
-# STATIC-NEXT: 0x201008 R_X86_64_64 bar 0x0
-# STATIC-NEXT: 0x201010 R_X86_64_PC64 zed 0x0
-# STATIC-NEXT: }
-# STATIC-NEXT: ]
+# STATIC-NEXT: Section {{.*}} .rela.dyn {
+# STATIC-NEXT: 0x201008 R_X86_64_64 bar 0x0
+# STATIC-NEXT: 0x201010 R_X86_64_PC64 zed 0x0
+# STATIC-NEXT: }
+# STATIC-NEXT: ]
+
# STATIC: DynamicSection [
-# STATIC: 0x0000000000000016 TEXTREL 0x0
+# STATIC: FLAGS TEXTREL
+# STATIC: TEXTREL 0x0
foo:
.quad foo
diff --git a/test/MinGW/driver.test b/test/MinGW/driver.test
index 8bf70a9b24fa..35d3ccf97ccd 100644
--- a/test/MinGW/driver.test
+++ b/test/MinGW/driver.test
@@ -90,6 +90,15 @@ RUN: ld.lld -### -m i386pep foo.o -s | FileCheck -check-prefix STRIP %s
RUN: ld.lld -### -m i386pep foo.o --strip-all | FileCheck -check-prefix STRIP %s
STRIP-NOT: -debug:dwarf
+RUN: ld.lld -### -m i386pep foo.o -S | FileCheck -check-prefix STRIP-DEBUG %s
+RUN: ld.lld -### -m i386pep foo.o --strip-debug | FileCheck -check-prefix STRIP-DEBUG %s
+STRIP-DEBUG: -debug:symtab
+STRIP-DEBUG-NOT: -debug:dwarf
+
+RUN: ld.lld -### -m i386pep foo.o -pdb out.pdb | FileCheck -check-prefix PDB %s
+PDB: -debug -pdb:out.pdb
+PDB-NOT: -debug:dwarf
+
RUN: ld.lld -### -m i386pep foo.o --large-address-aware | FileCheck -check-prefix LARGE-ADDRESS-AWARE %s
LARGE-ADDRESS-AWARE: -largeaddressaware
@@ -124,3 +133,15 @@ ICF-NONE: -opt:noicf
RUN: ld.lld -### -m i386pep foo.o --icf=all | FileCheck -check-prefix ICF %s
RUN: ld.lld -### -m i386pep foo.o -icf=all | FileCheck -check-prefix ICF %s
ICF: -opt:icf
+
+RUN: ld.lld -### -m i386pep --start-group foo.o --end-group
+
+RUN: ld.lld -### foo.o -m i386pe -shared --kill-at | FileCheck -check-prefix=KILL-AT %s
+RUN: ld.lld -### foo.o -m i386pe -shared -kill-at | FileCheck -check-prefix=KILL-AT %s
+KILL-AT: -kill-at
+
+RUN: ld.lld -### foo.o -m i386pep -Map bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep --Map bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep -Map=bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep --Map=bar.map | FileCheck -check-prefix=MAP %s
+MAP: -lldmap:bar.map
diff --git a/test/darwin/cmdline-lto_library.objtxt b/test/darwin/cmdline-lto_library.objtxt
new file mode 100644
index 000000000000..6b91235560b4
--- /dev/null
+++ b/test/darwin/cmdline-lto_library.objtxt
@@ -0,0 +1,11 @@
+# RUN: ld64.lld -arch x86_64 -lto_library %t -print-atoms -r %s 2>&1 | FileCheck %s
+#
+# Test that the -lto_library option does not result in an error.
+#
+
+# CHECK-NOT: -lto_library
+
+--- !native
+defined-atoms:
+ - name: _foo
+...
diff --git a/test/darwin/cmdline-objc_gc.objtxt b/test/darwin/cmdline-objc_gc.objtxt
index b5225a1d184e..4fff925234a0 100644
--- a/test/darwin/cmdline-objc_gc.objtxt
+++ b/test/darwin/cmdline-objc_gc.objtxt
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s
#
# Test that the -objc_gc is rejected.
#
diff --git a/test/darwin/cmdline-objc_gc_compaction.objtxt b/test/darwin/cmdline-objc_gc_compaction.objtxt
index acf7183d95eb..7cb7e8277368 100644
--- a/test/darwin/cmdline-objc_gc_compaction.objtxt
+++ b/test/darwin/cmdline-objc_gc_compaction.objtxt
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s
#
# Test that the -objc_gc_compaction is rejected.
#
diff --git a/test/darwin/cmdline-objc_gc_only.objtxt b/test/darwin/cmdline-objc_gc_only.objtxt
index db1cef94ea59..eb9f13145915 100644
--- a/test/darwin/cmdline-objc_gc_only.objtxt
+++ b/test/darwin/cmdline-objc_gc_only.objtxt
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s
#
# Test that the -objc_gc_only is rejected.
#
diff --git a/test/darwin/native-and-mach-o.objtxt b/test/darwin/native-and-mach-o.objtxt
index 1dee76d6d8cd..b4c0a4066a19 100644
--- a/test/darwin/native-and-mach-o.objtxt
+++ b/test/darwin/native-and-mach-o.objtxt
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: ld64.lld -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
diff --git a/test/lit.cfg.py b/test/lit.cfg.py
index ae0dd187c607..26880383d354 100644
--- a/test/lit.cfg.py
+++ b/test/lit.cfg.py
@@ -39,8 +39,9 @@ llvm_config.use_default_substitutions()
llvm_config.use_lld()
tool_patterns = [
- 'llc', 'llvm-as', 'llvm-mc', 'llvm-nm',
- 'llvm-objdump', 'llvm-pdbutil', 'llvm-readobj', 'obj2yaml', 'yaml2obj']
+ 'llc', 'llvm-as', 'llvm-mc', 'llvm-nm', 'llvm-objdump', 'llvm-pdbutil',
+ 'llvm-dwarfdump', 'llvm-readelf', 'llvm-readobj', 'obj2yaml', 'yaml2obj',
+ 'opt', 'llvm-dis']
llvm_config.add_tool_substitutions(tool_patterns)
@@ -64,6 +65,7 @@ llvm_config.feature_config(
'AMDGPU': 'amdgpu',
'ARM': 'arm',
'AVR': 'avr',
+ 'Hexagon': 'hexagon',
'Mips': 'mips',
'PowerPC': 'ppc',
'Sparc': 'sparc',
@@ -71,8 +73,9 @@ llvm_config.feature_config(
'X86': 'x86'})
])
-# Set a fake constant version so that we get consitent output.
+# Set a fake constant version so that we get consistent output.
config.environment['LLD_VERSION'] = 'LLD 1.0'
+config.environment['LLD_IN_TEST'] = '1'
# Indirectly check if the mt.exe Microsoft utility exists by searching for
# cvtres, which always accompanies it. Alternatively, check if we can use
@@ -84,6 +87,9 @@ if (lit.util.which('cvtres', config.environment['PATH'])) or \
if (config.llvm_libxml2_enabled == '1'):
config.available_features.add('libxml2')
+if config.have_dia_sdk:
+ config.available_features.add("diasdk")
+
tar_executable = lit.util.which('tar', config.environment['PATH'])
if tar_executable:
tar_version = subprocess.Popen(
diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in
index 50593f7d01bd..764ab83fbcf2 100644
--- a/test/lit.site.cfg.py.in
+++ b/test/lit.site.cfg.py.in
@@ -1,5 +1,8 @@
@LIT_SITE_CFG_IN_HEADER@
+import lit.util
+
+config.have_dia_sdk = lit.util.pythonize_bool("@LLVM_ENABLE_DIA_SDK@")
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
diff --git a/test/mach-o/Inputs/swift-version-1.yaml b/test/mach-o/Inputs/swift-version-1.yaml
index 1337d7a13245..b555e4782843 100644
--- a/test/mach-o/Inputs/swift-version-1.yaml
+++ b/test/mach-o/Inputs/swift-version-1.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/Inputs/wrong-arch-error.yaml b/test/mach-o/Inputs/wrong-arch-error.yaml
index 304c872375e4..39ef3c1a9500 100644
--- a/test/mach-o/Inputs/wrong-arch-error.yaml
+++ b/test/mach-o/Inputs/wrong-arch-error.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s 2> %t.err
+# RUN: not ld64.lld -arch x86_64 -r %s 2> %t.err
# RUN: FileCheck %s < %t.err
--- !mach-o
diff --git a/test/mach-o/PIE.yaml b/test/mach-o/PIE.yaml
index 24f8773cbd23..e7c15fbc1f14 100644
--- a/test/mach-o/PIE.yaml
+++ b/test/mach-o/PIE.yaml
@@ -1,12 +1,12 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: ld64.lld -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: ld64.lld -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: ld64.lld -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
diff --git a/test/mach-o/align_text.yaml b/test/mach-o/align_text.yaml
index 66b5afb5ff30..d633a8eb95df 100644
--- a/test/mach-o/align_text.yaml
+++ b/test/mach-o/align_text.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s
#
# Test that alignment info round trips through -r
#
diff --git a/test/mach-o/arm-interworking-movw.yaml b/test/mach-o/arm-interworking-movw.yaml
index b555112dde82..ade459c8c896 100644
--- a/test/mach-o/arm-interworking-movw.yaml
+++ b/test/mach-o/arm-interworking-movw.yaml
@@ -1,6 +1,6 @@
# 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: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch armv7 -dylib -print_atoms %t -o %t2 \
# RUN: %p/Inputs/armv7/libSystem.yaml -sectalign __TEXT __text 0x1000 | FileCheck %s
# RUN: llvm-objdump -d -macho -no-symbolic-operands %t2 | FileCheck -check-prefix=CODE %s
#
diff --git a/test/mach-o/arm-interworking.yaml b/test/mach-o/arm-interworking.yaml
index 3988a1958458..a41355fcb955 100644
--- a/test/mach-o/arm-interworking.yaml
+++ b/test/mach-o/arm-interworking.yaml
@@ -1,6 +1,6 @@
-# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s \
+# RUN: ld64.lld -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: && ld64.lld -arch armv7 -dylib -print_atoms \
# RUN: %p/Inputs/armv7/libSystem.yaml %t -o %t2 | FileCheck %s \
# RUN: && llvm-readobj -s -sd %t2 | FileCheck -check-prefix=CODE %s
#
diff --git a/test/mach-o/arm-shims.yaml b/test/mach-o/arm-shims.yaml
index 1b54de4f05aa..37e266e6218e 100644
--- a/test/mach-o/arm-shims.yaml
+++ b/test/mach-o/arm-shims.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/arm-shims.yaml \
+# RUN: ld64.lld -arch armv7 %s %p/Inputs/arm-shims.yaml \
# RUN: -dylib %p/Inputs/armv7/libSystem.yaml -o %t
# RUN: llvm-readobj -s -sd %t | FileCheck %s
#
diff --git a/test/mach-o/arm-subsections-via-symbols.yaml b/test/mach-o/arm-subsections-via-symbols.yaml
index 23c2847e6c77..63e23da9f71e 100644
--- a/test/mach-o/arm-subsections-via-symbols.yaml
+++ b/test/mach-o/arm-subsections-via-symbols.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s
+# RUN: ld64.lld -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
diff --git a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml
index ee8686cabb62..b0c86f92a98f 100644
--- a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml
+++ b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml
@@ -1,5 +1,5 @@
-# RUN: lld -flavor darwin -arch arm64 -r %s -o %t
-# RUN: lld -flavor darwin -arch arm64 -r %t -o %t2
+# RUN: ld64.lld -arch arm64 -r %s -o %t
+# RUN: ld64.lld -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
diff --git a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml
index d238097f9695..01a3e1bb6fc6 100644
--- a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml
+++ b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch arm64 %s -r \
+# RUN: not ld64.lld -arch arm64 %s -r \
# RUN: 2> %t.err
# RUN: FileCheck %s < %t.err
diff --git a/test/mach-o/arm64-section-order.yaml b/test/mach-o/arm64-section-order.yaml
index 50d684668a52..0dbf52c2546c 100644
--- a/test/mach-o/arm64-section-order.yaml
+++ b/test/mach-o/arm64-section-order.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch arm64 -r -print_atoms %s -o %t
+# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2
# RUN: llvm-objdump -section-headers %t | FileCheck %s
# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
diff --git a/test/mach-o/bind-opcodes.yaml b/test/mach-o/bind-opcodes.yaml
index ad8cd169a85c..294171755759 100644
--- a/test/mach-o/bind-opcodes.yaml
+++ b/test/mach-o/bind-opcodes.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
+# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
# RUN: obj2yaml %t | FileCheck %s
#
diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml
index 433dffcf62d9..2bc7e7c5c2f6 100644
--- a/test/mach-o/cstring-sections.yaml
+++ b/test/mach-o/cstring-sections.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
#
# Test -keep_private_externs in -r mode.
#
diff --git a/test/mach-o/data-in-code-load-command.yaml b/test/mach-o/data-in-code-load-command.yaml
index 0c84bd4d7452..32c5d9220c51 100644
--- a/test/mach-o/data-in-code-load-command.yaml
+++ b/test/mach-o/data-in-code-load-command.yaml
@@ -1,11 +1,11 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/libSystem.yaml -r -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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
diff --git a/test/mach-o/data-only-dylib.yaml b/test/mach-o/data-only-dylib.yaml
index 541e02f61ef9..a163609225b2 100644
--- a/test/mach-o/data-only-dylib.yaml
+++ b/test/mach-o/data-only-dylib.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -dylib %s -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm %t | FileCheck %s
#
# Test that a data-only dylib can be built.
diff --git a/test/mach-o/dead-strip-globals.yaml b/test/mach-o/dead-strip-globals.yaml
index 45d919db3aa5..42edd19f62ce 100644
--- a/test/mach-o/dead-strip-globals.yaml
+++ b/test/mach-o/dead-strip-globals.yaml
@@ -1,8 +1,8 @@
-# RUN: lld -flavor darwin -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/x86_64/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/x86_64/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/x86_64/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s
+# RUN: ld64.lld -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: ld64.lld -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: ld64.lld -arch x86_64 -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s
-# RUN: lld -flavor darwin -arch x86_64 -r %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t3.o
+# RUN: ld64.lld -arch x86_64 -r %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t3.o
# RUN: llvm-nm -m %t3.o | FileCheck -check-prefix=RELOCATABLE_SYMBOLS %s
#
diff --git a/test/mach-o/debug-syms.yaml b/test/mach-o/debug-syms.yaml
index 28428724ffe7..cd61c879b0b5 100644
--- a/test/mach-o/debug-syms.yaml
+++ b/test/mach-o/debug-syms.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -o %t %s -dylib %p/Inputs/x86_64/libSystem.yaml && \
+# RUN: ld64.lld -arch x86_64 -o %t %s -dylib %p/Inputs/x86_64/libSystem.yaml && \
# RUN: llvm-nm -no-sort -debug-syms %t | FileCheck %s
# CHECK: 0000000000000000 - 00 0000 SO /Users/lhames/Projects/lld/lld-svn-tot/scratch/
diff --git a/test/mach-o/demangle.yaml b/test/mach-o/demangle.yaml
index 333a59eaa528..cdd5e8adb621 100644
--- a/test/mach-o/demangle.yaml
+++ b/test/mach-o/demangle.yaml
@@ -1,10 +1,10 @@
# REQUIRES: system-linker-mach-o
#
-# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \
# RUN: -dylib -o %t %p/Inputs/x86_64/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: not ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \
# RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml -demangle 2> %t.err2
# RUN: FileCheck %s --check-prefix=DCHECK < %t.err2
#
diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml
index 2ec59b8afebb..34d688541b91 100644
--- a/test/mach-o/dependency_info.yaml
+++ b/test/mach-o/dependency_info.yaml
@@ -1,6 +1,6 @@
# Test -dependency_info option
#
-# RUN: lld -flavor darwin -arch x86_64 -test_file_usage \
+# RUN: ld64.lld -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 \
@@ -9,7 +9,7 @@
# RUN: -F/Custom/Frameworks \
# RUN: -framework Bar \
# RUN: -framework Foo
-# RUN: %python %p/Inputs/DependencyDump.py %t.info | FileCheck %s
+# RUN: '%python' %p/Inputs/DependencyDump.py %t.info | FileCheck %s
# CHECK: linker-vers: lld
diff --git a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml
index 70f76b5246f1..3afdc2be1fb7 100644
--- a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml
+++ b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -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
diff --git a/test/mach-o/dso_handle.yaml b/test/mach-o/dso_handle.yaml
index 0796c2ee566d..6c74371a0b3f 100644
--- a/test/mach-o/dso_handle.yaml
+++ b/test/mach-o/dso_handle.yaml
@@ -1,13 +1,13 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -o %t1
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -o %t1
# RUN: llvm-nm -m -n %t1 | FileCheck %s
#
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t2
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t2
# RUN: llvm-nm -m -n %t2 | FileCheck %s
#
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dylib -o %t3
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dylib -o %t3
# RUN: llvm-nm -m -n %t3 | FileCheck %s
#
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -bundle -o %t4
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/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
diff --git a/test/mach-o/dylib-install-names.yaml b/test/mach-o/dylib-install-names.yaml
index af00adfd5908..10209ba12abb 100644
--- a/test/mach-o/dylib-install-names.yaml
+++ b/test/mach-o/dylib-install-names.yaml
@@ -1,23 +1,23 @@
# Check we accept -install_name correctly:
-# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN: ld64.lld -arch x86_64 -install_name libwibble.dylib -dylib \
# RUN: -compatibility_version 2.0 -current_version 5.3 \
# RUN: %p/Inputs/x86_64/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: ld64.lld -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \
# RUN: %p/Inputs/x86_64/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: ld64.lld -arch x86_64 -dylib %s -o libwibble.dylib \
# RUN: -compatibility_version 2.0 -current_version 5.3 \
# RUN: %p/Inputs/x86_64/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: ld64.lld -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/x86_64/libSystem.yaml
# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
diff --git a/test/mach-o/eh-frame-relocs-arm64.yaml b/test/mach-o/eh-frame-relocs-arm64.yaml
index e23dd7c48ed9..a71f79e692ff 100644
--- a/test/mach-o/eh-frame-relocs-arm64.yaml
+++ b/test/mach-o/eh-frame-relocs-arm64.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -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
diff --git a/test/mach-o/error-simulator-vs-macosx.yaml b/test/mach-o/error-simulator-vs-macosx.yaml
index bd62db39fccb..609eb3be43ab 100644
--- a/test/mach-o/error-simulator-vs-macosx.yaml
+++ b/test/mach-o/error-simulator-vs-macosx.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch i386 -macosx_version_min 10.8 %s %p/Inputs/hello-world-x86.yaml -o %t && llvm-nm -m %t | FileCheck %s
+# RUN: not ld64.lld -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.
#
diff --git a/test/mach-o/exe-offsets.yaml b/test/mach-o/exe-offsets.yaml
index 6a0e35cedb46..31b778286bb2 100644
--- a/test/mach-o/exe-offsets.yaml
+++ b/test/mach-o/exe-offsets.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-readobj -sections %t | FileCheck %s
# Make sure data gets put at offset
diff --git a/test/mach-o/exe-segment-overlap.yaml b/test/mach-o/exe-segment-overlap.yaml
index 47f0214efd6c..b2ded264f4b0 100644
--- a/test/mach-o/exe-segment-overlap.yaml
+++ b/test/mach-o/exe-segment-overlap.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
--- !native
diff --git a/test/mach-o/executable-exports.yaml b/test/mach-o/executable-exports.yaml
index f16cbd5ce935..46ba9ca6d1d4 100644
--- a/test/mach-o/executable-exports.yaml
+++ b/test/mach-o/executable-exports.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 \
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 \
# RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t && \
# RUN: llvm-objdump -exports-trie %t | FileCheck %s
#
diff --git a/test/mach-o/export-trie-order.yaml b/test/mach-o/export-trie-order.yaml
index a11c998bdb06..53ee8afae660 100644
--- a/test/mach-o/export-trie-order.yaml
+++ b/test/mach-o/export-trie-order.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
# RUN: llvm-objdump -exports-trie %t | FileCheck %s
#
# Test that the export trie is emitted in order.
diff --git a/test/mach-o/exported_symbols_list-dylib.yaml b/test/mach-o/exported_symbols_list-dylib.yaml
index f9de5fe976e2..860d26848fea 100644
--- a/test/mach-o/exported_symbols_list-dylib.yaml
+++ b/test/mach-o/exported_symbols_list-dylib.yaml
@@ -1,19 +1,19 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/x86_64/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: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/x86_64/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: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/x86_64/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: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/x86_64/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
diff --git a/test/mach-o/exported_symbols_list-obj.yaml b/test/mach-o/exported_symbols_list-obj.yaml
index 31b325c7387b..cc0f75cdc2f7 100644
--- a/test/mach-o/exported_symbols_list-obj.yaml
+++ b/test/mach-o/exported_symbols_list-obj.yaml
@@ -1,11 +1,11 @@
-# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -exported_symbol _bar \
+# RUN: ld64.lld -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: ld64.lld -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: not ld64.lld -arch x86_64 -r %s -o %t3 \
# RUN: -exported_symbol _foo 2> %t4
# Test -exported_symbols_list properly changes visibility in -r mode.
diff --git a/test/mach-o/exported_symbols_list-undef.yaml b/test/mach-o/exported_symbols_list-undef.yaml
index 377282f2a7c4..6aca11b61d2a 100644
--- a/test/mach-o/exported_symbols_list-undef.yaml
+++ b/test/mach-o/exported_symbols_list-undef.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2
#
# Test -exported_symbol fails if exported symbol not found.
diff --git a/test/mach-o/fat-archive.yaml b/test/mach-o/fat-archive.yaml
index 979ede30a72a..a36c25bca7e1 100644
--- a/test/mach-o/fat-archive.yaml
+++ b/test/mach-o/fat-archive.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t \
# RUN: -L %p/Inputs -lfoo %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
diff --git a/test/mach-o/filelist.yaml b/test/mach-o/filelist.yaml
index 28bfeb74d02b..85c04f570722 100644
--- a/test/mach-o/filelist.yaml
+++ b/test/mach-o/filelist.yaml
@@ -1,11 +1,11 @@
-# RUN: lld -flavor darwin -test_file_usage \
+# RUN: ld64.lld -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: ld64.lld -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 \
diff --git a/test/mach-o/flat_namespace_undef_error.yaml b/test/mach-o/flat_namespace_undef_error.yaml
index af84608aa5ff..6d4c38ec1cca 100644
--- a/test/mach-o/flat_namespace_undef_error.yaml
+++ b/test/mach-o/flat_namespace_undef_error.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s
--- !native
defined-atoms:
diff --git a/test/mach-o/flat_namespace_undef_suppress.yaml b/test/mach-o/flat_namespace_undef_suppress.yaml
index e68fd998c1b2..8fdcfb9c30db 100644
--- a/test/mach-o/flat_namespace_undef_suppress.yaml
+++ b/test/mach-o/flat_namespace_undef_suppress.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml
#
# Sanity check '-flat_namespace -undefined suppress'.
# This should pass without error, even though '_bar' is undefined.
diff --git a/test/mach-o/force_load-dylib.yaml b/test/mach-o/force_load-dylib.yaml
index d32c63eab5c1..4e27b0220c34 100644
--- a/test/mach-o/force_load-dylib.yaml
+++ b/test/mach-o/force_load-dylib.yaml
@@ -1,6 +1,6 @@
-# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN: ld64.lld -arch x86_64 -dylib %p/Inputs/bar.yaml \
# RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib
-# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \
+# RUN: ld64.lld -arch x86_64 -dylib %s -all_load %t1.dylib \
# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t
# RUN: llvm-nm -m %t | FileCheck %s
#
diff --git a/test/mach-o/force_load-x86_64.yaml b/test/mach-o/force_load-x86_64.yaml
index 5b37f4764e68..7ea2a7851833 100644
--- a/test/mach-o/force_load-x86_64.yaml
+++ b/test/mach-o/force_load-x86_64.yaml
@@ -1,8 +1,8 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/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/x86_64/libSystem.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/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
#
diff --git a/test/mach-o/framework-user-paths.yaml b/test/mach-o/framework-user-paths.yaml
index 80d6e3b5868b..bb4d82250723 100644
--- a/test/mach-o/framework-user-paths.yaml
+++ b/test/mach-o/framework-user-paths.yaml
@@ -5,7 +5,7 @@
# /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: ld64.lld -arch x86_64 -r -test_file_usage -v \
# RUN: -path_exists myFrameworks \
# RUN: -path_exists myFrameworks/my.framework/my \
# RUN: -path_exists /opt/Frameworks \
diff --git a/test/mach-o/function-starts-load-command.yaml b/test/mach-o/function-starts-load-command.yaml
index 5cfe9dcac67d..fadc731e40e1 100644
--- a/test/mach-o/function-starts-load-command.yaml
+++ b/test/mach-o/function-starts-load-command.yaml
@@ -1,8 +1,8 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/gcc_except_tab-got-arm64.yaml b/test/mach-o/gcc_except_tab-got-arm64.yaml
index 47b174d6cf29..ed517c8bd6b1 100644
--- a/test/mach-o/gcc_except_tab-got-arm64.yaml
+++ b/test/mach-o/gcc_except_tab-got-arm64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch arm64 %s \
+# RUN: ld64.lld -arch arm64 %s \
# RUN: -dylib %p/Inputs/arm64/libSystem.yaml -o %t
# RUN: llvm-objdump -section-headers %t | FileCheck %s
diff --git a/test/mach-o/got-order.yaml b/test/mach-o/got-order.yaml
index 2e8579cad6d2..f7984741e519 100644
--- a/test/mach-o/got-order.yaml
+++ b/test/mach-o/got-order.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/got-order.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/got-order.yaml \
# RUN: %p/Inputs/got-order2.yaml -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-objdump -bind %t | FileCheck %s
#
diff --git a/test/mach-o/hello-world-arm64.yaml b/test/mach-o/hello-world-arm64.yaml
index 138af5940997..b2e73662c13f 100644
--- a/test/mach-o/hello-world-arm64.yaml
+++ b/test/mach-o/hello-world-arm64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
+# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
# RUN: llvm-nm -m -n %t | FileCheck %s
# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-PRIVATE-HEADER
#
diff --git a/test/mach-o/hello-world-armv6.yaml b/test/mach-o/hello-world-armv6.yaml
index 8a9edeeddbac..b14b775baaf7 100644
--- a/test/mach-o/hello-world-armv6.yaml
+++ b/test/mach-o/hello-world-armv6.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch armv6 %s %p/Inputs/hello-world-armv6.yaml -o %t
+# RUN: ld64.lld -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
diff --git a/test/mach-o/hello-world-armv7.yaml b/test/mach-o/hello-world-armv7.yaml
index 1871d68f6b92..28a96af0a882 100644
--- a/test/mach-o/hello-world-armv7.yaml
+++ b/test/mach-o/hello-world-armv7.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/hello-world-armv7.yaml -o %t
+# RUN: ld64.lld -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
diff --git a/test/mach-o/hello-world-x86.yaml b/test/mach-o/hello-world-x86.yaml
index 779b6811e080..7a0cfdc909f0 100644
--- a/test/mach-o/hello-world-x86.yaml
+++ b/test/mach-o/hello-world-x86.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: ld64.lld -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
diff --git a/test/mach-o/hello-world-x86_64.yaml b/test/mach-o/hello-world-x86_64.yaml
index 8803c4476c39..9df969d6baf7 100644
--- a/test/mach-o/hello-world-x86_64.yaml
+++ b/test/mach-o/hello-world-x86_64.yaml
@@ -1,8 +1,8 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \
+# RUN: ld64.lld -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: ld64.lld -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \
# RUN: -dead_strip -o %t2
# RUN: llvm-nm -m -n %t2 | FileCheck %s
#
diff --git a/test/mach-o/image-base.yaml b/test/mach-o/image-base.yaml
index aa78fea1c338..f0eb68096604 100644
--- a/test/mach-o/image-base.yaml
+++ b/test/mach-o/image-base.yaml
@@ -1,10 +1,10 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/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: not ld64.lld -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: not ld64.lld -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: not ld64.lld -arch x86_64 -image_base hithere %s >/dev/null 2> %t
# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
--- !native
diff --git a/test/mach-o/infer-arch.yaml b/test/mach-o/infer-arch.yaml
index c09c94dd1b70..2dbf124ee4e6 100644
--- a/test/mach-o/infer-arch.yaml
+++ b/test/mach-o/infer-arch.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch i386 -macosx_version_min 10.8 %s -r -o %t \
+# RUN: && ld64.lld -r %t -o %t2 -print_atoms | FileCheck %s
#
# Test linker can detect architecture without -arch option.
#
diff --git a/test/mach-o/interposing-section.yaml b/test/mach-o/interposing-section.yaml
index ec4eaa3f70ad..7b45f8a4d834 100644
--- a/test/mach-o/interposing-section.yaml
+++ b/test/mach-o/interposing-section.yaml
@@ -1,8 +1,8 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/interposing-section.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/interposing-section.yaml \
# RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-objdump -private-headers %t | FileCheck %s
#
-# RUN: lld -flavor darwin -arch x86_64 %s -r -o %t1
+# RUN: ld64.lld -arch x86_64 %s -r -o %t1
# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
#
# Test that interposing section is preserved by linker.
diff --git a/test/mach-o/keep_private_externs.yaml b/test/mach-o/keep_private_externs.yaml
index e7adf180fc7b..fdee3d4bf043 100644
--- a/test/mach-o/keep_private_externs.yaml
+++ b/test/mach-o/keep_private_externs.yaml
@@ -1,7 +1,7 @@
-# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t \
+# RUN: ld64.lld -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: ld64.lld -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.
diff --git a/test/mach-o/lazy-bind-x86_64.yaml b/test/mach-o/lazy-bind-x86_64.yaml
index 1322719e5f65..37b8c31a9552 100644
--- a/test/mach-o/lazy-bind-x86_64.yaml
+++ b/test/mach-o/lazy-bind-x86_64.yaml
@@ -1,6 +1,6 @@
# REQUIRES: x86
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: ld64.lld -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/x86_64/libSystem.yaml
diff --git a/test/mach-o/lc_segment_filesize.yaml b/test/mach-o/lc_segment_filesize.yaml
index 4413c7698767..71184c230842 100644
--- a/test/mach-o/lc_segment_filesize.yaml
+++ b/test/mach-o/lc_segment_filesize.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -o %t %s && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -o %t %s && llvm-objdump -private-headers %t | FileCheck %s
# CHECK: filesize 19
diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml
index 5005f016857f..68998e03f4f2 100644
--- a/test/mach-o/lib-search-paths.yaml
+++ b/test/mach-o/lib-search-paths.yaml
@@ -1,4 +1,4 @@
-# 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
+# RUN: ld64.lld -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1 | FileCheck %s
--- !native
undefined-atoms:
diff --git a/test/mach-o/library-order.yaml b/test/mach-o/library-order.yaml
index b53232dd398f..6e091fb9aa83 100644
--- a/test/mach-o/library-order.yaml
+++ b/test/mach-o/library-order.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
+# RUN: ld64.lld -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
# RUN: %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
diff --git a/test/mach-o/library-rescan.yaml b/test/mach-o/library-rescan.yaml
index 99c7b88c7e34..a09f35259e44 100644
--- a/test/mach-o/library-rescan.yaml
+++ b/test/mach-o/library-rescan.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
+# RUN: ld64.lld -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
# RUN: %s -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
diff --git a/test/mach-o/libresolve-bizarre-root-override.yaml b/test/mach-o/libresolve-bizarre-root-override.yaml
index c65ca319432d..1c346808022c 100644
--- a/test/mach-o/libresolve-bizarre-root-override.yaml
+++ b/test/mach-o/libresolve-bizarre-root-override.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -test_file_usage -v \
+# RUN: not ld64.lld -test_file_usage -v \
# RUN: -path_exists /usr/lib \
# RUN: -path_exists /Applications/MySDK/usr/local/lib \
# RUN: -path_exists /Applications/MySDK/usr/lib \
diff --git a/test/mach-o/libresolve-multiple-syslibroots.yaml b/test/mach-o/libresolve-multiple-syslibroots.yaml
index 0b63eb64e7a9..bc8e96462c2f 100644
--- a/test/mach-o/libresolve-multiple-syslibroots.yaml
+++ b/test/mach-o/libresolve-multiple-syslibroots.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/libresolve-one-syslibroot.yaml b/test/mach-o/libresolve-one-syslibroot.yaml
index f9042fcfada2..8e28ab4d302a 100644
--- a/test/mach-o/libresolve-one-syslibroot.yaml
+++ b/test/mach-o/libresolve-one-syslibroot.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/libresolve-simple.yaml b/test/mach-o/libresolve-simple.yaml
index ffb045fa3e3c..965099122d44 100644
--- a/test/mach-o/libresolve-simple.yaml
+++ b/test/mach-o/libresolve-simple.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/libresolve-user-paths.yaml b/test/mach-o/libresolve-user-paths.yaml
index 9fe885671686..b50703d821d6 100644
--- a/test/mach-o/libresolve-user-paths.yaml
+++ b/test/mach-o/libresolve-user-paths.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \
# RUN: -path_exists hasFoo \
# RUN: -path_exists hasFoo/libFoo.dylib \
# RUN: -path_exists /hasBar \
diff --git a/test/mach-o/libresolve-z.yaml b/test/mach-o/libresolve-z.yaml
index 1df7eceac1e4..509f80b525dc 100644
--- a/test/mach-o/libresolve-z.yaml
+++ b/test/mach-o/libresolve-z.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/mach_header-cpusubtype.yaml b/test/mach-o/mach_header-cpusubtype.yaml
index fa9024f999db..95d4627cf99f 100644
--- a/test/mach-o/mach_header-cpusubtype.yaml
+++ b/test/mach-o/mach_header-cpusubtype.yaml
@@ -1,6 +1,6 @@
-# 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
+# RUN: ld64.lld -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: ld64.lld -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: ld64.lld -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
diff --git a/test/mach-o/mh_bundle_header.yaml b/test/mach-o/mh_bundle_header.yaml
index d1b7d9ab2143..33944a4be882 100644
--- a/test/mach-o/mh_bundle_header.yaml
+++ b/test/mach-o/mh_bundle_header.yaml
@@ -1,5 +1,5 @@
-# RUN: lld -flavor darwin -arch x86_64 %s -bundle -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
-# RUN: lld -flavor darwin -arch x86_64 %s -bundle -dead_strip -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 %s -bundle -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 %s -bundle -dead_strip -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
#
# Test that __mh_bundle_header symbol is available for bundles
#
diff --git a/test/mach-o/mh_dylib_header.yaml b/test/mach-o/mh_dylib_header.yaml
index 8222063ee161..27d34c44ad18 100644
--- a/test/mach-o/mh_dylib_header.yaml
+++ b/test/mach-o/mh_dylib_header.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s -dylib -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 %s -dylib -o %t %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
# Test that __mh_dylib_header symbol is available for dylibs
diff --git a/test/mach-o/objc-category-list-atom.yaml b/test/mach-o/objc-category-list-atom.yaml
index 93974a646e06..4e6cd847840e 100644
--- a/test/mach-o/objc-category-list-atom.yaml
+++ b/test/mach-o/objc-category-list-atom.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
--- !mach-o
diff --git a/test/mach-o/objc-image-info-host-vs-simulator.yaml b/test/mach-o/objc-image-info-host-vs-simulator.yaml
index f836a7423271..38f251beb4ac 100644
--- a/test/mach-o/objc-image-info-host-vs-simulator.yaml
+++ b/test/mach-o/objc-image-info-host-vs-simulator.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -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.
diff --git a/test/mach-o/objc-image-info-invalid-size.yaml b/test/mach-o/objc-image-info-invalid-size.yaml
index 47fce886f2cc..a67f61a2fcca 100644
--- a/test/mach-o/objc-image-info-invalid-size.yaml
+++ b/test/mach-o/objc-image-info-invalid-size.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/objc-image-info-invalid-version.yaml b/test/mach-o/objc-image-info-invalid-version.yaml
index 04d62e9fb789..845ac56f12b1 100644
--- a/test/mach-o/objc-image-info-invalid-version.yaml
+++ b/test/mach-o/objc-image-info-invalid-version.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/objc-image-info-mismatched-swift-version.yaml b/test/mach-o/objc-image-info-mismatched-swift-version.yaml
index efb7c319285b..238991782611 100644
--- a/test/mach-o/objc-image-info-mismatched-swift-version.yaml
+++ b/test/mach-o/objc-image-info-mismatched-swift-version.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/objc-image-info-pass-output.yaml b/test/mach-o/objc-image-info-pass-output.yaml
index 7fc95a846324..c81e6bce1531 100644
--- a/test/mach-o/objc-image-info-pass-output.yaml
+++ b/test/mach-o/objc-image-info-pass-output.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: ld64.lld -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.
diff --git a/test/mach-o/objc-image-info-simulator-vs-host.yaml b/test/mach-o/objc-image-info-simulator-vs-host.yaml
index c4f9bd58f968..4fda686c9027 100644
--- a/test/mach-o/objc-image-info-simulator-vs-host.yaml
+++ b/test/mach-o/objc-image-info-simulator-vs-host.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -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.
diff --git a/test/mach-o/objc-image-info-unsupported-gc.yaml b/test/mach-o/objc-image-info-unsupported-gc.yaml
index 9f98369a39cb..1014b4acf7cc 100644
--- a/test/mach-o/objc-image-info-unsupported-gc.yaml
+++ b/test/mach-o/objc-image-info-unsupported-gc.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/objc_export_list.yaml b/test/mach-o/objc_export_list.yaml
index a2fcfa22ec07..55dff8d3e856 100644
--- a/test/mach-o/objc_export_list.yaml
+++ b/test/mach-o/objc_export_list.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t \
+# RUN: ld64.lld -arch x86_64 -dylib %s -o %t \
# RUN: -exported_symbol .objc_class_name_Foo %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-nm -m %t | FileCheck %s
#
diff --git a/test/mach-o/order_file-basic.yaml b/test/mach-o/order_file-basic.yaml
index f4d29fa17012..8c43ee6a7aaa 100644
--- a/test/mach-o/order_file-basic.yaml
+++ b/test/mach-o/order_file-basic.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/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
diff --git a/test/mach-o/parse-aliases.yaml b/test/mach-o/parse-aliases.yaml
index 54da2d64e63a..9d0a1c07dfce 100644
--- a/test/mach-o/parse-aliases.yaml
+++ b/test/mach-o/parse-aliases.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test multiple labels to same address parse into aliases.
#
diff --git a/test/mach-o/parse-arm-relocs.yaml b/test/mach-o/parse-arm-relocs.yaml
index abeb3ddeb9d1..9add766bef0c 100644
--- a/test/mach-o/parse-arm-relocs.yaml
+++ b/test/mach-o/parse-arm-relocs.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing of armv7 relocations.
#
diff --git a/test/mach-o/parse-cfstring32.yaml b/test/mach-o/parse-cfstring32.yaml
index 8e746f276664..52588d561dd9 100644
--- a/test/mach-o/parse-cfstring32.yaml
+++ b/test/mach-o/parse-cfstring32.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of mach-o functions.
#
diff --git a/test/mach-o/parse-cfstring64.yaml b/test/mach-o/parse-cfstring64.yaml
index b90277f056e5..f427ae51b648 100644
--- a/test/mach-o/parse-cfstring64.yaml
+++ b/test/mach-o/parse-cfstring64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of CFString constants.
#
diff --git a/test/mach-o/parse-compact-unwind32.yaml b/test/mach-o/parse-compact-unwind32.yaml
index ff613f0809bb..6af5fd4a2371 100644
--- a/test/mach-o/parse-compact-unwind32.yaml
+++ b/test/mach-o/parse-compact-unwind32.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of __LD/__compact_unwind (compact unwind) section.
#
diff --git a/test/mach-o/parse-compact-unwind64.yaml b/test/mach-o/parse-compact-unwind64.yaml
index af8967476e16..f0c1c86c2c07 100644
--- a/test/mach-o/parse-compact-unwind64.yaml
+++ b/test/mach-o/parse-compact-unwind64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of __LD/__compact_unwind (compact unwind) section.
#
diff --git a/test/mach-o/parse-data-in-code-armv7.yaml b/test/mach-o/parse-data-in-code-armv7.yaml
index 163cb18fdc5f..18eb6ffddc57 100644
--- a/test/mach-o/parse-data-in-code-armv7.yaml
+++ b/test/mach-o/parse-data-in-code-armv7.yaml
@@ -1,6 +1,6 @@
-# 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/armv7/libSystem.yaml \
+# RUN: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: ld64.lld -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/armv7/libSystem.yaml \
# RUN: && llvm-objdump -macho -private-headers %t3.dylib | FileCheck --check-prefix=CHECK2 %s
#
# Test parsing LC_DATA_IN_CODE
diff --git a/test/mach-o/parse-data-in-code-x86.yaml b/test/mach-o/parse-data-in-code-x86.yaml
index 43934440f2a0..927a9aa30cb0 100644
--- a/test/mach-o/parse-data-in-code-x86.yaml
+++ b/test/mach-o/parse-data-in-code-x86.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && ld64.lld -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing LC_DATA_IN_CODE
#
diff --git a/test/mach-o/parse-data-relocs-arm64.yaml b/test/mach-o/parse-data-relocs-arm64.yaml
index 0edd64689b2e..a46da1bffba3 100644
--- a/test/mach-o/parse-data-relocs-arm64.yaml
+++ b/test/mach-o/parse-data-relocs-arm64.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing and writing of arm64 data relocations.
#
diff --git a/test/mach-o/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml
index 6b5bb4b8fb59..d696aff0feff 100644
--- a/test/mach-o/parse-data-relocs-x86_64.yaml
+++ b/test/mach-o/parse-data-relocs-x86_64.yaml
@@ -1,6 +1,6 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \
+# RUN: && ld64.lld -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s
#
# Test parsing and writing of x86_64 data relocations.
#
diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml
index 3b422e04cae7..b1929ef230b6 100644
--- a/test/mach-o/parse-data.yaml
+++ b/test/mach-o/parse-data.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of mach-o data symbols.
#
diff --git a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
index b009cbcea139..0bc47ffef009 100644
--- a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
+++ b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of x86_64 __eh_frame (dwarf unwind) relocations.
diff --git a/test/mach-o/parse-eh-frame-x86-anon.yaml b/test/mach-o/parse-eh-frame-x86-anon.yaml
index 09b6ba37c09a..7a85dcb2de90 100644
--- a/test/mach-o/parse-eh-frame-x86-anon.yaml
+++ b/test/mach-o/parse-eh-frame-x86-anon.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -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.
diff --git a/test/mach-o/parse-eh-frame-x86-labeled.yaml b/test/mach-o/parse-eh-frame-x86-labeled.yaml
index 5be5abcc4a0e..7ec86de6d012 100644
--- a/test/mach-o/parse-eh-frame-x86-labeled.yaml
+++ b/test/mach-o/parse-eh-frame-x86-labeled.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -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.
diff --git a/test/mach-o/parse-eh-frame.yaml b/test/mach-o/parse-eh-frame.yaml
index 6453474024bb..6571c4f4d2d8 100644
--- a/test/mach-o/parse-eh-frame.yaml
+++ b/test/mach-o/parse-eh-frame.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of __eh_frame (dwarf unwind) section.
#
diff --git a/test/mach-o/parse-function.yaml b/test/mach-o/parse-function.yaml
index bfd8e5c815f4..677cf9a7f166 100644
--- a/test/mach-o/parse-function.yaml
+++ b/test/mach-o/parse-function.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r %s -o %t
+# RUN: ld64.lld -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s
#
# Test parsing of mach-o functions.
#
diff --git a/test/mach-o/parse-initializers32.yaml b/test/mach-o/parse-initializers32.yaml
index ede7b90e2cb9..b15f2954a4bb 100644
--- a/test/mach-o/parse-initializers32.yaml
+++ b/test/mach-o/parse-initializers32.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of literal sections.
#
diff --git a/test/mach-o/parse-initializers64.yaml b/test/mach-o/parse-initializers64.yaml
index c55a0ea0a5fa..9b3cb2d2264f 100644
--- a/test/mach-o/parse-initializers64.yaml
+++ b/test/mach-o/parse-initializers64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of literal sections.
#
diff --git a/test/mach-o/parse-literals-error.yaml b/test/mach-o/parse-literals-error.yaml
index 8daeeca5f654..9dad0cbbf974 100644
--- a/test/mach-o/parse-literals-error.yaml
+++ b/test/mach-o/parse-literals-error.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t 2> %t.err
+# RUN: not ld64.lld -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.
diff --git a/test/mach-o/parse-literals.yaml b/test/mach-o/parse-literals.yaml
index 7f80ba5212b8..f23653d475a9 100644
--- a/test/mach-o/parse-literals.yaml
+++ b/test/mach-o/parse-literals.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of literal sections.
#
diff --git a/test/mach-o/parse-non-lazy-pointers.yaml b/test/mach-o/parse-non-lazy-pointers.yaml
index 0b0ec5cf36ef..9d6a86221b2f 100644
--- a/test/mach-o/parse-non-lazy-pointers.yaml
+++ b/test/mach-o/parse-non-lazy-pointers.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of non-lazy-pointer sections.
#
diff --git a/test/mach-o/parse-relocs-x86.yaml b/test/mach-o/parse-relocs-x86.yaml
index c7ce80bb42a1..b93b43645714 100644
--- a/test/mach-o/parse-relocs-x86.yaml
+++ b/test/mach-o/parse-relocs-x86.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && ld64.lld -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing and writing of x86 relocations.
#
diff --git a/test/mach-o/parse-section-no-symbol.yaml b/test/mach-o/parse-section-no-symbol.yaml
index 46d005a1cd18..6164f0e3aaaf 100644
--- a/test/mach-o/parse-section-no-symbol.yaml
+++ b/test/mach-o/parse-section-no-symbol.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s
#
# Test parsing of mach-o functions with no symbols at all.
#
diff --git a/test/mach-o/parse-tentative-defs.yaml b/test/mach-o/parse-tentative-defs.yaml
index 1757c8c928b6..63596e9e37ad 100644
--- a/test/mach-o/parse-tentative-defs.yaml
+++ b/test/mach-o/parse-tentative-defs.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of tentative definitions, including size, scope, and alignment.
#
diff --git a/test/mach-o/parse-text-relocs-arm64.yaml b/test/mach-o/parse-text-relocs-arm64.yaml
index 38a52e7f6f28..9112782eba98 100644
--- a/test/mach-o/parse-text-relocs-arm64.yaml
+++ b/test/mach-o/parse-text-relocs-arm64.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing and writing of arm64 text relocations.
#
diff --git a/test/mach-o/parse-text-relocs-x86_64.yaml b/test/mach-o/parse-text-relocs-x86_64.yaml
index 6d0a52f60045..76df030c69ed 100644
--- a/test/mach-o/parse-text-relocs-x86_64.yaml
+++ b/test/mach-o/parse-text-relocs-x86_64.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing and writing of x86_64 text relocations.
#
diff --git a/test/mach-o/parse-tlv-relocs-x86-64.yaml b/test/mach-o/parse-tlv-relocs-x86-64.yaml
index 78b17841d4e7..b1a12e20ff7b 100644
--- a/test/mach-o/parse-tlv-relocs-x86-64.yaml
+++ b/test/mach-o/parse-tlv-relocs-x86-64.yaml
@@ -1,5 +1,5 @@
-# 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
+# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing of x86_64 tlv relocations.
diff --git a/test/mach-o/re-exported-dylib-ordinal.yaml b/test/mach-o/re-exported-dylib-ordinal.yaml
index ff4d756338ce..b25a5ec00221 100644
--- a/test/mach-o/re-exported-dylib-ordinal.yaml
+++ b/test/mach-o/re-exported-dylib-ordinal.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/rpath.yaml b/test/mach-o/rpath.yaml
index 639149381293..b25266ced993 100644
--- a/test/mach-o/rpath.yaml
+++ b/test/mach-o/rpath.yaml
@@ -1,5 +1,5 @@
# Check we handle -rpath correctly:
-# RUN: lld -flavor darwin -arch x86_64 -rpath @loader_path/../Frameworks \
+# RUN: ld64.lld -arch x86_64 -rpath @loader_path/../Frameworks \
# RUN: %p/Inputs/x86_64/libSystem.yaml %s -o %t
# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
diff --git a/test/mach-o/run-tlv-pass-x86-64.yaml b/test/mach-o/run-tlv-pass-x86-64.yaml
index dd524c067d87..765e1c1fd1bb 100644
--- a/test/mach-o/run-tlv-pass-x86-64.yaml
+++ b/test/mach-o/run-tlv-pass-x86-64.yaml
@@ -1,5 +1,5 @@
-# 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: ld64.lld -macosx_version_min 10.7 -arch x86_64 -print_atoms %s -o %t | FileCheck %s
+# RUN: not ld64.lld -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
#
diff --git a/test/mach-o/sdk-version-error.yaml b/test/mach-o/sdk-version-error.yaml
index 2607bb8e9c58..c7e4011b238c 100644
--- a/test/mach-o/sdk-version-error.yaml
+++ b/test/mach-o/sdk-version-error.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+# RUN: not ld64.lld -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/sectalign.yaml b/test/mach-o/sectalign.yaml
index f0df9f9c5485..b788d422bbb8 100644
--- a/test/mach-o/sectalign.yaml
+++ b/test/mach-o/sectalign.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -dylib \
# RUN: -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \
# RUN: %p/Inputs/x86_64/libSystem.yaml -o %t \
# RUN: && llvm-readobj -sections %t | FileCheck %s
diff --git a/test/mach-o/sectattrs.yaml b/test/mach-o/sectattrs.yaml
index 21113dcf8280..467c2b7fca07 100644
--- a/test/mach-o/sectattrs.yaml
+++ b/test/mach-o/sectattrs.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -dylib \
# RUN: %p/Inputs/x86_64/libSystem.yaml -o %t \
# RUN: && llvm-objdump -private-headers %t | FileCheck %s
#
diff --git a/test/mach-o/sectcreate.yaml b/test/mach-o/sectcreate.yaml
index 51c59dc5f3d4..aa32a05a6fb7 100644
--- a/test/mach-o/sectcreate.yaml
+++ b/test/mach-o/sectcreate.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -r -arch x86_64 -o %t -sectcreate __DATA __data \
+# RUN: ld64.lld -r -arch x86_64 -o %t -sectcreate __DATA __data \
# RUN: %p/Inputs/hw.raw_bytes -print_atoms | FileCheck %s
# CHECK: --- !native
diff --git a/test/mach-o/seg-protection-arm64.yaml b/test/mach-o/seg-protection-arm64.yaml
index f63b33ad2dc3..6b00fc9cfaea 100644
--- a/test/mach-o/seg-protection-arm64.yaml
+++ b/test/mach-o/seg-protection-arm64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
--- !mach-o
arch: arm64
diff --git a/test/mach-o/seg-protection-x86_64.yaml b/test/mach-o/seg-protection-x86_64.yaml
index 474f72f4c57f..2ce356634c7b 100644
--- a/test/mach-o/seg-protection-x86_64.yaml
+++ b/test/mach-o/seg-protection-x86_64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -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
diff --git a/test/mach-o/source-version.yaml b/test/mach-o/source-version.yaml
index 4e0eaee394f1..ce185f8886b6 100644
--- a/test/mach-o/source-version.yaml
+++ b/test/mach-o/source-version.yaml
@@ -1,5 +1,5 @@
-# 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/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: not ld64.lld -arch x86_64 -source_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+# RUN: ld64.lld -arch x86_64 -source_version 10.1.2.3.4 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/stack-size.yaml b/test/mach-o/stack-size.yaml
index 048282c504ef..6a5e313c4596 100644
--- a/test/mach-o/stack-size.yaml
+++ b/test/mach-o/stack-size.yaml
@@ -1,10 +1,10 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/x86_64/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/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t -stack_size 31415926000 %p/Inputs/x86_64/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: not ld64.lld -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: not ld64.lld -arch x86_64 -stack_size hithere %s >/dev/null 2> %t
# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
--- !native
diff --git a/test/mach-o/string-table.yaml b/test/mach-o/string-table.yaml
index eec2c77fe157..8bb4cfe495ad 100644
--- a/test/mach-o/string-table.yaml
+++ b/test/mach-o/string-table.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
# RUN: obj2yaml %t | FileCheck %s
#
# Test that the string table contains a ' ' as its first symbol
diff --git a/test/mach-o/subsections-via-symbols-default.yaml b/test/mach-o/subsections-via-symbols-default.yaml
index 93ddbc943f9a..a9bb4236875e 100644
--- a/test/mach-o/subsections-via-symbols-default.yaml
+++ b/test/mach-o/subsections-via-symbols-default.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t
+# RUN: ld64.lld -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
diff --git a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml
index b402ae3e17f2..a8ceb0f81ce4 100644
--- a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml
+++ b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/x86_64/libSystem.yaml
#
# Sanity check '-twolevel_namespace -undefined dynamic_lookup'.
# This should pass without error, even though '_bar' is undefined.
diff --git a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml
index 1ac704cdf954..6d9eaddacf99 100644
--- a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml
+++ b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml
@@ -1,6 +1,6 @@
-# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \
+# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/x86_64/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/x86_64/libSystem.yaml 2>&1 | \
+# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \
# RUN: FileCheck --check-prefix=CHECK-SUPPRESS %s
--- !native
diff --git a/test/mach-o/unwind-info-simple-arm64.yaml b/test/mach-o/unwind-info-simple-arm64.yaml
index 4caaf3582630..920cc0d7c363 100644
--- a/test/mach-o/unwind-info-simple-arm64.yaml
+++ b/test/mach-o/unwind-info-simple-arm64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch arm64 -o %t %s \
+# RUN: ld64.lld -arch arm64 -o %t %s \
# RUN: %p/Inputs/unwind-info-simple-arm64.yaml -e _main %p/Inputs/arm64/libSystem.yaml
# RUN: llvm-objdump -unwind-info %t | FileCheck %s
diff --git a/test/mach-o/unwind-info-simple-x86_64.yaml b/test/mach-o/unwind-info-simple-x86_64.yaml
index 797c5a319d2c..0c9b74c478c9 100644
--- a/test/mach-o/unwind-info-simple-x86_64.yaml
+++ b/test/mach-o/unwind-info-simple-x86_64.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _main %p/Inputs/x86_64/libSystem.yaml
+# RUN: ld64.lld -arch x86_64 %s -o %t -e _main %p/Inputs/x86_64/libSystem.yaml
# RUN: llvm-objdump -unwind-info %t | FileCheck %s
# CHECK: Contents of __unwind_info section:
diff --git a/test/mach-o/upward-dylib-load-command.yaml b/test/mach-o/upward-dylib-load-command.yaml
index 54e31f6960be..7fc703c7bef5 100644
--- a/test/mach-o/upward-dylib-load-command.yaml
+++ b/test/mach-o/upward-dylib-load-command.yaml
@@ -1,6 +1,6 @@
-# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN: ld64.lld -arch x86_64 -dylib %p/Inputs/bar.yaml \
# RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib
-# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library %t1.dylib \
+# RUN: ld64.lld -arch x86_64 -dylib %s -upward_library %t1.dylib \
# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t
# RUN: llvm-objdump -private-headers %t | FileCheck %s
#
diff --git a/test/mach-o/upward-dylib-paths.yaml b/test/mach-o/upward-dylib-paths.yaml
index 53ff9fa2298c..48536330695a 100644
--- a/test/mach-o/upward-dylib-paths.yaml
+++ b/test/mach-o/upward-dylib-paths.yaml
@@ -1,6 +1,6 @@
#
#
-# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: ld64.lld -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 \
diff --git a/test/mach-o/usage.yaml b/test/mach-o/usage.yaml
index 20a506284c96..d95823d24b83 100644
--- a/test/mach-o/usage.yaml
+++ b/test/mach-o/usage.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin | FileCheck %s
+# RUN: not ld64.lld | FileCheck %s
#
# Test that running darwin linker with no option prints out usage message.
#
diff --git a/test/mach-o/use-dylib.yaml b/test/mach-o/use-dylib.yaml
index c173cc0af352..bcb2d07e38e8 100644
--- a/test/mach-o/use-dylib.yaml
+++ b/test/mach-o/use-dylib.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s \
+# RUN: ld64.lld -arch x86_64 %s \
# RUN: %p/Inputs/use-simple-dylib.yaml %p/Inputs/x86_64/libSystem.yaml -dylib -o %t.dylib
# RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s
diff --git a/test/mach-o/use-simple-dylib.yaml b/test/mach-o/use-simple-dylib.yaml
index 658be16356ea..09906597f8dd 100644
--- a/test/mach-o/use-simple-dylib.yaml
+++ b/test/mach-o/use-simple-dylib.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 -print_atoms -r %s \
+# RUN: ld64.lld -arch x86_64 -print_atoms -r %s \
# RUN: %p/Inputs/use-simple-dylib.yaml -o %t | FileCheck %s
diff --git a/test/mach-o/version-min-load-command-object.yaml b/test/mach-o/version-min-load-command-object.yaml
index 33001cc6f715..08eb6ab768bf 100644
--- a/test/mach-o/version-min-load-command-object.yaml
+++ b/test/mach-o/version-min-load-command-object.yaml
@@ -1,6 +1,6 @@
-# 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
+# RUN: ld64.lld -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -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.
diff --git a/test/mach-o/version-min-load-command.yaml b/test/mach-o/version-min-load-command.yaml
index cb5331ec7f4b..a4d39b85e4c2 100644
--- a/test/mach-o/version-min-load-command.yaml
+++ b/test/mach-o/version-min-load-command.yaml
@@ -1,11 +1,11 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/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/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s --check-prefix=WARNING
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/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/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION
+# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -sdk_version 10.9 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION
--- !mach-o
arch: x86_64
diff --git a/test/mach-o/write-final-sections.yaml b/test/mach-o/write-final-sections.yaml
index 4e94acfa25b1..b39127139f80 100644
--- a/test/mach-o/write-final-sections.yaml
+++ b/test/mach-o/write-final-sections.yaml
@@ -1,4 +1,4 @@
-# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/write-final-sections.yaml \
+# RUN: ld64.lld -arch x86_64 %s %p/Inputs/write-final-sections.yaml \
# RUN: -o %t -e _foo
# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
diff --git a/test/mach-o/wrong-arch-error.yaml b/test/mach-o/wrong-arch-error.yaml
index 3b8ef0dc7ee6..d518c2943842 100644
--- a/test/mach-o/wrong-arch-error.yaml
+++ b/test/mach-o/wrong-arch-error.yaml
@@ -1,4 +1,4 @@
-# RUN: not lld -flavor darwin -arch x86_64 -r %s \
+# RUN: not ld64.lld -arch x86_64 -r %s \
# RUN: %p/Inputs/wrong-arch-error.yaml 2> %t.err
# RUN: FileCheck %s < %t.err
diff --git a/test/wasm/Inputs/archive1.ll b/test/wasm/Inputs/archive1.ll
index c942fa2c1b55..7f614795aa0c 100644
--- a/test/wasm/Inputs/archive1.ll
+++ b/test/wasm/Inputs/archive1.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
declare i32 @bar() local_unnamed_addr #1
define i32 @foo() local_unnamed_addr #0 {
diff --git a/test/wasm/Inputs/archive2.ll b/test/wasm/Inputs/archive2.ll
index 35534dc9e076..66bfeac5ac6c 100644
--- a/test/wasm/Inputs/archive2.ll
+++ b/test/wasm/Inputs/archive2.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
declare i32 @foo() local_unnamed_addr #1
define i32 @bar() local_unnamed_addr #0 {
@@ -5,3 +7,8 @@ entry:
%call = tail call i32 @foo() #2
ret i32 %call
}
+
+define void @archive2_symbol() local_unnamed_addr #0 {
+entry:
+ ret void
+}
diff --git a/test/wasm/Inputs/archive3.ll b/test/wasm/Inputs/archive3.ll
new file mode 100644
index 000000000000..8c78a464f490
--- /dev/null
+++ b/test/wasm/Inputs/archive3.ll
@@ -0,0 +1,11 @@
+target triple = "wasm32-unknown-unknown"
+
+define i32 @bar() local_unnamed_addr #0 {
+entry:
+ ret i32 1
+}
+
+define void @archive3_symbol() local_unnamed_addr #0 {
+entry:
+ ret void
+}
diff --git a/test/wasm/Inputs/call-indirect.ll b/test/wasm/Inputs/call-indirect.ll
index 388ea60c3a07..6afcf30c2515 100644
--- a/test/wasm/Inputs/call-indirect.ll
+++ b/test/wasm/Inputs/call-indirect.ll
@@ -1,17 +1,20 @@
-@indirect_bar = internal local_unnamed_addr global i32 ()* @bar, align 4
+target triple = "wasm32-unknown-unknown"
+
+@indirect_bar = internal local_unnamed_addr global i64 ()* @bar, align 4
@indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4
declare i32 @foo() local_unnamed_addr
-define i32 @bar() {
+define i64 @bar() {
entry:
- ret i32 1
+ ret i64 1
}
define void @call_bar_indirect() local_unnamed_addr #1 {
entry:
- %0 = load i32 ()*, i32 ()** @indirect_bar, align 4
+ %0 = load i64 ()*, i64 ()** @indirect_bar, align 4
%1 = load i32 ()*, i32 ()** @indirect_foo, align 4
- %call = tail call i32 %0() #2
+ %call0 = tail call i64 %0() #2
+ %call1 = tail call i32 %1() #2
ret void
}
diff --git a/test/wasm/Inputs/comdat1.ll b/test/wasm/Inputs/comdat1.ll
new file mode 100644
index 000000000000..12678b0eeff7
--- /dev/null
+++ b/test/wasm/Inputs/comdat1.ll
@@ -0,0 +1,13 @@
+target triple = "wasm32-unknown-unknown"
+
+$inlineFn = comdat any
+@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
+define linkonce_odr i32 @inlineFn() comdat {
+entry:
+ ret i32 ptrtoint ([3 x i8]* @constantData to i32)
+}
+
+define i32 @callInline1() {
+entry:
+ ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+}
diff --git a/test/wasm/Inputs/comdat2.ll b/test/wasm/Inputs/comdat2.ll
new file mode 100644
index 000000000000..d910e1afcdfc
--- /dev/null
+++ b/test/wasm/Inputs/comdat2.ll
@@ -0,0 +1,13 @@
+target triple = "wasm32-unknown-unknown"
+
+$inlineFn = comdat any
+@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
+define linkonce_odr i32 @inlineFn() comdat {
+entry:
+ ret i32 ptrtoint ([3 x i8]* @constantData to i32)
+}
+
+define i32 @callInline2() {
+entry:
+ ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+}
diff --git a/test/wasm/Inputs/custom.ll b/test/wasm/Inputs/custom.ll
new file mode 100644
index 000000000000..30b4ef00bc4c
--- /dev/null
+++ b/test/wasm/Inputs/custom.ll
@@ -0,0 +1,6 @@
+target triple = "wasm32-unknown-unknown"
+
+!0 = !{ !"red", !"foo" }
+!1 = !{ !"green", !"bar" }
+!2 = !{ !"green", !"qux" }
+!wasm.custom_sections = !{ !0, !1, !2 }
diff --git a/test/wasm/Inputs/debuginfo1.ll b/test/wasm/Inputs/debuginfo1.ll
new file mode 100644
index 000000000000..7f37fd4fccb8
--- /dev/null
+++ b/test/wasm/Inputs/debuginfo1.ll
@@ -0,0 +1,68 @@
+; ModuleID = 'hi.c'
+source_filename = "hi.c"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; // hi.c:
+; extern void foo(int);
+;
+; int test(int t) {
+; return t * t;
+; }
+;
+; int _start() {
+; foo(test(10));
+; return 0;
+; }
+
+; Function Attrs: nounwind readnone
+define hidden i32 @test(i32 %t) local_unnamed_addr #0 !dbg !7 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %t, metadata !12, metadata !DIExpression()), !dbg !13
+ %mul = mul nsw i32 %t, %t, !dbg !14
+ ret i32 %mul, !dbg !15
+}
+
+; Function Attrs: nounwind
+define hidden i32 @_start() local_unnamed_addr #1 !dbg !16 {
+entry:
+ tail call void @foo(i32 100) #4, !dbg !19
+ ret i32 0, !dbg !20
+}
+
+declare void @foo(i32) local_unnamed_addr #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "hi.c", directory: "/Users/yury/llvmwasm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 7.0.0 (trunk 331321)"}
+!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "t", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocation(line: 3, column: 14, scope: !7)
+!14 = !DILocation(line: 4, column: 12, scope: !7)
+!15 = !DILocation(line: 4, column: 3, scope: !7)
+!16 = distinct !DISubprogram(name: "_start", scope: !1, file: !1, line: 7, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, retainedNodes: !2)
+!17 = !DISubroutineType(types: !18)
+!18 = !{!10}
+!19 = !DILocation(line: 8, column: 3, scope: !16)
+!20 = !DILocation(line: 9, column: 3, scope: !16)
diff --git a/test/wasm/Inputs/debuginfo2.ll b/test/wasm/Inputs/debuginfo2.ll
new file mode 100644
index 000000000000..72f94e0407c1
--- /dev/null
+++ b/test/wasm/Inputs/debuginfo2.ll
@@ -0,0 +1,70 @@
+; ModuleID = 'hi_foo.c'
+source_filename = "hi_foo.c"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; // hi_foo.c:
+; int y[2] = {23, 41};
+;
+; void foo(int p) {
+; y[p & 1]++;
+; }
+;
+; // Will be GCed, but remain visible in debug info
+; int z[2] = {1, 2};
+
+@y = hidden local_unnamed_addr global [2 x i32] [i32 23, i32 41], align 4, !dbg !0
+@z = hidden local_unnamed_addr global [2 x i32] [i32 1, i32 2], align 4, !dbg !6
+
+; Function Attrs: nounwind
+define hidden void @foo(i32 %p) local_unnamed_addr #0 !dbg !16 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %p, metadata !20, metadata !DIExpression()), !dbg !21
+ %and = and i32 %p, 1, !dbg !22
+ %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @y, i32 0, i32 %and, !dbg !23
+ %0 = load i32, i32* %arrayidx, align 4, !dbg !24, !tbaa !25
+ %inc = add nsw i32 %0, 1, !dbg !24
+ store i32 %inc, i32* %arrayidx, align 4, !dbg !24, !tbaa !25
+ ret void, !dbg !29
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "hi_foo.c", directory: "/usr/local/google/home/sbc/dev/wasm/llvm-build")
+!4 = !{}
+!5 = !{!0, !6}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true)
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11}
+!11 = !DISubrange(count: 2)
+!12 = !{i32 2, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{!"clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)"}
+!16 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !17, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !19)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null, !9}
+!19 = !{!20}
+!20 = !DILocalVariable(name: "p", arg: 1, scope: !16, file: !3, line: 3, type: !9)
+!21 = !DILocation(line: 3, column: 14, scope: !16)
+!22 = !DILocation(line: 4, column: 7, scope: !16)
+!23 = !DILocation(line: 4, column: 3, scope: !16)
+!24 = !DILocation(line: 4, column: 11, scope: !16)
+!25 = !{!26, !26, i64 0}
+!26 = !{!"int", !27, i64 0}
+!27 = !{!"omnipotent char", !28, i64 0}
+!28 = !{!"Simple C/C++ TBAA"}
+!29 = !DILocation(line: 5, column: 1, scope: !16)
diff --git a/test/wasm/Inputs/global-ctor-dtor.ll b/test/wasm/Inputs/global-ctor-dtor.ll
index 5cacd7e433ab..5e73f06b0c02 100644
--- a/test/wasm/Inputs/global-ctor-dtor.ll
+++ b/test/wasm/Inputs/global-ctor-dtor.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
define hidden void @myctor() {
entry:
ret void
@@ -9,6 +11,14 @@ entry:
ret void
}
-@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }]
+@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
+ { i32, void ()*, i8* } { i32 2002, void ()* @myctor, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @myctor, i8* null },
+ { i32, void ()*, i8* } { i32 202, void ()* @myctor, i8* null }
+]
-@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }]
+@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [
+ { i32, void ()*, i8* } { i32 2002, void ()* @mydtor, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @mydtor, i8* null },
+ { i32, void ()*, i8* } { i32 202, void ()* @mydtor, i8* null }
+]
diff --git a/test/wasm/Inputs/globals.yaml b/test/wasm/Inputs/globals.yaml
new file mode 100644
index 000000000000..c08a3044ec95
--- /dev/null
+++ b/test/wasm/Inputs/globals.yaml
@@ -0,0 +1,54 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ReturnType: I64
+ ParamTypes:
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: GLOBAL
+ Globals:
+ - Index: 0
+ Type: I64
+ Mutable: true
+ InitExpr:
+ Opcode: I64_CONST
+ Value: 123
+ - Index: 1
+ Type: I64
+ Mutable: true
+ InitExpr:
+ Opcode: I64_CONST
+ Value: 456
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ Body: 2381808080000B
+ Relocations:
+ - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+ Index: 1
+ Offset: 0x00000004
+ - Type: CUSTOM
+ Name: linking
+ Version: 1
+ SymbolTable:
+ - Index: 0
+ Kind: GLOBAL
+ Name: unused_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Global: 0
+ - Index: 1
+ Kind: GLOBAL
+ Name: used_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Global: 1
+ - Index: 2
+ Kind: FUNCTION
+ Name: use_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Function: 0
+...
diff --git a/test/wasm/Inputs/hello.ll b/test/wasm/Inputs/hello.ll
index 93df0f559809..675566861cc7 100644
--- a/test/wasm/Inputs/hello.ll
+++ b/test/wasm/Inputs/hello.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
; Wasm module generated from the following C code:
; void puts(const char*);
; void hello() { puts("hello\n"); }
diff --git a/test/wasm/Inputs/hidden.ll b/test/wasm/Inputs/hidden.ll
index 25890e9f03f2..4af16b3b99ed 100644
--- a/test/wasm/Inputs/hidden.ll
+++ b/test/wasm/Inputs/hidden.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: norecurse nounwind readnone
define hidden i32 @archiveHidden() #0 {
entry:
diff --git a/test/wasm/Inputs/locals-duplicate1.ll b/test/wasm/Inputs/locals-duplicate1.ll
new file mode 100644
index 000000000000..f118dd4bd679
--- /dev/null
+++ b/test/wasm/Inputs/locals-duplicate1.ll
@@ -0,0 +1,51 @@
+target triple = "wasm32-unknown-unknown"
+
+; Will collide: local (internal linkage) with global (external) linkage
+@colliding_global1 = internal default global i32 0, align 4
+; Will collide: global with local
+@colliding_global2 = default global i32 0, align 4
+; Will collide: local with local
+@colliding_global3 = internal default global i32 0, align 4
+
+; Will collide: local with global
+define internal i32 @colliding_func1() {
+entry:
+ ret i32 2
+}
+; Will collide: global with local
+define i32 @colliding_func2() {
+entry:
+ ret i32 2
+}
+; Will collide: local with local
+define internal i32 @colliding_func3() {
+entry:
+ ret i32 2
+}
+
+
+define i32* @get_global1A() {
+entry:
+ ret i32* @colliding_global1
+}
+define i32* @get_global2A() {
+entry:
+ ret i32* @colliding_global2
+}
+define i32* @get_global3A() {
+entry:
+ ret i32* @colliding_global3
+}
+
+define i32 ()* @get_func1A() {
+entry:
+ ret i32 ()* @colliding_func1
+}
+define i32 ()* @get_func2A() {
+entry:
+ ret i32 ()* @colliding_func2
+}
+define i32 ()* @get_func3A() {
+entry:
+ ret i32 ()* @colliding_func3
+}
diff --git a/test/wasm/Inputs/locals-duplicate2.ll b/test/wasm/Inputs/locals-duplicate2.ll
new file mode 100644
index 000000000000..617abfea0cdc
--- /dev/null
+++ b/test/wasm/Inputs/locals-duplicate2.ll
@@ -0,0 +1,51 @@
+target triple = "wasm32-unknown-unknown"
+
+; Will collide: local (internal linkage) with global (external) linkage
+@colliding_global1 = default global i32 0, align 4
+; Will collide: global with local
+@colliding_global2 = internal default global i32 0, align 4
+; Will collide: local with local
+@colliding_global3 = internal default global i32 0, align 4
+
+; Will collide: local with global
+define i32 @colliding_func1() {
+entry:
+ ret i32 2
+}
+; Will collide: global with local
+define internal i32 @colliding_func2() {
+entry:
+ ret i32 2
+}
+; Will collide: local with local
+define internal i32 @colliding_func3() {
+entry:
+ ret i32 2
+}
+
+
+define i32* @get_global1B() {
+entry:
+ ret i32* @colliding_global1
+}
+define i32* @get_global2B() {
+entry:
+ ret i32* @colliding_global2
+}
+define i32* @get_global3B() {
+entry:
+ ret i32* @colliding_global3
+}
+
+define i32 ()* @get_func1B() {
+entry:
+ ret i32 ()* @colliding_func1
+}
+define i32 ()* @get_func2B() {
+entry:
+ ret i32 ()* @colliding_func2
+}
+define i32 ()* @get_func3B() {
+entry:
+ ret i32 ()* @colliding_func3
+}
diff --git a/test/wasm/Inputs/many-funcs.ll b/test/wasm/Inputs/many-funcs.ll
index b8daab23638d..1829d7d6b488 100644
--- a/test/wasm/Inputs/many-funcs.ll
+++ b/test/wasm/Inputs/many-funcs.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
@g0 = global i32 1, align 4
@foo = global i32 1, align 4
diff --git a/test/wasm/Inputs/ret32.ll b/test/wasm/Inputs/ret32.ll
index a4565288f08b..674b34b66499 100644
--- a/test/wasm/Inputs/ret32.ll
+++ b/test/wasm/Inputs/ret32.ll
@@ -1,6 +1,6 @@
-; Function Attrs: norecurse nounwind readnone
-define i32 @ret32(float %arg) #0 {
+target triple = "wasm32-unknown-unknown"
+
+define hidden i32 @ret32(float %arg) {
entry:
ret i32 0
- ; ptrtoint (i32 (float)* @ret32 to i32)
}
diff --git a/test/wasm/Inputs/ret64.ll b/test/wasm/Inputs/ret64.ll
index 6a9de0dace1d..c1dd5e55fee0 100644
--- a/test/wasm/Inputs/ret64.ll
+++ b/test/wasm/Inputs/ret64.ll
@@ -1,4 +1,6 @@
-define i64 @ret64(double %arg) local_unnamed_addr #0 {
+target triple = "wasm32-unknown-unknown"
+
+define hidden i64 @ret64(double %arg) {
entry:
ret i64 1
}
diff --git a/test/wasm/Inputs/start.ll b/test/wasm/Inputs/start.ll
new file mode 100644
index 000000000000..e2629659bf50
--- /dev/null
+++ b/test/wasm/Inputs/start.ll
@@ -0,0 +1,6 @@
+target triple = "wasm32-unknown-unknown"
+
+define void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
diff --git a/test/wasm/Inputs/strong-symbol.ll b/test/wasm/Inputs/strong-symbol.ll
new file mode 100644
index 000000000000..cc2aa8ab5d26
--- /dev/null
+++ b/test/wasm/Inputs/strong-symbol.ll
@@ -0,0 +1,6 @@
+target triple = "wasm32-unknown-unknown"
+
+define i64 @weakFn() #0 {
+entry:
+ ret i64 1
+}
diff --git a/test/wasm/Inputs/undefined-globals.yaml b/test/wasm/Inputs/undefined-globals.yaml
new file mode 100644
index 000000000000..440a538d6587
--- /dev/null
+++ b/test/wasm/Inputs/undefined-globals.yaml
@@ -0,0 +1,52 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ReturnType: I64
+ ParamTypes:
+ - Type: IMPORT
+ Imports:
+ - Module: env
+ Field: unused_undef_global
+ Kind: GLOBAL
+ GlobalType: I64
+ GlobalMutable: true
+ - Module: env
+ Field: used_undef_global
+ Kind: GLOBAL
+ GlobalType: I64
+ GlobalMutable: true
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ Body: 2381808080000B
+ Relocations:
+ - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+ Index: 1
+ Offset: 0x00000004
+ - Type: CUSTOM
+ Name: linking
+ Version: 1
+ SymbolTable:
+ - Index: 0
+ Kind: GLOBAL
+ Name: unused_undef_global
+ Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+ Global: 0
+ - Index: 1
+ Kind: GLOBAL
+ Name: used_undef_global
+ Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+ Global: 1
+ - Index: 2
+ Kind: FUNCTION
+ Name: use_undef_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Function: 0
+...
diff --git a/test/wasm/Inputs/weak-alias.ll b/test/wasm/Inputs/weak-alias.ll
index b911b35529c5..1840ffd1fc54 100644
--- a/test/wasm/Inputs/weak-alias.ll
+++ b/test/wasm/Inputs/weak-alias.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: norecurse nounwind readnone
define i32 @direct_fn() #0 {
entry:
diff --git a/test/wasm/Inputs/weak-symbol1.ll b/test/wasm/Inputs/weak-symbol1.ll
index 61e7e5818c54..6e394ff91d0c 100644
--- a/test/wasm/Inputs/weak-symbol1.ll
+++ b/test/wasm/Inputs/weak-symbol1.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
define weak i32 @weakFn() #0 {
entry:
ret i32 1
diff --git a/test/wasm/Inputs/weak-symbol2.ll b/test/wasm/Inputs/weak-symbol2.ll
index 9e2e270f8693..e9c30c18f7de 100644
--- a/test/wasm/Inputs/weak-symbol2.ll
+++ b/test/wasm/Inputs/weak-symbol2.ll
@@ -1,3 +1,5 @@
+target triple = "wasm32-unknown-unknown"
+
define weak i32 @weakFn() #0 {
entry:
ret i32 2
diff --git a/test/wasm/alias.ll b/test/wasm/alias.ll
new file mode 100644
index 000000000000..f88452e538c4
--- /dev/null
+++ b/test/wasm/alias.ll
@@ -0,0 +1,88 @@
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: wasm-ld %t.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+@start_alias = alias void (), void ()* @_start
+
+; Function Attrs: nounwind uwtable
+define void @_start() local_unnamed_addr #1 {
+entry:
+ ret void
+}
+
+; CHECK: --- !WASM
+; CHECK-NEXT: FileHeader:
+; CHECK-NEXT: Version: 0x00000001
+; CHECK-NEXT: Sections:
+; CHECK-NEXT: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0, 0 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; CHECK-NEXT: Initial: 0x00000001
+; CHECK-NEXT: Maximum: 0x00000001
+; CHECK-NEXT: - Type: MEMORY
+; CHECK-NEXT: Memories:
+; CHECK-NEXT: - Initial: 0x00000002
+; CHECK-NEXT: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: start_alias
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: ...
diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll
index a43e460d69f2..50f72d627386 100644
--- a/test/wasm/archive.ll
+++ b/test/wasm/archive.ll
@@ -1,31 +1,51 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive1.ll -o %t.a1.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive2.ll -o %t.a2.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/hello.ll -o %t.a3.o
-; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o
-; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: llc -filetype=obj %S/Inputs/archive1.ll -o %t.a1.o
+; RUN: llc -filetype=obj %S/Inputs/archive2.ll -o %t.a2.o
+; RUN: llc -filetype=obj %S/Inputs/archive3.ll -o %t.a3.o
+; RUN: llc -filetype=obj %S/Inputs/hello.ll -o %t.hello.o
+; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o %t.hello.o
+; RUN: rm -f %t.imports
+; RUN: not wasm-ld %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED %s
+
+; CHECK-UNDEFINED: undefined symbol: missing_func
+
+; RUN: echo 'missing_func' > %t.imports
+; RUN: wasm-ld -r %t.a %t.o -o %t.wasm
+
; RUN: llvm-nm -a %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
declare i32 @foo() local_unnamed_addr #1
+declare i32 @missing_func() local_unnamed_addr #1
-define i32 @_start() local_unnamed_addr #0 {
+define void @_start() local_unnamed_addr #0 {
entry:
- %call = tail call i32 @foo() #2
- ret i32 %call
+ %call1 = call i32 @foo() #2
+ %call2 = call i32 @missing_func() #2
+ ret void
}
-; Verify that multually dependant object files in an archive is handled
-; correctly.
+; Verify that mutually dependant object files in an archive is handled
+; correctly. Since we're using llvm-nm, we must link with --relocatable.
+;
+; TODO(ncw): Update LLD so that the symbol table is written out for
+; non-relocatable output (with an option to strip it)
-; CHECK: 00000002 T _start
-; CHECK-NEXT: 00000002 T _start
-; CHECK-NEXT: 00000000 T bar
-; CHECK-NEXT: 00000000 T bar
-; CHECK-NEXT: 00000001 T foo
-; CHECK-NEXT: 00000001 T foo
+; CHECK: 00000004 T _start
+; CHECK-NEXT: 00000002 T archive2_symbol
+; CHECK-NEXT: 00000001 T bar
+; CHECK-NEXT: 00000003 T foo
+; CHECK-NEXT: U missing_func
; Verify that symbols from unused objects don't appear in the symbol table
; CHECK-NOT: hello
; Specifying the same archive twice is allowed.
-; RUN: lld -flavor wasm %t.a %t.a %t.o -o %t.wasm
+; RUN: wasm-ld %t.a %t.a %t.o -o %t.wasm
+
+; Verfiy errors include library name
+; RUN: not wasm-ld -u archive2_symbol -u archive3_symbol %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-DUP %s
+; CHECK-DUP: error: duplicate symbol: bar
+; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a2.o)
+; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a3.o)
diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll
index 2b838a8efa4d..63a6def87382 100644
--- a/test/wasm/call-indirect.ll
+++ b/test/wasm/call-indirect.ll
@@ -1,6 +1,6 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/call-indirect.ll -o %t2.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t2.o %t.o
+; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t2.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; bitcode generated from the following C code:
@@ -8,6 +8,8 @@
; int (*indirect_func)(void) = &foo;
; void _start(void) { indirect_func(); }
+target triple = "wasm32-unknown-unknown"
+
@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
; Function Attrs: norecurse nounwind readnone
@@ -17,11 +19,11 @@ entry:
}
; Function Attrs: nounwind
-define i32 @_start() local_unnamed_addr #1 {
+define void @_start() local_unnamed_addr #1 {
entry:
%0 = load i32 ()*, i32 ()** @indirect_func, align 4
%call = call i32 %0() #2
- ret i32 0
+ ret void
}
; Indirect function call where no function actually has this type.
@@ -38,21 +40,24 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: ReturnType: NORESULT
-; CHECK-NEXT: ParamTypes:
-; CHECK-NEXT: - I32
-; CHECK-NEXT: - Index: 3
; CHECK-NEXT: ReturnType: I64
-; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I64
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - I32
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2 ]
+; CHECK-NEXT: FunctionTypes: [ 3, 0, 3, 1, 3, 4 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@@ -65,49 +70,87 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1036
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1032
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 3
-; CHECK-NEXT: - Name: foo
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: bar
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: call_bar_indirect
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: foo
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: indirect_func
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: call_ptr
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1
-; CHECK-NEXT: Functions: [ 0, 2 ]
+; CHECK-NEXT: Functions: [ 1, 3 ]
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 41010B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 410028028088808000118080808000001A0B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 42010B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: Count: 1
+; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41020B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 42012000118380808000001A0B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 410028028888808000118180808000001A0B
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 42012000118280808000001A0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@@ -117,16 +160,18 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: Content: '010000000200000002000000'
; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 12
-; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: bar
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: call_bar_indirect
+; CHECK-NEXT: Name: bar
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: foo
+; CHECK-NEXT: Name: call_bar_indirect
; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: foo
+; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: call_ptr
+; CHECK-NEXT: ...
diff --git a/test/wasm/comdats.ll b/test/wasm/comdats.ll
new file mode 100644
index 000000000000..d0bec4cda146
--- /dev/null
+++ b/test/wasm/comdats.ll
@@ -0,0 +1,99 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat1.ll -o %t1.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat2.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+declare i32 @inlineFn()
+
+define void @_start() local_unnamed_addr {
+entry:
+ %call = call i32 @inlineFn()
+ ret void
+}
+
+; CHECK: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1027
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: inlineFn
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: constantData
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: callInline1
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: callInline2
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Type: ELEM
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: Functions: [ 2 ]
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080001A0B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4180888080000B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4181808080000B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4181808080000B
+; CHECK-NEXT: - Type: DATA
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - SectionOffset: 7
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: Content: '616263'
diff --git a/test/wasm/compress-relocs.ll b/test/wasm/compress-relocs.ll
new file mode 100644
index 000000000000..b137d5abd43e
--- /dev/null
+++ b/test/wasm/compress-relocs.ll
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t2.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; RUN: wasm-ld -O2 -o %t-compressed.wasm %t2.o %t.o
+; RUN: obj2yaml %t-compressed.wasm | FileCheck %s -check-prefix=COMPRESS
+
+target triple = "wasm32-unknown-unknown-wasm"
+
+define i32 @foo() {
+entry:
+ ret i32 2
+}
+
+define void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
+
+; CHECK: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B
+; COMPRESS: Body: 41002802840821004100280280081100001A20001101001A0B
diff --git a/test/wasm/conflict.test b/test/wasm/conflict.test
index 41684ae51a12..9adc92ed1eda 100644
--- a/test/wasm/conflict.test
+++ b/test/wasm/conflict.test
@@ -1,5 +1,5 @@
-# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-# RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s
+# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: not wasm-ld -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s
# CHECK: duplicate symbol: ret32
# CHECK-NEXT: >>> defined in {{.*}}conflict.test.tmp.ret32.o
diff --git a/test/wasm/custom-sections.ll b/test/wasm/custom-sections.ll
new file mode 100644
index 000000000000..c33ca2774afa
--- /dev/null
+++ b/test/wasm/custom-sections.ll
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %s -o %t1.o
+; RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o
+; RUN: wasm-ld --relocatable -o %t.wasm %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i32 @_start() local_unnamed_addr {
+entry:
+ %retval = alloca i32, align 4
+ ret i32 0
+}
+
+!0 = !{ !"red", !"extra" }
+!wasm.custom_sections = !{ !0 }
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: green
+; CHECK-NEXT: Payload: '626172717578'
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: red
+; CHECK-NEXT: Payload: 6578747261666F6F
diff --git a/test/wasm/cxx-mangling.ll b/test/wasm/cxx-mangling.ll
new file mode 100644
index 000000000000..67f3594e8166
--- /dev/null
+++ b/test/wasm/cxx-mangling.ll
@@ -0,0 +1,66 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld --demangle -o %t_demangle.wasm %t.o
+; RUN: obj2yaml %t_demangle.wasm | FileCheck %s
+; RUN: wasm-ld --no-demangle -o %t_nodemangle.wasm %t.o
+; RUN: obj2yaml %t_nodemangle.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; Check that the EXPORT name is still mangled, but that the "name" custom
+; section contains the unmangled name.
+
+define void @_Z3fooi(i32 %arg) {
+ ret void
+}
+
+declare extern_weak void @_Z3bari(i32 %arg)
+
+define void @_start() {
+ call void @_Z3fooi(i32 1)
+ call void @_Z3bari(i32 1)
+ ret void
+}
+
+; CHECK: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: _Z3fooi
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 000B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 410110828080800041011081808080000B
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: 'undefined function bar(int)'
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: 'foo(int)'
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: ...
diff --git a/test/wasm/data-layout.ll b/test/wasm/data-layout.ll
index 2300b362a55f..5fd3f2d7791c 100644
--- a/test/wasm/data-layout.ll
+++ b/test/wasm/data-layout.ll
@@ -1,7 +1,7 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm --emit-relocs --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
+; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj %s -o %t.o
+
+target triple = "wasm32-unknown-unknown"
@foo = hidden global i32 1, align 4
@aligned_bar = hidden global i32 3, align 16
@@ -9,53 +9,138 @@
@hello_str = external global i8*
@external_ref = global i8** @hello_str, align 8
-; CHECK: - Type: GLOBAL
+%struct.s = type { i32, i32 }
+@local_struct = hidden global %struct.s zeroinitializer, align 4
+@local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4
+
+; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; CHECK: - Type: MEMORY
+; CHECK-NEXT: Memories:
+; CHECK-NEXT: - Initial: 0x00000002
+; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66608
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1024
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1040
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1048
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1052
+; CHECK-NEXT: Value: 66608
-; CHECK: - Type: DATA
-; CHECK-NEXT: Relocations:
-; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
-; CHECK-NEXT: Index: 4
-; CHECK-NEXT: Offset: 0x0000001F
+; CHECK: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1024
-; CHECK-NEXT: Content: 0100000000000000000000000000000003000000000000001C040000
-; CHECK-NEXT: - SectionOffset: 41
+; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000002804000024040000'
+; CHECK-NEXT: - SectionOffset: 45
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1052
+; CHECK-NEXT: Value: 1056
+; CHECK-NEXT: Content: '0000000000000000'
+; CHECK-NEXT: - SectionOffset: 59
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1064
; CHECK-NEXT: Content: 68656C6C6F0A00
+; CHECK-NEXT: - Type: CUSTOM
+
+
+; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \
+; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \
+; RUN: %t.hello.o
+; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX
+
+; CHECK-MAX: - Type: MEMORY
+; CHECK-MAX-NEXT: Memories:
+; CHECK-MAX-NEXT: - Flags: [ HAS_MAX ]
+; CHECK-MAX-NEXT: Initial: 0x00000002
+; CHECK-MAX-NEXT: Maximum: 0x00000002
+
+
+; RUN: wasm-ld --relocatable -o %t_reloc.wasm %t.o %t.hello.o
+; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC
+
+; RELOC: - Type: DATA
+; RELOC-NEXT: Relocations:
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000018
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
+; RELOC-NEXT: Index: 3
+; RELOC-NEXT: Offset: 0x0000002E
+; RELOC-NEXT: Addend: 4
+; RELOC-NEXT: Segments:
+; RELOC-NEXT: - SectionOffset: 6
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 0
+; RELOC-NEXT: Content: '01000000'
+; RELOC-NEXT: - SectionOffset: 15
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 16
+; RELOC-NEXT: Content: '03000000'
+; RELOC-NEXT: - SectionOffset: 24
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 24
+; RELOC-NEXT: Content: '28000000'
+; RELOC-NEXT: - SectionOffset: 33
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 28
+; RELOC-NEXT: Content: '0000000000000000'
+; RELOC-NEXT: - SectionOffset: 46
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 36
+; RELOC-NEXT: Content: '20000000'
+; RELOC-NEXT: - SectionOffset: 55
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 40
+; RELOC-NEXT: Content: 68656C6C6F0A00
-; CHECK: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 35
+; RELOC: SymbolTable:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: foo
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Segment: 0
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: aligned_bar
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Segment: 1
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: external_ref
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Segment: 2
+; RELOC-NEXT: Size: 4
+; RELOC: - Index: 6
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: hello_str
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Segment: 5
+; RELOC-NEXT: Size: 7
diff --git a/test/wasm/data-segment-merging.ll b/test/wasm/data-segment-merging.ll
new file mode 100644
index 000000000000..d0df84d0fc23
--- /dev/null
+++ b/test/wasm/data-segment-merging.ll
@@ -0,0 +1,48 @@
+target triple = "wasm32-unknown-unknown"
+
+@a = hidden global [6 x i8] c"hello\00", align 1
+@b = hidden global [8 x i8] c"goodbye\00", align 1
+@c = hidden global [9 x i8] c"whatever\00", align 1
+@d = hidden global i32 42, align 4
+
+; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o
+
+; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o
+; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE
+; MERGE: - Type: DATA
+; MERGE-NEXT: Segments:
+; MERGE-NEXT: - SectionOffset: 7
+; MERGE-NEXT: MemoryIndex: 0
+; MERGE-NEXT: Offset:
+; MERGE-NEXT: Opcode: I32_CONST
+; MERGE-NEXT: Value: 1024
+; MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+
+; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o
+; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE
+; SEPARATE: - Type: DATA
+; SEPARATE-NEXT: Segments:
+; SEPARATE-NEXT: - SectionOffset: 7
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1024
+; SEPARATE-NEXT: Content: 68656C6C6F00
+; SEPARATE-NEXT: - SectionOffset: 19
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1030
+; SEPARATE-NEXT: Content: 676F6F6462796500
+; SEPARATE-NEXT: - SectionOffset: 33
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1038
+; SEPARATE-NEXT: Content: '776861746576657200'
+; SEPARATE-NEXT: - SectionOffset: 48
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1048
+; SEPARATE-NEXT: Content: 2A000000
diff --git a/test/wasm/debuginfo.test b/test/wasm/debuginfo.test
new file mode 100644
index 000000000000..ce68a03bcbce
--- /dev/null
+++ b/test/wasm/debuginfo.test
@@ -0,0 +1,85 @@
+RUN: llc -filetype=obj %p/Inputs/debuginfo1.ll -o %t.debuginfo1.o
+RUN: llc -filetype=obj %p/Inputs/debuginfo2.ll -o %t.debuginfo2.o
+RUN: wasm-ld -o %t.wasm %t.debuginfo1.o %t.debuginfo2.o
+RUN: llvm-dwarfdump %t.wasm | FileCheck %s
+
+CHECK: file format WASM
+
+CHECK: .debug_info contents:
+CHECK: DW_TAG_compile_unit
+CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})")
+CHECK-NEXT: DW_AT_language (DW_LANG_C99)
+CHECK-NEXT: DW_AT_name ("hi.c")
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("test")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+CHECK-NEXT: DW_AT_prototyped (true)
+
+CHECK: DW_TAG_formal_parameter
+CHECK-NEXT: DW_AT_name ("t")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("_start")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (7)
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("int")
+CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
+CHECK-NEXT: DW_AT_byte_size (0x04)
+
+CHECK: DW_TAG_compile_unit
+CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})")
+CHECK-NEXT: DW_AT_language (DW_LANG_C99)
+CHECK-NEXT: DW_AT_name ("hi_foo.c")
+
+CHECK: DW_TAG_variable
+CHECK-NEXT: DW_AT_name ("y")
+CHECK-NEXT: DW_AT_type (0x00000097 "int[]")
+CHECK-NEXT: DW_AT_external (true)
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (1)
+CHECK: DW_AT_location (DW_OP_addr 0x400)
+
+CHECK: DW_TAG_array_type
+
+CHECK: DW_TAG_subrange_type
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("int")
+CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
+CHECK-NEXT: DW_AT_byte_size (0x04)
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("__ARRAY_SIZE_TYPE__")
+CHECK-NEXT: DW_AT_byte_size (0x08)
+CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned)
+
+CHECK: DW_TAG_variable
+CHECK-NEXT: DW_AT_name ("z")
+CHECK-NEXT: DW_AT_type (0x00000097 "int[]")
+CHECK-NEXT: DW_AT_external (true)
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (8)
+CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0)
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("foo")
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
+CHECK: DW_TAG_formal_parameter
+CHECK-NEXT: DW_AT_name ("p")
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
diff --git a/test/wasm/demangle.ll b/test/wasm/demangle.ll
new file mode 100644
index 000000000000..f0416bb6b32f
--- /dev/null
+++ b/test/wasm/demangle.ll
@@ -0,0 +1,17 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: not wasm-ld --undefined _Z3fooi \
+; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s
+
+; CHECK: error: undefined symbol: foo(int)
+
+; RUN: not wasm-ld --no-demangle --undefined _Z3fooi \
+; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s
+
+; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi
+
+target triple = "wasm32-unknown-unknown"
+
+define hidden void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
diff --git a/test/wasm/driver.ll b/test/wasm/driver.ll
new file mode 100644
index 000000000000..22e6bc180e4a
--- /dev/null
+++ b/test/wasm/driver.ll
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %s -o %t.o
+
+target triple = "wasm32-unknown-unknown"
+
+define hidden void @entry() local_unnamed_addr #0 {
+entry:
+ ret void
+}
+
+; RUN: not wasm-ld -o %t.exe 2>&1 | FileCheck -check-prefix=IN %s
+; IN: error: no input files
+
+; RUN: not wasm-ld %t.o 2>&1 | FileCheck -check-prefix=OUT %s
+; OUT: error: no output file specified
+
+; RUN: not wasm-ld 2>&1 | FileCheck -check-prefix=BOTH %s
+; BOTH: error: no input files
+; BOTH-NOT: error: no output file specified
+
+; RUN: not wasm-ld --export-table --import-table %t.o 2>&1 \
+; RUN: | FileCheck -check-prefix=TABLE %s
+; TABLE: error: --import-table and --export-table may not be used together
diff --git a/test/wasm/entry-signature.ll b/test/wasm/entry-signature.ll
new file mode 100644
index 000000000000..8e245b14e964
--- /dev/null
+++ b/test/wasm/entry-signature.ll
@@ -0,0 +1,10 @@
+; Verify that the entry point signauture can be flexible.
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t1.wasm %t.o
+
+target triple = "wasm32-unknown-unknown-wasm"
+
+define hidden i32 @_start(i32, i64) local_unnamed_addr #0 {
+entry:
+ ret i32 0
+}
diff --git a/test/wasm/entry.ll b/test/wasm/entry.ll
index 4749d8306651..30fff9a2bdcb 100644
--- a/test/wasm/entry.ll
+++ b/test/wasm/entry.ll
@@ -1,19 +1,50 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -e entry -o %t.wasm %t.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
-; RUN: lld -flavor wasm --entry=entry -o %t.wasm %t.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
+; RUN: llc -filetype=obj %s -o %t.o
-define void @entry() local_unnamed_addr #0 {
+target triple = "wasm32-unknown-unknown"
+
+define hidden void @entry() local_unnamed_addr #0 {
entry:
ret void
}
-; CHECK: - Type: EXPORT
-; CHECK: Exports:
-; CHECK: - Name: memory
-; CHECK: Kind: MEMORY
-; CHECK: Index: 0
-; CHECK: - Name: entry
-; CHECK: Kind: FUNCTION
-; CHECK: Index: 0
+; RUN: wasm-ld -e entry -o %t1.wasm %t.o
+; RUN: obj2yaml %t1.wasm | FileCheck %s
+; RUN: wasm-ld --entry=entry -o %t2.wasm %t.o
+; RUN: obj2yaml %t2.wasm | FileCheck %s
+
+; CHECK: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: entry
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Type:
+
+; The __wasm_call_ctors is somewhat special since its created by the linker.
+; Make sure we can use it as the entry point if we choose
+; RUN: wasm-ld --entry=__wasm_call_ctors -o %t3.wasm %t.o
+; RUN: obj2yaml %t3.wasm | FileCheck %s -check-prefix=CHECK-CTOR
+
+; CHECK-CTOR: - Type: EXPORT
+; CHECK-CTOR-NEXT: Exports:
+; CHECK-CTOR-NEXT: - Name: memory
+; CHECK-CTOR-NEXT: Kind: MEMORY
+; CHECK-CTOR-NEXT: Index: 0
+; CHECK-CTOR-NEXT: - Name: __wasm_call_ctors
+; CHECK-CTOR-NEXT: Kind: FUNCTION
+; CHECK-CTOR-NEXT: Index: 0
+; CHECK-CTOR-NEXT: - Name: __heap_base
+; CHECK-CTOR-NEXT: Kind: GLOBAL
+; CHECK-CTOR-NEXT: Index: 1
+; CHECK-CTOR-NEXT: - Name: __data_end
+; CHECK-CTOR-NEXT: Kind: GLOBAL
+; CHECK-CTOR-NEXT: Index: 2
+; CHECK-CTOR-NEXT: - Type:
diff --git a/test/wasm/export-all.ll b/test/wasm/export-all.ll
new file mode 100644
index 000000000000..34797aac76f7
--- /dev/null
+++ b/test/wasm/export-all.ll
@@ -0,0 +1,48 @@
+; RUN: llc -O0 -filetype=obj %s -o %t.o
+
+; RUN: wasm-ld -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; RUN: wasm-ld --export-all -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=EXPORT
+
+; RUN: wasm-ld --export-all --no-gc-sections -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=EXPORT
+
+; Verify the --export-all flag exports hidden symbols
+
+target triple = "wasm32-unknown-unknown"
+
+define internal void @internal_func() local_unnamed_addr {
+entry:
+ ret void
+}
+
+define hidden void @bar() local_unnamed_addr {
+entry:
+ ret void
+}
+
+define hidden void @foo() local_unnamed_addr {
+entry:
+ ret void
+}
+
+define hidden void @_start() local_unnamed_addr {
+entry:
+ call void @foo()
+ call void @internal_func()
+ ret void
+}
+
+; CHECK: - Type: EXPORT
+; CHECK: - Name: _start
+; CHECK-NOT: - Name: bar
+; CHECK-NOT: - Name: foo
+; CHECK-NOT: - Name: internal_func
+
+; EXPORT: - Type: EXPORT
+; EXPORT: - Name: _start
+; EXPORT: - Name: bar
+; EXPORT: - Name: foo
+; EXPORT-NOT: - Name: internal_func
diff --git a/test/wasm/export-table.test b/test/wasm/export-table.test
new file mode 100644
index 000000000000..58775b928f7f
--- /dev/null
+++ b/test/wasm/export-table.test
@@ -0,0 +1,19 @@
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --export-table -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --export-table flag creates a table export
+
+# CHECK: - Type: TABLE
+# CHECK-NEXT: Tables:
+# CHECK-NEXT: - ElemType: ANYFUNC
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Flags: [ HAS_MAX ]
+# CHECK-NEXT: Initial: 0x00000001
+# CHECK-NEXT: Maximum: 0x00000001
+# CHECK-NEXT: - Type:
+# CHECK: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK: - Name: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Index: 0
diff --git a/test/wasm/export.ll b/test/wasm/export.ll
new file mode 100644
index 000000000000..16b2b6ca57cc
--- /dev/null
+++ b/test/wasm/export.ll
@@ -0,0 +1,37 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: not wasm-ld --export=missing -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s
+; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define hidden i32 @hidden_function() local_unnamed_addr {
+entry:
+ ret i32 0
+}
+
+define void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
+
+; CHECK-ERROR: error: symbol exported via --export not found: missing
+
+; CHECK: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: hidden_function
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Type: CODE
diff --git a/test/wasm/fatal-warnings.ll b/test/wasm/fatal-warnings.ll
new file mode 100644
index 000000000000..0007dc203f02
--- /dev/null
+++ b/test/wasm/fatal-warnings.ll
@@ -0,0 +1,17 @@
+; RUN: llc -filetype=obj %s -o %t.main.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: lld -flavor wasm -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN
+; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL
+
+; CHECK-WARN: warning: function signature mismatch: ret32
+; CHECK-FATAL: error: function signature mismatch: ret32
+
+target triple = "wasm32-unknown-unknown"
+
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+ %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2
+ ret void
+}
+
+declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
diff --git a/test/wasm/function-imports-first.ll b/test/wasm/function-imports-first.ll
index eda1302703c0..00c73741b066 100644
--- a/test/wasm/function-imports-first.ll
+++ b/test/wasm/function-imports-first.ll
@@ -1,8 +1,10 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t.o %t.ret32.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
entry:
@@ -22,21 +24,25 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - F32
; CHECK: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ]
; CHECK: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 43000000001081808080001A0B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 43000000001082808080001A0B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41000B
; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 0
-; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: _start
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: ret32
; CHECK-NEXT: ...
diff --git a/test/wasm/function-imports.ll b/test/wasm/function-imports.ll
index 072554d8400a..a2c6405b0565 100644
--- a/test/wasm/function-imports.ll
+++ b/test/wasm/function-imports.ll
@@ -1,8 +1,10 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t.ret32.o %t.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.ret32.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
entry:
@@ -16,22 +18,25 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
-; CHECK-NEXT: - F32
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - F32
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ]
; CHECK: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK: - Locals:
-; CHECK: - Locals:
+; CHECK: - Index: 0
+; CHECK: - Index: 1
+; CHECK: - Index: 2
; CHECK: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: ret32
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: ret32
+; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: _start
; CHECK-NEXT: ...
diff --git a/test/wasm/function-index.test b/test/wasm/function-index.test
index c65c560d11c8..82f5d0cfb245 100644
--- a/test/wasm/function-index.test
+++ b/test/wasm/function-index.test
@@ -1,6 +1,6 @@
-# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret64.ll -o %t.ret64.o
-# RUN: lld -flavor wasm -r -o %t.wasm %t.ret32.o %t.ret64.o
+# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: llc -filetype=obj %p/Inputs/ret64.ll -o %t.ret64.o
+# RUN: wasm-ld -r -o %t.wasm %t.ret32.o %t.ret64.o
# RUN: obj2yaml %t.wasm | FileCheck %s
CHECK: Sections:
diff --git a/test/wasm/gc-imports.ll b/test/wasm/gc-imports.ll
new file mode 100644
index 000000000000..fbcb74dbdd3e
--- /dev/null
+++ b/test/wasm/gc-imports.ll
@@ -0,0 +1,93 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: yaml2obj %S/Inputs/undefined-globals.yaml -o %t_globals.o
+; RUN: wasm-ld --allow-undefined -o %t1.wasm %t.o %t_globals.o
+
+target triple = "wasm32-unknown-unknown"
+
+declare i64 @unused_undef_function(i64 %arg)
+
+declare i32 @used_undef_function()
+
+declare i64 @use_undef_global()
+
+define hidden void @foo() {
+entry:
+ call i64 @unused_undef_function(i64 0)
+ ret void
+}
+
+define hidden void @_start() {
+entry:
+ call i32 @used_undef_function()
+ call i64 @use_undef_global()
+ ret void
+}
+
+; RUN: obj2yaml %t1.wasm | FileCheck %s
+
+; CHECK: - Type: IMPORT
+; CHECK-NEXT: Imports:
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: used_undef_function
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 0
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: used_undef_global
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I64
+; CHECK-NEXT: GlobalMutable: true
+; CHECK-NEXT: - Type:
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: used_undef_function
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: use_undef_global
+; CHECK-NEXT: ...
+
+; RUN: wasm-ld --no-gc-sections --allow-undefined \
+; RUN: -o %t1.no-gc.wasm %t.o %t_globals.o
+; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC
+
+; NO-GC: - Type: IMPORT
+; NO-GC-NEXT: Imports:
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: unused_undef_function
+; NO-GC-NEXT: Kind: FUNCTION
+; NO-GC-NEXT: SigIndex: 0
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: used_undef_function
+; NO-GC-NEXT: Kind: FUNCTION
+; NO-GC-NEXT: SigIndex: 1
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: unused_undef_global
+; NO-GC-NEXT: Kind: GLOBAL
+; NO-GC-NEXT: GlobalType: I64
+; NO-GC-NEXT: GlobalMutable: true
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: used_undef_global
+; NO-GC-NEXT: Kind: GLOBAL
+; NO-GC-NEXT: GlobalType: I64
+; NO-GC-NEXT: GlobalMutable: true
+; NO-GC-NEXT: - Type:
+; NO-GC: - Type: CUSTOM
+; NO-GC-NEXT: Name: name
+; NO-GC-NEXT: FunctionNames:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: Name: unused_undef_function
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: Name: used_undef_function
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: Name: __wasm_call_ctors
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: Name: foo
+; NO-GC-NEXT: - Index: 4
+; NO-GC-NEXT: Name: _start
+; NO-GC-NEXT: - Index: 5
+; NO-GC-NEXT: Name: use_undef_global
+; NO-GC-NEXT: ...
diff --git a/test/wasm/gc-sections.ll b/test/wasm/gc-sections.ll
new file mode 100644
index 000000000000..57b69738a6f3
--- /dev/null
+++ b/test/wasm/gc-sections.ll
@@ -0,0 +1,153 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: yaml2obj %S/Inputs/globals.yaml -o %t_globals.o
+; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o %t_globals.o | \
+; RUN: FileCheck %s -check-prefix=PRINT-GC
+; PRINT-GC: removing unused section {{.*}}:(unused_function)
+; PRINT-GC-NOT: removing unused section {{.*}}:(used_function)
+; PRINT-GC: removing unused section {{.*}}:(.data.unused_data)
+; PRINT-GC-NOT: removing unused section {{.*}}:(.data.used_data)
+; PRINT-GC: removing unused section {{.*}}:(unused_global)
+; PRINT-GC-NOT: removing unused section {{.*}}:(used_global)
+
+target triple = "wasm32-unknown-unknown"
+
+@unused_data = hidden global i64 1, align 4
+@used_data = hidden global i32 2, align 4
+
+define hidden i64 @unused_function(i64 %arg) {
+ %1 = load i64, i64* @unused_data, align 4
+ ret i64 %1
+}
+
+define hidden i32 @used_function() {
+ %1 = load i32, i32* @used_data, align 4
+ ret i32 %1
+}
+
+declare i64 @use_global()
+
+define hidden void @_start() {
+entry:
+ call i32 @used_function()
+ call i64 @use_global()
+ ret void
+}
+
+; RUN: obj2yaml %t1.wasm | FileCheck %s
+
+; CHECK: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: ReturnType: I64
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+
+; CHECK: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I64
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I64_CONST
+; CHECK-NEXT: Value: 456
+
+; CHECK: - Type: DATA
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - SectionOffset: 7
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: Content: '02000000'
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: used_function
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: use_global
+; CHECK-NEXT: ...
+
+; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \
+; RUN: %t.o %t_globals.o
+; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC
+
+; NO-GC: - Type: TYPE
+; NO-GC-NEXT: Signatures:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: ReturnType: NORESULT
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: ReturnType: I64
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - I64
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: ReturnType: I32
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: ReturnType: I64
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Type: FUNCTION
+
+; NO-GC: - Type: GLOBAL
+; NO-GC-NEXT: Globals:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: Type: I32
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I32_CONST
+; NO-GC-NEXT: Value: 66576
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: Type: I64
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I64_CONST
+; NO-GC-NEXT: Value: 123
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: Type: I64
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I64_CONST
+; NO-GC-NEXT: Value: 456
+
+; NO-GC: - Type: DATA
+; NO-GC-NEXT: Segments:
+; NO-GC-NEXT: - SectionOffset: 7
+; NO-GC-NEXT: MemoryIndex: 0
+; NO-GC-NEXT: Offset:
+; NO-GC-NEXT: Opcode: I32_CONST
+; NO-GC-NEXT: Value: 1024
+; NO-GC-NEXT: Content: '010000000000000002000000'
+; NO-GC-NEXT: - Type: CUSTOM
+; NO-GC-NEXT: Name: name
+; NO-GC-NEXT: FunctionNames:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: Name: __wasm_call_ctors
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: Name: unused_function
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: Name: used_function
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: Name: _start
+; NO-GC-NEXT: - Index: 4
+; NO-GC-NEXT: Name: use_global
+; NO-GC-NEXT: ...
+
+; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR
+; CHECK-ERROR: error: -r and --gc-sections may not be used together
diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test
index 9713e6cd5a17..49bf06b74832 100644
--- a/test/wasm/import-memory.test
+++ b/test/wasm/import-memory.test
@@ -1,13 +1,33 @@
-# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-# RUN: lld -flavor wasm -entry ret32 --import-memory -o %t.wasm %t.ret32.o
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --import-memory -o %t.wasm %t.start.o
# RUN: obj2yaml %t.wasm | FileCheck %s
# Verify the --import-memory flag creates a memory import
# CHECK: - Type: IMPORT
-# CHECK-NEXT: Imports:
+# CHECK-NEXT: Imports:
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: memory
# CHECK-NEXT: Kind: MEMORY
-# CHECK-NEXT: Memory:
+# CHECK-NEXT: Memory:
# CHECK-NEXT: Initial: 0x00000002
+# CHECK-NEXT: - Type:
+
+
+
+# RUN: wasm-ld --import-memory --initial-memory=262144 \
+# RUN: --max-memory=327680 -o %t.max.wasm %t.start.o
+# RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-MAX %s
+
+# Verify the --initial-memory and --max-memory arguments work with imports
+
+# CHECK-MAX: - Type: IMPORT
+# CHECK-MAX-NEXT: Imports:
+# CHECK-MAX-NEXT: - Module: env
+# CHECK-MAX-NEXT: Field: memory
+# CHECK-MAX-NEXT: Kind: MEMORY
+# CHECK-MAX-NEXT: Memory:
+# CHECK-MAX-NEXT: Flags: [ HAS_MAX ]
+# CHECK-MAX-NEXT: Initial: 0x00000004
+# CHECK-MAX-NEXT: Maximum: 0x00000005
+# CHECK-MAX-NEXT: - Type:
diff --git a/test/wasm/import-table.test b/test/wasm/import-table.test
new file mode 100644
index 000000000000..eb767090292a
--- /dev/null
+++ b/test/wasm/import-table.test
@@ -0,0 +1,18 @@
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --import-table -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --import-table flag creates a table import
+
+# CHECK: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: ElemType: ANYFUNC
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Flags: [ HAS_MAX ]
+# CHECK-NEXT: Initial: 0x00000001
+# CHECK-NEXT: Maximum: 0x00000001
+
diff --git a/test/wasm/init-fini.ll b/test/wasm/init-fini.ll
index bdae29811d8e..9a7f5357ef01 100644
--- a/test/wasm/init-fini.ll
+++ b/test/wasm/init-fini.ll
@@ -1,5 +1,7 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llc -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o
+
+target triple = "wasm32-unknown-unknown"
define hidden void @func1() {
entry:
@@ -11,89 +13,316 @@ entry:
ret void
}
-define void @__cxa_atexit() {
+define hidden void @func3() {
+entry:
ret void
}
+define hidden void @func4() {
+entry:
+ ret void
+}
+
+declare hidden void @externCtor()
+declare hidden void @externDtor()
+
+define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) {
+ ret i32 0
+}
+
define hidden void @_start() {
entry:
ret void
}
-@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }]
+@llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [
+ { i32, void ()*, i8* } { i32 1001, void ()* @func1, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @func1, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @func2, i8* null },
+ { i32, void ()*, i8* } { i32 4000, void ()* @externCtor, i8* null }
+]
-@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }]
+@llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [
+ { i32, void ()*, i8* } { i32 1001, void ()* @func3, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @func3, i8* null },
+ { i32, void ()*, i8* } { i32 101, void ()* @func4, i8* null },
+ { i32, void ()*, i8* } { i32 4000, void ()* @externDtor, i8* null }
+]
-; RUN: lld -flavor wasm %t.o %t.global-ctor-dtor.o -o %t.wasm
+; RUN: wasm-ld --allow-undefined %t.o %t.global-ctor-dtor.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
-; CHECK: Name: linking
-; CHECK-NEXT: DataSize: 0
+; CHECK: - Type: IMPORT
+; CHECK-NEXT: Imports:
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: externDtor
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 0
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: externCtor
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 0
+; CHECK: - Type: ELEM
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: Functions: [ 9, 11, 13, 17, 19, 21 ]
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 10031004100A100F1012100F10141003100C100F10161001100E0B
+; CHECK: - Index: 22
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 024041868080800041004180888080001087808080000D000F0B00000B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
-; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: func1
+; CHECK-NEXT: Name: externDtor
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: func2
+; CHECK-NEXT: Name: externCtor
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: __cxa_atexit
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 3
-; CHECK-NEXT: Name: _start
+; CHECK-NEXT: Name: func1
; CHECK-NEXT: - Index: 4
-; CHECK-NEXT: Name: .Lcall_dtors
+; CHECK-NEXT: Name: func2
; CHECK-NEXT: - Index: 5
-; CHECK-NEXT: Name: .Lregister_call_dtors
+; CHECK-NEXT: Name: func3
; CHECK-NEXT: - Index: 6
-; CHECK-NEXT: Name: .Lbitcast
+; CHECK-NEXT: Name: func4
; CHECK-NEXT: - Index: 7
-; CHECK-NEXT: Name: myctor
+; CHECK-NEXT: Name: __cxa_atexit
; CHECK-NEXT: - Index: 8
-; CHECK-NEXT: Name: mydtor
+; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 9
-; CHECK-NEXT: Name: .Lcall_dtors
+; CHECK-NEXT: Name: .Lcall_dtors.101
; CHECK-NEXT: - Index: 10
-; CHECK-NEXT: Name: .Lregister_call_dtors
+; CHECK-NEXT: Name: .Lregister_call_dtors.101
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Name: .Lcall_dtors.1001
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Name: .Lregister_call_dtors.1001
+; CHECK-NEXT: - Index: 13
+; CHECK-NEXT: Name: .Lcall_dtors.4000
+; CHECK-NEXT: - Index: 14
+; CHECK-NEXT: Name: .Lregister_call_dtors.4000
+; CHECK-NEXT: - Index: 15
+; CHECK-NEXT: Name: myctor
+; CHECK-NEXT: - Index: 16
+; CHECK-NEXT: Name: mydtor
+; CHECK-NEXT: - Index: 17
+; CHECK-NEXT: Name: .Lcall_dtors.101
+; CHECK-NEXT: - Index: 18
+; CHECK-NEXT: Name: .Lregister_call_dtors.101
+; CHECK-NEXT: - Index: 19
+; CHECK-NEXT: Name: .Lcall_dtors.202
+; CHECK-NEXT: - Index: 20
+; CHECK-NEXT: Name: .Lregister_call_dtors.202
+; CHECK-NEXT: - Index: 21
+; CHECK-NEXT: Name: .Lcall_dtors.2002
+; CHECK-NEXT: - Index: 22
+; CHECK-NEXT: Name: .Lregister_call_dtors.2002
; CHECK-NEXT: ...
-; RUN: lld -flavor wasm -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm
+; RUN: wasm-ld -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm
; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s
-; RELOC: Name: linking
-; RELOC-NEXT: DataSize: 0
-; RELOC-NEXT: InitFunctions:
-; RELOC-NEXT: - Priority: 65535
-; RELOC-NEXT: FunctionIndex: 0
-; RELOC-NEXT: - Priority: 65535
-; RELOC-NEXT: FunctionIndex: 5
-; RELOC-NEXT: - Priority: 65535
-; RELOC-NEXT: FunctionIndex: 7
-; RELOC-NEXT: - Priority: 65535
-; RELOC-NEXT: FunctionIndex: 10
-; RELOC-NEXT: - Type: CUSTOM
-; RELOC-NEXT: Name: name
-; RELOC-NEXT: FunctionNames:
+; RELOC: SymbolTable:
; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func1
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 2
; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func2
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 3
; RELOC-NEXT: - Index: 2
-; RELOC-NEXT: Name: __cxa_atexit
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: func3
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 4
; RELOC-NEXT: - Index: 3
-; RELOC-NEXT: Name: _start
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: func4
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 5
; RELOC-NEXT: - Index: 4
-; RELOC-NEXT: Name: .Lcall_dtors
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: __cxa_atexit
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 6
; RELOC-NEXT: - Index: 5
-; RELOC-NEXT: Name: .Lregister_call_dtors
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: _start
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 7
; RELOC-NEXT: - Index: 6
-; RELOC-NEXT: Name: .Lbitcast
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.101
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 8
; RELOC-NEXT: - Index: 7
-; RELOC-NEXT: Name: myctor
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.101
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 9
; RELOC-NEXT: - Index: 8
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: __dso_handle
+; RELOC-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, UNDEFINED ]
+; RELOC-NEXT: - Index: 9
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.1001
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 10
+; RELOC-NEXT: - Index: 10
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.1001
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 11
+; RELOC-NEXT: - Index: 11
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.4000
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 12
+; RELOC-NEXT: - Index: 12
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: externDtor
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+; RELOC-NEXT: Function: 0
+; RELOC-NEXT: - Index: 13
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.4000
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 13
+; RELOC-NEXT: - Index: 14
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: externCtor
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+; RELOC-NEXT: Function: 1
+; RELOC-NEXT: - Index: 15
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: myctor
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 14
+; RELOC-NEXT: - Index: 16
+; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: mydtor
+; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; RELOC-NEXT: Function: 15
+; RELOC-NEXT: - Index: 17
+; RELOC-NEXT: Kind: GLOBAL
+; RELOC-NEXT: Name: __stack_pointer
+; RELOC-NEXT: Flags: [ UNDEFINED ]
+; RELOC-NEXT: Global: 0
+; RELOC-NEXT: - Index: 18
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.101
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 16
+; RELOC-NEXT: - Index: 19
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.101
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 17
+; RELOC-NEXT: - Index: 20
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.202
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 18
+; RELOC-NEXT: - Index: 21
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.202
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 19
+; RELOC-NEXT: - Index: 22
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lcall_dtors.2002
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 20
+; RELOC-NEXT: - Index: 23
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: .Lregister_call_dtors.2002
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 21
+; RELOC-NEXT: InitFunctions:
+; RELOC-NEXT: - Priority: 101
+; RELOC-NEXT: Symbol: 0
+; RELOC-NEXT: - Priority: 101
+; RELOC-NEXT: Symbol: 1
+; RELOC-NEXT: - Priority: 101
+; RELOC-NEXT: Symbol: 7
+; RELOC-NEXT: - Priority: 101
+; RELOC-NEXT: Symbol: 15
+; RELOC-NEXT: - Priority: 101
+; RELOC-NEXT: Symbol: 19
+; RELOC-NEXT: - Priority: 202
+; RELOC-NEXT: Symbol: 15
+; RELOC-NEXT: - Priority: 202
+; RELOC-NEXT: Symbol: 21
+; RELOC-NEXT: - Priority: 1001
+; RELOC-NEXT: Symbol: 0
+; RELOC-NEXT: - Priority: 1001
+; RELOC-NEXT: Symbol: 10
+; RELOC-NEXT: - Priority: 2002
+; RELOC-NEXT: Symbol: 15
+; RELOC-NEXT: - Priority: 2002
+; RELOC-NEXT: Symbol: 23
+; RELOC-NEXT: - Priority: 4000
+; RELOC-NEXT: Symbol: 14
+; RELOC-NEXT: - Priority: 4000
+; RELOC-NEXT: Symbol: 13
+; RELOC-NEXT: - Type: CUSTOM
+; RELOC-NEXT: Name: name
+; RELOC-NEXT: FunctionNames:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Name: externDtor
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Name: externCtor
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Name: func1
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Name: func2
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Name: func3
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Name: func4
+; RELOC-NEXT: - Index: 6
+; RELOC-NEXT: Name: __cxa_atexit
+; RELOC-NEXT: - Index: 7
+; RELOC-NEXT: Name: _start
+; RELOC-NEXT: - Index: 8
+; RELOC-NEXT: Name: .Lcall_dtors.101
; RELOC-NEXT: - Index: 9
-; RELOC-NEXT: Name: .Lcall_dtors
+; RELOC-NEXT: Name: .Lregister_call_dtors.101
; RELOC-NEXT: - Index: 10
-; RELOC-NEXT: Name: .Lregister_call_dtors
+; RELOC-NEXT: Name: .Lcall_dtors.1001
+; RELOC-NEXT: - Index: 11
+; RELOC-NEXT: Name: .Lregister_call_dtors.1001
+; RELOC-NEXT: - Index: 12
+; RELOC-NEXT: Name: .Lcall_dtors.4000
+; RELOC-NEXT: - Index: 13
+; RELOC-NEXT: Name: .Lregister_call_dtors.4000
+; RELOC-NEXT: - Index: 14
+; RELOC-NEXT: Name: myctor
+; RELOC-NEXT: - Index: 15
+; RELOC-NEXT: Name: mydtor
+; RELOC-NEXT: - Index: 16
+; RELOC-NEXT: Name: .Lcall_dtors.101
+; RELOC-NEXT: - Index: 17
+; RELOC-NEXT: Name: .Lregister_call_dtors.101
+; RELOC-NEXT: - Index: 18
+; RELOC-NEXT: Name: .Lcall_dtors.202
+; RELOC-NEXT: - Index: 19
+; RELOC-NEXT: Name: .Lregister_call_dtors.202
+; RELOC-NEXT: - Index: 20
+; RELOC-NEXT: Name: .Lcall_dtors.2002
+; RELOC-NEXT: - Index: 21
+; RELOC-NEXT: Name: .Lregister_call_dtors.2002
; RELOC-NEXT: ...
diff --git a/test/wasm/invalid-stack-size.test b/test/wasm/invalid-stack-size.test
index 484bbd3ca2c8..90c9fda113e6 100644
--- a/test/wasm/invalid-stack-size.test
+++ b/test/wasm/invalid-stack-size.test
@@ -1,9 +1,4 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %s -o %t.o
-; RUN: not lld -flavor wasm -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s
-
-define i32 @_start() local_unnamed_addr #1 {
-entry:
- ret i32 0
-}
+; RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
+; RUN: not wasm-ld -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s
; CHECK: error: stack size must be 16-byte aligned
diff --git a/test/wasm/load-undefined.ll b/test/wasm/load-undefined.ll
deleted file mode 100644
index f979c9acb517..000000000000
--- a/test/wasm/load-undefined.ll
+++ /dev/null
@@ -1,38 +0,0 @@
-; Verify that the -u / --undefined option is able to pull in symbols from
-; an archive, and doesn't error when uses to pull in a symbol already loaded.
-;
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret64.ll -o %t.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret32.ll -o %t2.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t3.o
-; RUN: llvm-ar rcs %t2.a %t2.o
-; RUN: lld -flavor wasm %t3.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64
-; RUN: obj2yaml %t.wasm | FileCheck %s
-
-define i32 @_start() local_unnamed_addr {
-entry:
- ret i32 1
-}
-
-; CHECK: - Type: EXPORT
-; CHECK-NEXT: Exports:
-; CHECK-NEXT: - Name: memory
-; CHECK-NEXT: Kind: MEMORY
-; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: _start
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: ret32
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
-; CHECK-NEXT: - Name: ret64
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
-; CHECK-NEXT: - Type:
-
-
-; Verify that referencing a symbol that doesn't exist won't work
-; RUN: not lld -flavor wasm %t3.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s
-; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist
-
-; RUN: not lld -flavor wasm %t3.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s
-; CHECK-UNDEFINED2: function forced with --undefined not found: symboldoesnotexist
diff --git a/test/wasm/load-undefined.test b/test/wasm/load-undefined.test
new file mode 100644
index 000000000000..160cb485ac34
--- /dev/null
+++ b/test/wasm/load-undefined.test
@@ -0,0 +1,40 @@
+; Verify that the -u / --undefined option is able to pull in symbols from
+; an archive, and doesn't error when uses to pull in a symbol already loaded.
+;
+; RUN: llc -filetype=obj %S/Inputs/ret64.ll -o %t.o
+; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t2.o
+; RUN: llc -filetype=obj %S/Inputs/start.ll -o %t.start.o
+; RUN: llvm-ar rcs %t2.a %t2.o
+; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64
+; RUN: obj2yaml %t.wasm | FileCheck %s
+; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t2.wasm
+; RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefix=NO-LOAD
+
+; CHECK: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: ret32
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: ret64
+; CHECK-NEXT: ...
+
+; NO-LOAD: Name: name
+; NO-LOAD-NEXT: FunctionNames:
+; NO-LOAD-NEXT: - Index: 0
+; NO-LOAD-NEXT: Name: __wasm_call_ctors
+; NO-LOAD-NEXT: - Index: 1
+; NO-LOAD-NEXT: Name: _start
+; NO-LOAD-NEXT: - Index: 2
+; NO-LOAD-NEXT: Name: ret64
+; NO-LOAD-NEXT: ...
+
+; Verify that referencing a symbol that doesn't exist won't work
+; RUN: not wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s
+; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist
+
+; RUN: not wasm-ld %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s
+; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist
diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll
index e88f656e14c6..5471466eb076 100644
--- a/test/wasm/local-symbols.ll
+++ b/test/wasm/local-symbols.ll
@@ -1,18 +1,22 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
@foo = default global i32 1, align 4
@bar = internal default global i32 3, align 4
define internal i32 @baz() local_unnamed_addr {
entry:
- ret i32 2
+ %0 = load i32, i32* @bar, align 4
+ ret i32 %0
}
-define i32 @_start() local_unnamed_addr {
+define void @_start() local_unnamed_addr {
entry:
- ret i32 1
+ call i32 @baz()
+ ret void
}
; CHECK: --- !WASM
@@ -22,10 +26,13 @@ entry:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 0 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@@ -38,25 +45,58 @@ entry:
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1032
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: foo
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 41020B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 41010B
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4100280284888080000B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1081808080001A0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@@ -66,13 +106,12 @@ entry:
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: Content: '0100000003000000'
; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 8
-; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: baz
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: baz
+; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: _start
; CHECK-NEXT: ...
diff --git a/test/wasm/locals-duplicate.test b/test/wasm/locals-duplicate.test
new file mode 100644
index 000000000000..3c67cdd8cfa4
--- /dev/null
+++ b/test/wasm/locals-duplicate.test
@@ -0,0 +1,568 @@
+; RUN: llc -filetype=obj %p/Inputs/locals-duplicate1.ll -o %t1.o
+; RUN: llc -filetype=obj %p/Inputs/locals-duplicate2.ll -o %t2.o
+; RUN: wasm-ld --no-entry -o %t.wasm %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; CHECK: --- !WASM
+; CHECK-NEXT: FileHeader:
+; CHECK-NEXT: Version: 0x00000001
+; CHECK-NEXT: Sections:
+; CHECK-NEXT: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+; CHECK-NEXT: 1, 1, 1 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; CHECK-NEXT: Initial: 0x00000007
+; CHECK-NEXT: Maximum: 0x00000007
+; CHECK-NEXT: - Type: MEMORY
+; CHECK-NEXT: Memories:
+; CHECK-NEXT: - Initial: 0x00000002
+; CHECK-NEXT: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66592
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66592
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1048
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1028
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1036
+; CHECK-NEXT: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: colliding_func2
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: get_global1A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Name: get_global2A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 5
+; CHECK-NEXT: - Name: colliding_global2
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: get_global3A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 6
+; CHECK-NEXT: - Name: get_func1A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 7
+; CHECK-NEXT: - Name: get_func2A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 8
+; CHECK-NEXT: - Name: get_func3A
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 9
+; CHECK-NEXT: - Name: colliding_func1
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 10
+; CHECK-NEXT: - Name: get_global1B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 13
+; CHECK-NEXT: - Name: colliding_global1
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Name: get_global2B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 14
+; CHECK-NEXT: - Name: get_global3B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 15
+; CHECK-NEXT: - Name: get_func1B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 16
+; CHECK-NEXT: - Name: get_func2B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 17
+; CHECK-NEXT: - Name: get_func3B
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 18
+; CHECK-NEXT: - Type: ELEM
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: Functions: [ 1, 2, 3, 10, 11, 12 ]
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4180888080000B
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4184888080000B
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4188888080000B
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4181808080000B
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4182808080000B
+; CHECK-NEXT: - Index: 9
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4183808080000B
+; CHECK-NEXT: - Index: 10
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Index: 13
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 418C888080000B
+; CHECK-NEXT: - Index: 14
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4190888080000B
+; CHECK-NEXT: - Index: 15
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4194888080000B
+; CHECK-NEXT: - Index: 16
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4184808080000B
+; CHECK-NEXT: - Index: 17
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4185808080000B
+; CHECK-NEXT: - Index: 18
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4186808080000B
+; CHECK-NEXT: - Type: DATA
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - SectionOffset: 7
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: Content: '000000000000000000000000000000000000000000000000'
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: colliding_func1
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: colliding_func2
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: colliding_func3
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Name: get_global1A
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: get_global2A
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Name: get_global3A
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Name: get_func1A
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Name: get_func2A
+; CHECK-NEXT: - Index: 9
+; CHECK-NEXT: Name: get_func3A
+; CHECK-NEXT: - Index: 10
+; CHECK-NEXT: Name: colliding_func1
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Name: colliding_func2
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Name: colliding_func3
+; CHECK-NEXT: - Index: 13
+; CHECK-NEXT: Name: get_global1B
+; CHECK-NEXT: - Index: 14
+; CHECK-NEXT: Name: get_global2B
+; CHECK-NEXT: - Index: 15
+; CHECK-NEXT: Name: get_global3B
+; CHECK-NEXT: - Index: 16
+; CHECK-NEXT: Name: get_func1B
+; CHECK-NEXT: - Index: 17
+; CHECK-NEXT: Name: get_func2B
+; CHECK-NEXT: - Index: 18
+; CHECK-NEXT: Name: get_func3B
+; CHECK-NEXT: ...
+
+
+; RUN: wasm-ld -r --no-entry -o %t.reloc.wasm %t1.o %t2.o
+; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s
+
+; RELOC: --- !WASM
+; RELOC-NEXT: FileHeader:
+; RELOC-NEXT: Version: 0x00000001
+; RELOC-NEXT: Sections:
+; RELOC-NEXT: - Type: TYPE
+; RELOC-NEXT: Signatures:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: ReturnType: I32
+; RELOC-NEXT: ParamTypes:
+; RELOC-NEXT: - Type: FUNCTION
+; RELOC-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+; RELOC-NEXT: 0, 0 ]
+; RELOC-NEXT: - Type: TABLE
+; RELOC-NEXT: Tables:
+; RELOC-NEXT: - ElemType: ANYFUNC
+; RELOC-NEXT: Limits:
+; RELOC-NEXT: Flags: [ HAS_MAX ]
+; RELOC-NEXT: Initial: 0x00000007
+; RELOC-NEXT: Maximum: 0x00000007
+; RELOC-NEXT: - Type: MEMORY
+; RELOC-NEXT: Memories:
+; RELOC-NEXT: - Initial: 0x00000001
+; RELOC-NEXT: - Type: ELEM
+; RELOC-NEXT: Segments:
+; RELOC-NEXT: - Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 1
+; RELOC-NEXT: Functions: [ 0, 1, 2, 9, 10, 11 ]
+; RELOC-NEXT: - Type: CODE
+; RELOC-NEXT: Relocations:
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Offset: 0x00000013
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x0000001C
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 8
+; RELOC-NEXT: Offset: 0x00000025
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 0
+; RELOC-NEXT: Offset: 0x0000002E
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 1
+; RELOC-NEXT: Offset: 0x00000037
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 2
+; RELOC-NEXT: Offset: 0x00000040
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 16
+; RELOC-NEXT: Offset: 0x00000058
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 18
+; RELOC-NEXT: Offset: 0x00000061
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; RELOC-NEXT: Index: 20
+; RELOC-NEXT: Offset: 0x0000006A
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 12
+; RELOC-NEXT: Offset: 0x00000073
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 13
+; RELOC-NEXT: Offset: 0x0000007C
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 14
+; RELOC-NEXT: Offset: 0x00000085
+; RELOC-NEXT: Functions:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4180808080000B
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4188808080000B
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4190808080000B
+; RELOC-NEXT: - Index: 6
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4181808080000B
+; RELOC-NEXT: - Index: 7
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4182808080000B
+; RELOC-NEXT: - Index: 8
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4183808080000B
+; RELOC-NEXT: - Index: 9
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 10
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 11
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41020B
+; RELOC-NEXT: - Index: 12
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4184808080000B
+; RELOC-NEXT: - Index: 13
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 418C808080000B
+; RELOC-NEXT: - Index: 14
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4194808080000B
+; RELOC-NEXT: - Index: 15
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4184808080000B
+; RELOC-NEXT: - Index: 16
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4185808080000B
+; RELOC-NEXT: - Index: 17
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 4186808080000B
+; RELOC-NEXT: - Type: DATA
+; RELOC-NEXT: Segments:
+; RELOC-NEXT: - SectionOffset: 6
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 0
+; RELOC-NEXT: Content: '0000000000000000'
+; RELOC-NEXT: - SectionOffset: 19
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 8
+; RELOC-NEXT: Content: '0000000000000000'
+; RELOC-NEXT: - SectionOffset: 32
+; RELOC-NEXT: MemoryIndex: 0
+; RELOC-NEXT: Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 16
+; RELOC-NEXT: Content: '0000000000000000'
+; RELOC-NEXT: - Type: CUSTOM
+; RELOC-NEXT: Name: linking
+; RELOC-NEXT: Version: 1
+; RELOC-NEXT: SymbolTable:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func1
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 0
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func2
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 1
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func3
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 2
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global1A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 3
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global1
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Segment: 0
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global2A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 4
+; RELOC-NEXT: - Index: 6
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global2
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Segment: 1
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 7
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global3A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 5
+; RELOC-NEXT: - Index: 8
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global3
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Segment: 2
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 9
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func1A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 6
+; RELOC-NEXT: - Index: 10
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func2A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 7
+; RELOC-NEXT: - Index: 11
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func3A
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 8
+; RELOC-NEXT: - Index: 12
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func1
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 9
+; RELOC-NEXT: - Index: 13
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func2
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 10
+; RELOC-NEXT: - Index: 14
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: colliding_func3
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Function: 11
+; RELOC-NEXT: - Index: 15
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global1B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 12
+; RELOC-NEXT: - Index: 16
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global1
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Segment: 0
+; RELOC-NEXT: Offset: 4
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 17
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global2B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 13
+; RELOC-NEXT: - Index: 18
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global2
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Segment: 1
+; RELOC-NEXT: Offset: 4
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 19
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_global3B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 14
+; RELOC-NEXT: - Index: 20
+; RELOC-NEXT: Kind: DATA
+; RELOC-NEXT: Name: colliding_global3
+; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
+; RELOC-NEXT: Segment: 2
+; RELOC-NEXT: Offset: 4
+; RELOC-NEXT: Size: 4
+; RELOC-NEXT: - Index: 21
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func1B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 15
+; RELOC-NEXT: - Index: 22
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func2B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 16
+; RELOC-NEXT: - Index: 23
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: get_func3B
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 17
+; RELOC-NEXT: SegmentInfo:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Name: .bss.colliding_global1
+; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Name: .bss.colliding_global2
+; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Name: .bss.colliding_global3
+; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: - Type: CUSTOM
+; RELOC-NEXT: Name: name
+; RELOC-NEXT: FunctionNames:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Name: colliding_func1
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Name: colliding_func2
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Name: colliding_func3
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Name: get_global1A
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Name: get_global2A
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Name: get_global3A
+; RELOC-NEXT: - Index: 6
+; RELOC-NEXT: Name: get_func1A
+; RELOC-NEXT: - Index: 7
+; RELOC-NEXT: Name: get_func2A
+; RELOC-NEXT: - Index: 8
+; RELOC-NEXT: Name: get_func3A
+; RELOC-NEXT: - Index: 9
+; RELOC-NEXT: Name: colliding_func1
+; RELOC-NEXT: - Index: 10
+; RELOC-NEXT: Name: colliding_func2
+; RELOC-NEXT: - Index: 11
+; RELOC-NEXT: Name: colliding_func3
+; RELOC-NEXT: - Index: 12
+; RELOC-NEXT: Name: get_global1B
+; RELOC-NEXT: - Index: 13
+; RELOC-NEXT: Name: get_global2B
+; RELOC-NEXT: - Index: 14
+; RELOC-NEXT: Name: get_global3B
+; RELOC-NEXT: - Index: 15
+; RELOC-NEXT: Name: get_func1B
+; RELOC-NEXT: - Index: 16
+; RELOC-NEXT: Name: get_func2B
+; RELOC-NEXT: - Index: 17
+; RELOC-NEXT: Name: get_func3B
+; RELOC-NEXT: ...
diff --git a/test/wasm/lto/Inputs/archive.ll b/test/wasm/lto/Inputs/archive.ll
new file mode 100644
index 000000000000..75984793246c
--- /dev/null
+++ b/test/wasm/lto/Inputs/archive.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @f() {
+ ret void
+}
diff --git a/test/wasm/lto/Inputs/cache.ll b/test/wasm/lto/Inputs/cache.ll
new file mode 100644
index 000000000000..a66f36aef9cb
--- /dev/null
+++ b/test/wasm/lto/Inputs/cache.ll
@@ -0,0 +1,10 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define i32 @_start() {
+entry:
+ call void (...) @globalfunc()
+ ret i32 0
+}
+
+declare void @globalfunc(...)
diff --git a/test/wasm/lto/Inputs/save-temps.ll b/test/wasm/lto/Inputs/save-temps.ll
new file mode 100644
index 000000000000..6f4de417c380
--- /dev/null
+++ b/test/wasm/lto/Inputs/save-temps.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @bar() {
+ ret void
+}
diff --git a/test/wasm/lto/Inputs/thinlto.ll b/test/wasm/lto/Inputs/thinlto.ll
new file mode 100644
index 000000000000..39e573b1c21e
--- /dev/null
+++ b/test/wasm/lto/Inputs/thinlto.ll
@@ -0,0 +1,7 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @g() {
+entry:
+ ret void
+}
diff --git a/test/wasm/lto/Inputs/used.ll b/test/wasm/lto/Inputs/used.ll
new file mode 100644
index 000000000000..d0250d518abc
--- /dev/null
+++ b/test/wasm/lto/Inputs/used.ll
@@ -0,0 +1,8 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@foo = hidden global i32 1
+
+define hidden void @bar() {
+ ret void
+}
diff --git a/test/wasm/lto/archive.ll b/test/wasm/lto/archive.ll
new file mode 100644
index 000000000000..89fa840cdec5
--- /dev/null
+++ b/test/wasm/lto/archive.ll
@@ -0,0 +1,25 @@
+; 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: wasm-ld %t2.o %t.a -o %t3
+; RUN: obj2yaml %t3 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @_start() {
+ call void @f()
+ ret void
+}
+
+declare void @f()
+
+; CHECK: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: f
diff --git a/test/wasm/lto/atomics.ll b/test/wasm/lto/atomics.ll
new file mode 100644
index 000000000000..a5a82ae2a5fc
--- /dev/null
+++ b/test/wasm/lto/atomics.ll
@@ -0,0 +1,14 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t.wasm -lto-O0
+; Atomic operations with fail to compile if the ThreadModel is not
+; correctly set to Single (i.e. if atomics are not lowered to regular ops).
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+@foo = hidden global i32 1
+
+define void @_start() {
+ %1 = load atomic i32, i32* @foo unordered, align 4
+ ret void
+}
diff --git a/test/wasm/lto/cache.ll b/test/wasm/lto/cache.ll
new file mode 100644
index 000000000000..b0a7820c1e19
--- /dev/null
+++ b/test/wasm/lto/cache.ll
@@ -0,0 +1,38 @@
+; RUN: opt -module-hash -module-summary %s -o %t.o
+; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
+
+; RUN: rm -Rf %t.cache && mkdir %t.cache
+; Create two files that would be removed by cache pruning due to age.
+; We should only remove files matching the pattern "llvmcache-*".
+; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=1h:prune_interval=0s -o %t.wasm %t2.o %t.o
+
+; Two cached objects, plus a timestamp file and "foo", minus the file we removed.
+; RUN: ls %t.cache | count 4
+
+; Create a file of size 64KB.
+; RUN: "%python" -c "print(' ' * 65536)" > %t.cache/llvmcache-foo
+
+; This should leave the file in place.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 5
+
+; This should remove it.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 4
+
+; Setting max number of files to 0 should disable the limit, not delete everything.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=0:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 4
+
+; Delete everything except for the timestamp, "foo" and one cache file.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=1:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 3
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define void @globalfunc() #0 {
+entry:
+ ret void
+}
diff --git a/test/wasm/lto/diagnostics.ll b/test/wasm/lto/diagnostics.ll
new file mode 100644
index 000000000000..77f68fe93abb
--- /dev/null
+++ b/test/wasm/lto/diagnostics.ll
@@ -0,0 +1,22 @@
+; verify that errors in the LLVM backend during LTO manifest as lld
+; errors
+
+; RUN: llvm-as %s -o %t.o
+; RUN: not wasm-ld --lto-O0 %t.o -o %t2 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @_start() {
+ call i8* @foo()
+ ret void
+}
+
+define i8* @foo() {
+ %1 = call i8* @llvm.returnaddress(i32 0)
+ ret i8* %1
+}
+
+declare i8* @llvm.returnaddress(i32)
+
+; CHECK: error: {{.*}} WebAssembly hasn't implemented __builtin_return_address
diff --git a/test/wasm/lto/export.ll b/test/wasm/lto/export.ll
new file mode 100644
index 000000000000..44ded6f147f6
--- /dev/null
+++ b/test/wasm/lto/export.ll
@@ -0,0 +1,38 @@
+; RUN: llvm-as -o %t.bc %s
+; RUN: not wasm-ld --export=missing -o %t.wasm %t.bc 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s
+; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.bc
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define hidden i32 @hidden_function() local_unnamed_addr {
+entry:
+ ret i32 0
+}
+
+define void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
+
+; CHECK-ERROR: error: symbol exported via --export not found: missing
+
+; CHECK: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: hidden_function
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Type: CODE
diff --git a/test/wasm/lto/incompatible.ll b/test/wasm/lto/incompatible.ll
new file mode 100644
index 000000000000..ee98cb4b4e63
--- /dev/null
+++ b/test/wasm/lto/incompatible.ll
@@ -0,0 +1,8 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.bc
+; RUN: not wasm-ld %t.bc -o out.wasm 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: {{.*}}incompatible.ll.tmp.bc: machine type must be wasm32
diff --git a/test/wasm/lto/internalize-basic.ll b/test/wasm/lto/internalize-basic.ll
new file mode 100644
index 000000000000..313a05ecbae4
--- /dev/null
+++ b/test/wasm/lto/internalize-basic.ll
@@ -0,0 +1,20 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+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/wasm/lto/lto-start.ll b/test/wasm/lto/lto-start.ll
new file mode 100644
index 000000000000..6e8f99c95308
--- /dev/null
+++ b/test/wasm/lto/lto-start.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define void @_start() {
+ ret void
+}
diff --git a/test/wasm/lto/opt-level.ll b/test/wasm/lto/opt-level.ll
new file mode 100644
index 000000000000..b7e6a4cdc70a
--- /dev/null
+++ b/test/wasm/lto/opt-level.ll
@@ -0,0 +1,30 @@
+; RUN: llvm-as -o %t.o %s
+; RUN: wasm-ld -o %t0 -e main --lto-O0 %t.o
+; RUN: obj2yaml %t0 | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: wasm-ld -o %t2 -e main --lto-O2 %t.o
+; RUN: obj2yaml %t2 | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: wasm-ld -o %t2a -e main %t.o
+; RUN: obj2yaml %t2a | FileCheck --check-prefix=CHECK-O2 %s
+
+; Reject invalid optimization levels.
+; RUN: not ld.lld -o %t3 -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: 4294967295
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; CHECK-O0: Name: foo
+; CHECK-O2-NOT: Name: foo
+define internal void @foo() {
+ ret void
+}
+
+define void @main() {
+ call void @foo()
+ ret void
+}
diff --git a/test/wasm/lto/parallel.ll b/test/wasm/lto/parallel.ll
new file mode 100644
index 000000000000..a93c3558d969
--- /dev/null
+++ b/test/wasm/lto/parallel.ll
@@ -0,0 +1,24 @@
+; RUN: llvm-as -o %t.bc %s
+; RUN: rm -f %t.lto.o %t1.lto.o
+; RUN: wasm-ld --lto-partitions=2 -save-temps -o %t %t.bc -r
+; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; 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/wasm/lto/save-temps.ll b/test/wasm/lto/save-temps.ll
new file mode 100644
index 000000000000..2734d86815c7
--- /dev/null
+++ b/test/wasm/lto/save-temps.ll
@@ -0,0 +1,19 @@
+; 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: wasm-ld -r -o a.out %t.o %t2.o -save-temps
+; RUN: llvm-nm a.out | FileCheck %s
+; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
+; RUN: llvm-nm a.out.lto.o | FileCheck %s
+; RUN: llvm-dis a.out.0.0.preopt.bc
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @foo() {
+ ret void
+}
+
+; CHECK: T bar
+; CHECK: T foo
diff --git a/test/wasm/lto/thinlto.ll b/test/wasm/lto/thinlto.ll
new file mode 100644
index 000000000000..062da1a33b89
--- /dev/null
+++ b/test/wasm/lto/thinlto.ll
@@ -0,0 +1,34 @@
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; First force single-threaded mode
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: wasm-ld -r -save-temps --thinlto-jobs=1 %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; Next force multi-threaded mode
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: wasm-ld -r -save-temps --thinlto-jobs=2 %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; Check without --thinlto-jobs (which currently default to hardware_concurrency)
+; RUN: wasm-ld -r %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; NM1: T f
+; NM2: T g
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/wasm/lto/undef.ll b/test/wasm/lto/undef.ll
new file mode 100644
index 000000000000..729007b50c05
--- /dev/null
+++ b/test/wasm/lto/undef.ll
@@ -0,0 +1,20 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t.wasm --allow-undefined
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @bar()
+
+define void @_start() {
+ call void @bar()
+ ret void
+}
+
+; CHECK: - Type: IMPORT
+; CHECK-NEXT: Imports:
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: bar
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 0
diff --git a/test/wasm/lto/used.ll b/test/wasm/lto/used.ll
new file mode 100644
index 000000000000..8bf840366cc5
--- /dev/null
+++ b/test/wasm/lto/used.ll
@@ -0,0 +1,45 @@
+; RUN: llc %s -o %t.o -filetype=obj
+; RUN: llvm-as %S/Inputs/used.ll -o %t1.o
+; RUN: wasm-ld %t.o %t1.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Verify that symbols references from regular objects are preserved by LTO
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @bar()
+
+@foo = external global i32
+
+define void @_start() {
+ %val = load i32, i32* @foo, align 4
+ %tobool = icmp ne i32 %val, 0
+ br i1 %tobool, label %callbar, label %return
+
+callbar:
+ call void @bar()
+ br label %return
+
+return:
+ ret void
+}
+
+; CHECK: - Type: DATA
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - SectionOffset: 7
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: Content: '01000000'
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: bar
diff --git a/test/wasm/lto/verify-invalid.ll b/test/wasm/lto/verify-invalid.ll
new file mode 100644
index 000000000000..c4a5bcdc67d1
--- /dev/null
+++ b/test/wasm/lto/verify-invalid.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: 2>&1 | FileCheck -check-prefix=DEFAULT %s
+; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+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/wasm/lto/weak.ll b/test/wasm/lto/weak.ll
new file mode 100644
index 000000000000..03a017c1a183
--- /dev/null
+++ b/test/wasm/lto/weak.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o %t.o -o %t.wasm -r
+; RUN: llvm-readobj -t %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define weak void @f() {
+ ret void
+}
+
+; CHECK: Symbol {
+; CHECK-NEXT: Name: f
+; CHECK-NEXT: Type: FUNCTION (0x0)
+; CHECK-NEXT: Flags: 0x1
+; CHECK-NEXT: }
diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll
index f21298d862d6..02ad9aab51a0 100644
--- a/test/wasm/many-functions.ll
+++ b/test/wasm/many-functions.ll
@@ -1,6 +1,6 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/many-funcs.ll -o %t.many.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -r -o %t.wasm %t.many.o %t.o
+; RUN: llc -filetype=obj %p/Inputs/many-funcs.ll -o %t.many.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.many.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that relocations within the CODE section correctly handle
@@ -8,6 +8,8 @@
; 128 function and so the final output requires a 2-byte LEB in
; the CODE section header to store the function count.
+target triple = "wasm32-unknown-unknown"
+
define i32 @func() {
entry:
%call = tail call i32 @func()
@@ -17,655 +19,785 @@ entry:
; CHECK: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000008
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000014
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000020
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000002C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000038
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000044
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000050
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000005C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000068
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000074
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000080
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000008C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000098
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000A4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000B0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000BC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000C8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000D4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000E0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000EC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000000F8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000104
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000110
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000011C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000128
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000134
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000140
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000014C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000158
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000164
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000170
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000017C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000188
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000194
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001A0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001AC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001B8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001C4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001D0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001DC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001E8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000001F4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000200
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000020C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000218
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000224
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000230
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000023C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000248
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000254
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000260
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000026C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000278
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000284
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000290
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000029C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002A8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002B4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002C0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002CC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002D8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002E4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002F0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000002FC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000308
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000314
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000320
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000032C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000338
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000344
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000350
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000035C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000368
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000374
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000380
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000038C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000398
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003A4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003B0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003BC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003C8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003D4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003E0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003EC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000003F8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000404
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000410
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000041C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000428
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000434
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000440
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000044C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000458
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000464
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000470
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000047C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000488
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000494
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004A0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004AC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004B8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004C4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004D0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004DC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004E8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000004F4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000500
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000050C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000518
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000524
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000530
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000053C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000548
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000554
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000560
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000056C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000578
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000584
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000590
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000059C
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005A8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005B4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005C0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005CC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005D8
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005E4
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x000005F0
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 129
; CHECK-NEXT: Offset: 0x000005FC
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 129
; CHECK-NEXT: Offset: 0x00000608
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
-; CHECK-NEXT: Index: 129
+; CHECK-NEXT: Index: 131
; CHECK-NEXT: Offset: 0x00000611
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 9
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 10
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 13
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 14
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 15
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 16
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 17
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 18
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 19
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 20
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 21
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 22
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 23
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 24
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 25
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 26
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 27
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 28
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 29
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 30
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 31
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 32
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 33
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 34
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 35
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 36
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 37
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 38
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 39
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 40
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 41
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 42
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 43
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 44
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 45
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 46
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 47
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 48
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 49
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 50
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 51
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 52
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 53
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 54
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 55
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 56
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 57
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 58
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 59
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 60
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 61
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 62
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 63
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 64
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 65
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 66
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 67
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 68
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 69
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 70
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 71
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 72
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 73
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 74
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 75
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 76
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 77
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 78
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 79
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 80
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 81
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 82
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 83
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 84
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 85
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 86
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 87
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 88
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 89
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 90
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 91
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 92
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 93
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 94
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 95
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 96
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 97
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 98
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 99
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 100
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 101
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 102
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 103
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 104
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 105
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 106
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 107
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 108
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 109
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 110
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 111
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 112
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 113
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 114
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 115
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 116
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 117
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 118
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 119
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 120
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 121
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 122
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 123
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 124
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 125
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 126
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280284808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 127
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280280808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 128
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280280808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 129
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 1081818080000B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
@@ -683,7 +815,670 @@ entry:
; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 8
+; CHECK-NEXT: Version: 1
+; CHECK-NEXT: SymbolTable:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f1
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 0
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: foo
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Segment: 1
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f2
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 1
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f3
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 2
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f4
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 3
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f5
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 4
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f6
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 5
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f7
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 6
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f8
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 7
+; CHECK-NEXT: - Index: 9
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f9
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 8
+; CHECK-NEXT: - Index: 10
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f10
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 9
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f11
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 10
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f12
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 11
+; CHECK-NEXT: - Index: 13
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f13
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 12
+; CHECK-NEXT: - Index: 14
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f14
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 13
+; CHECK-NEXT: - Index: 15
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f15
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 14
+; CHECK-NEXT: - Index: 16
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f16
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 15
+; CHECK-NEXT: - Index: 17
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f17
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 16
+; CHECK-NEXT: - Index: 18
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f18
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 17
+; CHECK-NEXT: - Index: 19
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f19
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 18
+; CHECK-NEXT: - Index: 20
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f20
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 19
+; CHECK-NEXT: - Index: 21
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f21
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 20
+; CHECK-NEXT: - Index: 22
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f22
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 21
+; CHECK-NEXT: - Index: 23
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f23
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 22
+; CHECK-NEXT: - Index: 24
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f24
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 23
+; CHECK-NEXT: - Index: 25
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f25
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 24
+; CHECK-NEXT: - Index: 26
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f26
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 25
+; CHECK-NEXT: - Index: 27
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f27
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 26
+; CHECK-NEXT: - Index: 28
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f28
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 27
+; CHECK-NEXT: - Index: 29
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f29
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 28
+; CHECK-NEXT: - Index: 30
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f30
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 29
+; CHECK-NEXT: - Index: 31
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f31
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 30
+; CHECK-NEXT: - Index: 32
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f32
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 31
+; CHECK-NEXT: - Index: 33
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f33
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 32
+; CHECK-NEXT: - Index: 34
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f34
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 33
+; CHECK-NEXT: - Index: 35
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f35
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 34
+; CHECK-NEXT: - Index: 36
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f36
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 35
+; CHECK-NEXT: - Index: 37
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f37
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 36
+; CHECK-NEXT: - Index: 38
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f38
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 37
+; CHECK-NEXT: - Index: 39
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f39
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 38
+; CHECK-NEXT: - Index: 40
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f40
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 39
+; CHECK-NEXT: - Index: 41
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f41
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 40
+; CHECK-NEXT: - Index: 42
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f42
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 41
+; CHECK-NEXT: - Index: 43
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f43
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 42
+; CHECK-NEXT: - Index: 44
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f44
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 43
+; CHECK-NEXT: - Index: 45
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f45
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 44
+; CHECK-NEXT: - Index: 46
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f46
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 45
+; CHECK-NEXT: - Index: 47
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f47
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 46
+; CHECK-NEXT: - Index: 48
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f48
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 47
+; CHECK-NEXT: - Index: 49
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f49
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 48
+; CHECK-NEXT: - Index: 50
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f50
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 49
+; CHECK-NEXT: - Index: 51
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f51
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 50
+; CHECK-NEXT: - Index: 52
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f52
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 51
+; CHECK-NEXT: - Index: 53
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f53
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 52
+; CHECK-NEXT: - Index: 54
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f54
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 53
+; CHECK-NEXT: - Index: 55
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f55
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 54
+; CHECK-NEXT: - Index: 56
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f56
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 55
+; CHECK-NEXT: - Index: 57
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f57
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 56
+; CHECK-NEXT: - Index: 58
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f58
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 57
+; CHECK-NEXT: - Index: 59
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f59
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 58
+; CHECK-NEXT: - Index: 60
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f60
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 59
+; CHECK-NEXT: - Index: 61
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f61
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 60
+; CHECK-NEXT: - Index: 62
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f62
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 61
+; CHECK-NEXT: - Index: 63
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f63
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 62
+; CHECK-NEXT: - Index: 64
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f64
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 63
+; CHECK-NEXT: - Index: 65
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f65
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 64
+; CHECK-NEXT: - Index: 66
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f66
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 65
+; CHECK-NEXT: - Index: 67
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f67
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 66
+; CHECK-NEXT: - Index: 68
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f68
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 67
+; CHECK-NEXT: - Index: 69
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f69
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 68
+; CHECK-NEXT: - Index: 70
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f70
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 69
+; CHECK-NEXT: - Index: 71
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f71
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 70
+; CHECK-NEXT: - Index: 72
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f72
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 71
+; CHECK-NEXT: - Index: 73
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f73
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 72
+; CHECK-NEXT: - Index: 74
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f74
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 73
+; CHECK-NEXT: - Index: 75
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f75
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 74
+; CHECK-NEXT: - Index: 76
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f76
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 75
+; CHECK-NEXT: - Index: 77
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f77
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 76
+; CHECK-NEXT: - Index: 78
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f78
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 77
+; CHECK-NEXT: - Index: 79
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f79
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 78
+; CHECK-NEXT: - Index: 80
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f80
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 79
+; CHECK-NEXT: - Index: 81
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f81
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 80
+; CHECK-NEXT: - Index: 82
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f82
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 81
+; CHECK-NEXT: - Index: 83
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f83
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 82
+; CHECK-NEXT: - Index: 84
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f84
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 83
+; CHECK-NEXT: - Index: 85
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f85
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 84
+; CHECK-NEXT: - Index: 86
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f86
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 85
+; CHECK-NEXT: - Index: 87
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f87
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 86
+; CHECK-NEXT: - Index: 88
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f88
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 87
+; CHECK-NEXT: - Index: 89
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f89
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 88
+; CHECK-NEXT: - Index: 90
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f90
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 89
+; CHECK-NEXT: - Index: 91
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f91
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 90
+; CHECK-NEXT: - Index: 92
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f92
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 91
+; CHECK-NEXT: - Index: 93
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f93
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 92
+; CHECK-NEXT: - Index: 94
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f94
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 93
+; CHECK-NEXT: - Index: 95
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f95
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 94
+; CHECK-NEXT: - Index: 96
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f96
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 95
+; CHECK-NEXT: - Index: 97
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f97
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 96
+; CHECK-NEXT: - Index: 98
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f98
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 97
+; CHECK-NEXT: - Index: 99
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f99
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 98
+; CHECK-NEXT: - Index: 100
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f100
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 99
+; CHECK-NEXT: - Index: 101
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f101
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 100
+; CHECK-NEXT: - Index: 102
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f102
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 101
+; CHECK-NEXT: - Index: 103
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f103
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 102
+; CHECK-NEXT: - Index: 104
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f104
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 103
+; CHECK-NEXT: - Index: 105
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f105
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 104
+; CHECK-NEXT: - Index: 106
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f106
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 105
+; CHECK-NEXT: - Index: 107
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f107
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 106
+; CHECK-NEXT: - Index: 108
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f108
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 107
+; CHECK-NEXT: - Index: 109
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f109
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 108
+; CHECK-NEXT: - Index: 110
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f110
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 109
+; CHECK-NEXT: - Index: 111
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f111
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 110
+; CHECK-NEXT: - Index: 112
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f112
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 111
+; CHECK-NEXT: - Index: 113
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f113
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 112
+; CHECK-NEXT: - Index: 114
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f114
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 113
+; CHECK-NEXT: - Index: 115
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f115
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 114
+; CHECK-NEXT: - Index: 116
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f116
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 115
+; CHECK-NEXT: - Index: 117
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f117
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 116
+; CHECK-NEXT: - Index: 118
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f118
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 117
+; CHECK-NEXT: - Index: 119
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f119
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 118
+; CHECK-NEXT: - Index: 120
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f120
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 119
+; CHECK-NEXT: - Index: 121
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f121
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 120
+; CHECK-NEXT: - Index: 122
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f122
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 121
+; CHECK-NEXT: - Index: 123
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f123
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 122
+; CHECK-NEXT: - Index: 124
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f124
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 123
+; CHECK-NEXT: - Index: 125
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f125
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 124
+; CHECK-NEXT: - Index: 126
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f126
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 125
+; CHECK-NEXT: - Index: 127
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f127
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 126
+; CHECK-NEXT: - Index: 128
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f128
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 127
+; CHECK-NEXT: - Index: 129
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: g0
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Segment: 0
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 130
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: f129
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 128
+; CHECK-NEXT: - Index: 131
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: func
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 129
; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .data.g0
diff --git a/test/wasm/reloc-addend.ll b/test/wasm/reloc-addend.ll
new file mode 100644
index 000000000000..f678a3d4b617
--- /dev/null
+++ b/test/wasm/reloc-addend.ll
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+@foo = hidden global [76 x i32] zeroinitializer, align 16
+
+; bar points to the 16th element, which happens to be 64 bytes
+; This generates an addend of 64 which, is the value at which
+; signed and unsigned LEB encodes will differ.
+@bar = hidden local_unnamed_addr global i32* getelementptr inbounds ([76 x i32], [76 x i32]* @foo, i32 0, i32 16), align 4
+
+; CHECK: - Type: DATA
+; CHECK-NEXT: Relocations:
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x0000013D
+; CHECK-NEXT: Addend: 64
diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll
index d9d2e02bdabb..4e8a887f31d8 100644
--- a/test/wasm/relocatable.ll
+++ b/test/wasm/relocatable.ll
@@ -1,22 +1,34 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -r -o %t.wasm %t.hello.o %t.o
+; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.hello.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: nounwind
define hidden i32 @my_func() local_unnamed_addr {
entry:
%call = tail call i32 @foo_import()
+ %call2 = tail call i32 @bar_import()
ret i32 1
}
declare i32 @foo_import() local_unnamed_addr
+declare extern_weak i32 @bar_import() local_unnamed_addr
@data_import = external global i64
@func_addr1 = hidden global i32()* @my_func, align 4
@func_addr2 = hidden global i32()* @foo_import, align 4
+@func_addr3 = hidden global i32()* @bar_import, align 4
@data_addr1 = hidden global i64* @data_import, align 8
+$func_comdat = comdat any
+@data_comdat = weak_odr constant [3 x i8] c"abc", comdat($func_comdat)
+define linkonce_odr i32 @func_comdat() comdat {
+entry:
+ ret i32 ptrtoint ([3 x i8]* @data_comdat to i32)
+}
+
; CHECK: --- !WASM
; CHECK-NEXT: FileHeader:
; CHECK-NEXT: Version: 0x00000001
@@ -26,115 +38,86 @@ declare i32 @foo_import() local_unnamed_addr
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
-; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: IMPORT
; CHECK-NEXT: Imports:
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: puts
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: SigIndex: 1
+; CHECK-NEXT: SigIndex: 0
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: foo_import
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: SigIndex: 2
+; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: env
-; CHECK-NEXT: Field: data_import
-; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: GlobalType: I32
-; CHECK-NEXT: GlobalMutable: false
+; CHECK-NEXT: Field: bar_import
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 2 ]
+; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
-; CHECK-NEXT: Initial: 0x00000002
-; CHECK-NEXT: Maximum: 0x00000002
+; CHECK-NEXT: Initial: 0x00000004
+; CHECK-NEXT: Maximum: 0x00000004
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
; CHECK-NEXT: - Initial: 0x00000001
-; CHECK-NEXT: - Type: GLOBAL
-; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 0
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 8
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 12
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: false
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 16
-; CHECK-NEXT: - Type: EXPORT
-; CHECK-NEXT: Exports:
-; CHECK-NEXT: - Name: hello
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
-; CHECK-NEXT: - Name: my_func
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 3
-; CHECK-NEXT: - Name: hello_str
-; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: Index: 1
-; CHECK-NEXT: - Name: func_addr1
-; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: Index: 2
-; CHECK-NEXT: - Name: func_addr2
-; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: Index: 3
-; CHECK-NEXT: - Name: data_addr1
-; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 0
-; CHECK-NEXT: Functions: [ 3, 1 ]
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: Functions: [ 4, 1, 2 ]
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000004
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: Offset: 0x0000000A
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x00000013
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 5
+; CHECK-NEXT: Offset: 0x0000001A
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; CHECK-NEXT: Index: 7
+; CHECK-NEXT: Offset: 0x00000026
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4180808080001080808080000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1081808080001A41010B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1081808080001A1082808080001A41010B
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 419C808080000B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: Offset: 0x00000012
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x0000001B
-; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: Offset: 0x00000024
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
+; CHECK-NEXT: Index: 12
+; CHECK-NEXT: Offset: 0x0000002D
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
; CHECK-NEXT: MemoryIndex: 0
@@ -147,39 +130,137 @@ declare i32 @foo_import() local_unnamed_addr
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 8
-; CHECK-NEXT: Content: '00000000'
+; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - SectionOffset: 27
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 12
-; CHECK-NEXT: Content: '01000000'
+; CHECK-NEXT: Content: '02000000'
; CHECK-NEXT: - SectionOffset: 36
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 16
-; CHECK-NEXT: Content: FFFFFFFF
+; CHECK-NEXT: Content: '03000000'
+; CHECK-NEXT: - SectionOffset: 45
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 24
+; CHECK-NEXT: Content: '00000000'
+; CHECK-NEXT: - SectionOffset: 54
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 28
+; CHECK-NEXT: Content: '616263'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 20
+; CHECK-NEXT: Version: 1
+; CHECK-NEXT: SymbolTable:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: hello
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Function: 3
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: hello_str
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Segment: 0
+; CHECK-NEXT: Size: 7
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: puts
+; CHECK-NEXT: Flags: [ UNDEFINED ]
+; CHECK-NEXT: Function: 0
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: my_func
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Function: 4
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: foo_import
+; CHECK-NEXT: Flags: [ UNDEFINED ]
+; CHECK-NEXT: Function: 1
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: bar_import
+; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]
+; CHECK-NEXT: Function: 2
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: func_comdat
+; CHECK-NEXT: Flags: [ BINDING_WEAK ]
+; CHECK-NEXT: Function: 5
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: data_comdat
+; CHECK-NEXT: Flags: [ BINDING_WEAK ]
+; CHECK-NEXT: Segment: 5
+; CHECK-NEXT: Size: 3
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: func_addr1
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Segment: 1
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 9
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: func_addr2
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Segment: 2
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 10
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: func_addr3
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Segment: 3
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 11
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: data_addr1
+; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+; CHECK-NEXT: Segment: 4
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: - Index: 12
+; CHECK-NEXT: Kind: DATA
+; CHECK-NEXT: Name: data_import
+; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .rodata.hello_str
; CHECK-NEXT: Alignment: 1
-; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: .data.func_addr1
; CHECK-NEXT: Alignment: 4
-; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: .data.func_addr2
; CHECK-NEXT: Alignment: 4
-; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: .data.func_addr3
+; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: .data.data_addr1
; CHECK-NEXT: Alignment: 8
-; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: .rodata.data_comdat
+; CHECK-NEXT: Alignment: 1
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Comdats:
+; CHECK-NEXT: - Name: func_comdat
+; CHECK-NEXT: Entries:
+; CHECK-NEXT: - Kind: FUNCTION
+; CHECK-NEXT: Index: 5
+; CHECK-NEXT: - Kind: DATA
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
@@ -188,7 +269,11 @@ declare i32 @foo_import() local_unnamed_addr
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: foo_import
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: hello
+; CHECK-NEXT: Name: bar_import
; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: hello
+; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: my_func
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: func_comdat
; CHECK-NEXT: ...
diff --git a/test/wasm/responsefile.test b/test/wasm/responsefile.test
new file mode 100644
index 000000000000..11f805997b26
--- /dev/null
+++ b/test/wasm/responsefile.test
@@ -0,0 +1,10 @@
+RUN: llc -filetype=obj -o %t.o %p/Inputs/ret32.ll
+
+RUN: echo "%/t.o -o %/t.wasm -e ret32" > %t.rsp
+RUN: wasm-ld @%t.rsp --initial-memory=655360
+RUN: llvm-readobj --sections %t.wasm | FileCheck %s
+CHECK: InitialPages: 10
+
+RUN: echo "blah\foo" > %t.rsp
+RUN: not wasm-ld @%t.rsp 2>&1 | FileCheck --check-prefix=ESCAPE %s
+ESCAPE: error: cannot open blahfoo: {{[Nn]}}o such file or directory
diff --git a/test/wasm/signature-mismatch-weak.ll b/test/wasm/signature-mismatch-weak.ll
new file mode 100644
index 000000000000..dbf73d1aa46e
--- /dev/null
+++ b/test/wasm/signature-mismatch-weak.ll
@@ -0,0 +1,18 @@
+; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t.weak.o
+; RUN: llc -filetype=obj %p/Inputs/strong-symbol.ll -o %t.strong.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+declare i32 @weakFn() local_unnamed_addr
+
+define void @_start() local_unnamed_addr {
+entry:
+ %call = call i32 @weakFn()
+ ret void
+}
+
+; CHECK: warning: function signature mismatch: weakFn
+; CHECK-NEXT: >>> defined as () -> I32 in {{.*}}signature-mismatch-weak.ll.tmp.o
+; CHECK-NEXT: >>> defined as () -> I64 in {{.*}}signature-mismatch-weak.ll.tmp.strong.o
diff --git a/test/wasm/signature-mismatch.ll b/test/wasm/signature-mismatch.ll
index 842b8289afd9..d750d4f6b359 100644
--- a/test/wasm/signature-mismatch.ll
+++ b/test/wasm/signature-mismatch.ll
@@ -1,6 +1,12 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.main.o
-; RUN: not lld -flavor wasm --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.main.o
+; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
+; Run the test again by with the object files in the other order to verify
+; the check works when the undefined symbol is resolved by an existing defined
+; one.
+; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE
+
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
@@ -14,3 +20,7 @@ declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
; CHECK: error: function signature mismatch: ret32
; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o
; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o
+
+; REVERSE: error: function signature mismatch: ret32
+; REVERSE-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o
+; REVERSE-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o
diff --git a/test/wasm/stack-first.test b/test/wasm/stack-first.test
new file mode 100644
index 000000000000..71d1e9dde858
--- /dev/null
+++ b/test/wasm/stack-first.test
@@ -0,0 +1,42 @@
+; Test that the --stack-first option places the stack at the start of linear
+; memory. In this case the --stack-first option is being passed along with a
+; stack size of 512. This means (since the stack grows down) the stack pointer
+; global should be initialized to 512.
+
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
+
+RUN: wasm-ld -z stack-size=512 --stack-first --allow-undefined -o %t.wasm %t.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+CHECK: - Type: GLOBAL
+CHECK-NEXT: Globals:
+CHECK-NEXT: - Index: 0
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: true
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 1
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 2
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Type: EXPORT
+CHECK-NEXT: Exports:
+CHECK-NEXT: - Name: memory
+CHECK-NEXT: Kind: MEMORY
+CHECK-NEXT: Index: 0
+CHECK-NEXT: - Name: __heap_base
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 1
+CHECK-NEXT: - Name: __data_end
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 2
+
diff --git a/test/wasm/stack-pointer.ll b/test/wasm/stack-pointer.ll
index c5be94af4e39..888c938881de 100644
--- a/test/wasm/stack-pointer.ll
+++ b/test/wasm/stack-pointer.ll
@@ -1,9 +1,11 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm --emit-relocs -o %t.wasm %t.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld --relocatable -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
; Function Attrs: nounwind
-define hidden i32 @_start() local_unnamed_addr {
+define i32 @_start() local_unnamed_addr {
entry:
%retval = alloca i32, align 4
ret i32 0
@@ -18,6 +20,13 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: IMPORT
+; CHECK-NEXT: Imports:
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __stack_pointer
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I32
+; CHECK-NEXT: GlobalMutable: true
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0 ]
; CHECK-NEXT: - Type: TABLE
@@ -29,33 +38,30 @@ entry:
; CHECK-NEXT: Maximum: 0x00000001
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
-; CHECK-NEXT: - Initial: 0x00000002
-; CHECK-NEXT: - Type: GLOBAL
-; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
-; CHECK-NEXT: Mutable: true
-; CHECK-NEXT: InitExpr:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 66560
-; CHECK-NEXT: - Type: EXPORT
-; CHECK-NEXT: Exports:
-; CHECK-NEXT: - Name: memory
-; CHECK-NEXT: Kind: MEMORY
-; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: _start
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Initial: 0x00000000
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000004
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 23808080800041106B1A41000B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 0
+; CHECK-NEXT: Version: 1
+; CHECK-NEXT: SymbolTable:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: Function: 0
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Name: __stack_pointer
+; CHECK-NEXT: Flags: [ UNDEFINED ]
+; CHECK-NEXT: Global: 0
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test
index ca4b02a4a5fb..be5ba700e258 100644
--- a/test/wasm/strip-debug.test
+++ b/test/wasm/strip-debug.test
@@ -1,5 +1,5 @@
-RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-RUN: lld -flavor wasm --strip-debug --entry=ret32 -o %t.wasm %t.ret32.o
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+RUN: wasm-ld --strip-debug -o %t.wasm %t.start.o
RUN: obj2yaml %t.wasm | FileCheck %s
# Check that there is no name section
diff --git a/test/wasm/symbol-type-mismatch.ll b/test/wasm/symbol-type-mismatch.ll
index b7e37c142549..4738c4bd00b9 100644
--- a/test/wasm/symbol-type-mismatch.ll
+++ b/test/wasm/symbol-type-mismatch.ll
@@ -1,9 +1,11 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-; RUN: not lld -flavor wasm -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: not wasm-ld -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
@ret32 = extern_weak global i32, align 4
; CHECK: error: symbol type mismatch: ret32
-; CHECK: >>> defined as Global in {{.*}}symbol-type-mismatch.ll.tmp.o
-; CHECK: >>> defined as Function in {{.*}}.ret32.o
+; CHECK: >>> defined as WASM_SYMBOL_TYPE_DATA in {{.*}}symbol-type-mismatch.ll.tmp.o
+; CHECK: >>> defined as WASM_SYMBOL_TYPE_FUNCTION in {{.*}}.ret32.o
diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test
index 55f7d6fb7843..ffa079ca638b 100644
--- a/test/wasm/undefined-entry.test
+++ b/test/wasm/undefined-entry.test
@@ -1,4 +1,11 @@
-RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
-RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s
+RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s
+RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM
+RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW
CHECK: error: undefined symbol: _start
+CHECK-CUSTOM: error: undefined symbol: foo
+CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress):
+_start
+
+RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o
diff --git a/test/wasm/undefined-weak-call.ll b/test/wasm/undefined-weak-call.ll
new file mode 100644
index 000000000000..c13f5c1ae3f1
--- /dev/null
+++ b/test/wasm/undefined-weak-call.ll
@@ -0,0 +1,120 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld --no-entry --print-gc-sections %t.o \
+; RUN: -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-GC %s
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Check that calling an undefined weak function generates an appropriate stub
+; that will fail at runtime with "unreachable".
+
+target triple = "wasm32-unknown-unknown"
+
+declare extern_weak void @weakFunc1()
+declare extern_weak void @weakFunc2() ; same signature
+declare extern_weak void @weakFunc3(i32 %arg) ; different
+declare extern_weak void @weakFunc4() ; should be GC'd as not called
+
+; CHECK-GC: removing unused section {{.*}}:(weakFunc4)
+
+define i32 @callWeakFuncs() {
+ call void @weakFunc1()
+ call void @weakFunc2()
+ call void @weakFunc3(i32 2)
+ %addr1 = ptrtoint void ()* @weakFunc1 to i32
+ %addr4 = ptrtoint void ()* @weakFunc4 to i32
+ %sum = add i32 %addr1, %addr4
+ ret i32 %sum
+}
+
+; CHECK: --- !WASM
+; CHECK-NEXT: FileHeader:
+; CHECK-NEXT: Version: 0x00000001
+; CHECK-NEXT: Sections:
+; CHECK-NEXT: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - I32
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1, 2 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; CHECK-NEXT: Initial: 0x00000001
+; CHECK-NEXT: Maximum: 0x00000001
+; CHECK-NEXT: - Type: MEMORY
+; CHECK-NEXT: Memories:
+; CHECK-NEXT: - Initial: 0x00000002
+; CHECK-NEXT: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
+; CHECK-NEXT: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: callWeakFuncs
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 000B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 000B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 000B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 10818080800010828080800041021083808080004180808080004180808080006A0B
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: undefined function weakFunc1
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: undefined function weakFunc2
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: undefined function weakFunc3
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Name: callWeakFuncs
+; CHECK-NEXT: ...
diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll
index 249afe243b07..7d2161d2bcc6 100644
--- a/test/wasm/undefined.ll
+++ b/test/wasm/undefined.ll
@@ -1,13 +1,19 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm --allow-undefined -o %t.wasm %t.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o
-; Fails due to undefined 'foo'
-; RUN: not lld -flavor wasm -o %t.wasm %t.o 2>&1 | FileCheck %s
+; Fails due to undefined 'foo' and also 'baz'
+; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s
; CHECK: error: {{.*}}.o: undefined symbol: foo
+; CHECK: error: undefined symbol: baz
-; But succeeds if we pass a file containing 'foo' as --allow-undefined-file.
+; Succeeds if we pass a file containing 'foo' as --allow-undefined-file.
; RUN: echo 'foo' > %t.txt
-; RUN: lld -flavor wasm --allow-undefined-file=%t.txt -o %t.wasm %t.o
+; RUN: wasm-ld --allow-undefined-file=%t.txt -o %t.wasm %t.o
+
+; Succeeds even if a missing symbol is added via --export
+; RUN: wasm-ld --allow-undefined --export=xxx -o %t.wasm %t.o
+
+target triple = "wasm32-unknown-unknown"
; Takes the address of the external foo() resulting in undefined external
@bar = hidden local_unnamed_addr global i8* bitcast (i32 ()* @foo to i8*), align 4
diff --git a/test/wasm/version.ll b/test/wasm/version.ll
index 2ae65d9ad37f..ea5b41ff9b0d 100644
--- a/test/wasm/version.ll
+++ b/test/wasm/version.ll
@@ -1,7 +1,9 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o
; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
define hidden void @_start() local_unnamed_addr #0 {
entry:
ret void
diff --git a/test/wasm/visibility-hidden.ll b/test/wasm/visibility-hidden.ll
index 9960b952492b..af973df0751a 100644
--- a/test/wasm/visibility-hidden.ll
+++ b/test/wasm/visibility-hidden.ll
@@ -1,12 +1,14 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/hidden.ll -o %t2.o
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llc -filetype=obj %S/Inputs/hidden.ll -o %t2.o
; RUN: llvm-ar rcs %t2.a %t2.o
-; RUN: lld -flavor wasm %t.o %t2.a -o %t.wasm
+; RUN: wasm-ld %t.o %t2.a -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that hidden symbols are not exported, whether pulled in from an archive
; or directly.
+target triple = "wasm32-unknown-unknown"
+
define hidden i32 @objectHidden() {
entry:
ret i32 0
@@ -20,13 +22,13 @@ entry:
declare i32 @archiveHidden()
declare i32 @archiveDefault()
-define i32 @_start() {
+define void @_start() {
entry:
%call1 = call i32 @objectHidden()
%call2 = call i32 @objectDefault()
%call3 = call i32 @archiveHidden()
%call4 = call i32 @archiveDefault()
- ret i32 0
+ ret void
}
; CHECK: - Type: EXPORT
@@ -34,13 +36,19 @@ entry:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: objectDefault
+; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: archiveDefault
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
-; CHECK-NEXT: - Name: objectDefault
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Type:
diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll
index c2f673a52725..8b98f3347a1c 100644
--- a/test/wasm/weak-alias-overide.ll
+++ b/test/wasm/weak-alias-overide.ll
@@ -1,11 +1,13 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
-; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
+; RUN: wasm-ld %t.o %t2.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that the strongly defined alias_fn from this file is used both here
; and in call_alias.
+target triple = "wasm32-unknown-unknown"
+
define i32 @alias_fn() local_unnamed_addr #1 {
ret i32 1
}
@@ -24,13 +26,13 @@ entry:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1, 1, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@@ -43,81 +45,109 @@ entry:
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: alias_fn
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: direct_fn
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: call_direct
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 3
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: call_alias
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Name: call_alias_ptr
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 5
+; CHECK-NEXT: Index: 6
; CHECK-NEXT: - Name: call_direct_ptr
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 6
+; CHECK-NEXT: Index: 7
; CHECK-NEXT: - Type: ELEM
-; CHECK-NEXT: Segments:
-; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1
-; CHECK-NEXT: Functions: [ 0, 2 ]
+; CHECK-NEXT: Functions: [ 1, 3 ]
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41010B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1080808080001A0B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1081808080001A0B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1082808080000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1080808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1083808080000B
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1081808080000B
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Locals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
-; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081080808080002101200041106A24808080800020010B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Locals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
-; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B
-; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 0
+; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081083808080002101200041106A24808080800020010B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: alias_fn
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: _start
+; CHECK-NEXT: Name: alias_fn
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: direct_fn
+; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 3
-; CHECK-NEXT: Name: call_direct
+; CHECK-NEXT: Name: direct_fn
; CHECK-NEXT: - Index: 4
-; CHECK-NEXT: Name: call_alias
+; CHECK-NEXT: Name: call_direct
; CHECK-NEXT: - Index: 5
-; CHECK-NEXT: Name: call_alias_ptr
+; CHECK-NEXT: Name: call_alias
; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Name: call_alias_ptr
+; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Name: call_direct_ptr
; CHECK-NEXT: ...
diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll
index 6a345ec0c63e..227906a55504 100644
--- a/test/wasm/weak-alias.ll
+++ b/test/wasm/weak-alias.ll
@@ -1,17 +1,19 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
-; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
+; RUN: wasm-ld %t.o %t2.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that weak aliases (alias_fn is a weak alias of direct_fn) are linked correctly
+target triple = "wasm32-unknown-unknown"
+
declare i32 @alias_fn() local_unnamed_addr #1
; Function Attrs: nounwind uwtable
-define i32 @_start() local_unnamed_addr #1 {
+define void @_start() local_unnamed_addr #1 {
entry:
%call = tail call i32 @alias_fn() #2
- ret i32 %call
+ ret void
}
; CHECK: --- !WASM
@@ -21,93 +23,288 @@ entry:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
-; CHECK-NEXT: Initial: 0x00000003
-; CHECK-NEXT: Maximum: 0x00000003
+; CHECK-NEXT: Initial: 0x00000002
+; CHECK-NEXT: Maximum: 0x00000002
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: alias_fn
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: direct_fn
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: call_direct
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: call_alias
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 3
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: call_alias_ptr
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Name: call_direct_ptr
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 5
+; CHECK-NEXT: Index: 6
; CHECK-NEXT: - Type: ELEM
-; CHECK-NEXT: Segments:
-; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1
-; CHECK-NEXT: Functions: [ 1, 1 ]
+; CHECK-NEXT: Functions: [ 2 ]
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1081808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080001A0B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1081808080000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1081808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080000B
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080000B
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
-; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Locals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
-; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081081808080002101200041106A24808080800020010B
-; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 0
+; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: _start
+; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: direct_fn
+; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: call_direct
+; CHECK-NEXT: Name: direct_fn
; CHECK-NEXT: - Index: 3
-; CHECK-NEXT: Name: call_alias
+; CHECK-NEXT: Name: call_direct
; CHECK-NEXT: - Index: 4
-; CHECK-NEXT: Name: call_alias_ptr
+; CHECK-NEXT: Name: call_alias
; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: call_alias_ptr
+; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Name: call_direct_ptr
; CHECK-NEXT: ...
+
+; RUN: wasm-ld --relocatable %t.o %t2.o -o %t.reloc.o
+; RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC
+
+; RELOC: --- !WASM
+; RELOC-NEXT: FileHeader:
+; RELOC-NEXT: Version: 0x00000001
+; RELOC-NEXT: Sections:
+; RELOC-NEXT: - Type: TYPE
+; RELOC-NEXT: Signatures:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: ReturnType: NORESULT
+; RELOC-NEXT: ParamTypes:
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: ReturnType: I32
+; RELOC-NEXT: ParamTypes:
+; RELOC-NEXT: - Type: IMPORT
+; RELOC-NEXT: Imports:
+; RELOC-NEXT: - Module: env
+; RELOC-NEXT: Field: __stack_pointer
+; RELOC-NEXT: Kind: GLOBAL
+; RELOC-NEXT: GlobalType: I32
+; RELOC-NEXT: GlobalMutable: true
+; RELOC-NEXT: - Type: FUNCTION
+; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ]
+; RELOC-NEXT: - Type: TABLE
+; RELOC-NEXT: Tables:
+; RELOC-NEXT: - ElemType: ANYFUNC
+; RELOC-NEXT: Limits:
+; RELOC-NEXT: Flags: [ HAS_MAX ]
+; RELOC-NEXT: Initial: 0x00000002
+; RELOC-NEXT: Maximum: 0x00000002
+; RELOC-NEXT: - Type: MEMORY
+; RELOC-NEXT: Memories:
+; RELOC-NEXT: - Initial: 0x00000000
+; RELOC-NEXT: - Type: ELEM
+; RELOC-NEXT: Segments:
+; RELOC-NEXT: - Offset:
+; RELOC-NEXT: Opcode: I32_CONST
+; RELOC-NEXT: Value: 1
+; RELOC-NEXT: Functions: [ 1 ]
+; RELOC-NEXT: - Type: CODE
+; RELOC-NEXT: Relocations:
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Offset: 0x00000004
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; RELOC-NEXT: Index: 1
+; RELOC-NEXT: Offset: 0x00000013
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Offset: 0x0000001C
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000027
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000032
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Offset: 0x0000003A
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Offset: 0x00000043
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000050
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x0000005D
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000068
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
+; RELOC-NEXT: Index: 1
+; RELOC-NEXT: Offset: 0x00000070
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; RELOC-NEXT: Index: 1
+; RELOC-NEXT: Offset: 0x00000079
+; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; RELOC-NEXT: Index: 6
+; RELOC-NEXT: Offset: 0x00000086
+; RELOC-NEXT: Functions:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 1081808080001A0B
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 41000B
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 1081808080000B
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: Body: 1081808080000B
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: - Type: I32
+; RELOC-NEXT: Count: 2
+; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Locals:
+; RELOC-NEXT: - Type: I32
+; RELOC-NEXT: Count: 2
+; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
+; RELOC-NEXT: - Type: CUSTOM
+; RELOC-NEXT: Name: linking
+; RELOC-NEXT: Version: 1
+; RELOC-NEXT: SymbolTable:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: _start
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 0
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: direct_fn
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 1
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: call_direct
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 2
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: call_alias
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 3
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: alias_fn
+; RELOC-NEXT: Flags: [ BINDING_WEAK ]
+; RELOC-NEXT: Function: 1
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: call_alias_ptr
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 4
+; RELOC-NEXT: - Index: 6
+; RELOC-NEXT: Kind: GLOBAL
+; RELOC-NEXT: Name: __stack_pointer
+; RELOC-NEXT: Flags: [ UNDEFINED ]
+; RELOC-NEXT: Global: 0
+; RELOC-NEXT: - Index: 7
+; RELOC-NEXT: Kind: FUNCTION
+; RELOC-NEXT: Name: call_direct_ptr
+; RELOC-NEXT: Flags: [ ]
+; RELOC-NEXT: Function: 5
+; RELOC-NEXT: - Type: CUSTOM
+; RELOC-NEXT: Name: name
+; RELOC-NEXT: FunctionNames:
+; RELOC-NEXT: - Index: 0
+; RELOC-NEXT: Name: _start
+; RELOC-NEXT: - Index: 1
+; RELOC-NEXT: Name: direct_fn
+; RELOC-NEXT: - Index: 2
+; RELOC-NEXT: Name: call_direct
+; RELOC-NEXT: - Index: 3
+; RELOC-NEXT: Name: call_alias
+; RELOC-NEXT: - Index: 4
+; RELOC-NEXT: Name: call_alias_ptr
+; RELOC-NEXT: - Index: 5
+; RELOC-NEXT: Name: call_direct_ptr
+; RELOC-NEXT: ...
diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll
index 4e4e2edfa9b2..bd45de39ca35 100644
--- a/test/wasm/weak-symbols.ll
+++ b/test/wasm/weak-symbols.ll
@@ -1,17 +1,19 @@
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol1.ll -o %t1.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol2.ll -o %t2.o
-; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -o %t.wasm %t.o %t1.o %t2.o
+; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t1.o
+; RUN: llc -filetype=obj %p/Inputs/weak-symbol2.ll -o %t2.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
+target triple = "wasm32-unknown-unknown"
+
declare i32 @weakFn() local_unnamed_addr
@weakGlobal = external global i32
-define i32 @_start() local_unnamed_addr {
+define void @_start() local_unnamed_addr {
entry:
%call = call i32 @weakFn()
%val = load i32, i32* @weakGlobal, align 4
- ret i32 %val
+ ret void
}
; CHECK: --- !WASM
@@ -21,10 +23,13 @@ entry:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@@ -37,45 +42,81 @@ entry:
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1032
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: weakFn
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: exportWeak1
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: weakGlobal
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: exportWeak2
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
+; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1
-; CHECK-NEXT: Functions: [ 1 ]
+; CHECK-NEXT: Functions: [ 2 ]
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 1081808080001A4100280280888080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080001A0B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41010B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4181808080000B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41020B
-; CHECK-NEXT: - Locals:
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4181808080000B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
@@ -86,15 +127,18 @@ entry:
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: Content: '0100000002000000'
; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 8
-; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: weakFn
+; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Name: exportWeak1
; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Name: weakFn
+; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Name: exportWeak2
; CHECK-NEXT: ...
diff --git a/test/wasm/weak-external.ll b/test/wasm/weak-undefined.ll
index e5025db53693..53b38bc32c3e 100644
--- a/test/wasm/weak-external.ll
+++ b/test/wasm/weak-undefined.ll
@@ -1,10 +1,12 @@
-; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
-; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: wasm-ld -strip-debug %t.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that undefined weak externals (global_var) and (foo) don't cause
; link failures and resolve to zero.
+target triple = "wasm32-unknown-unknown"
+
@global_var = extern_weak global i32, align 4
declare extern_weak i32 @foo()
@@ -18,10 +20,10 @@ define i32* @get_address_of_global_var() #0 {
ret i32* @global_var
}
-define i32 @_start() #0 {
+define void @_start() #0 {
entry:
- %0 = load i32, i32* @global_var, align 4
- ret i32 %0
+ %call = call i32* @get_address_of_global_var()
+ ret void
}
; CHECK: --- !WASM
@@ -31,56 +33,75 @@ entry:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
-; CHECK-NEXT: Initial: 0x00000002
-; CHECK-NEXT: Maximum: 0x00000002
+; CHECK-NEXT: Initial: 0x00000001
+; CHECK-NEXT: Maximum: 0x00000001
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
; CHECK-NEXT: - Initial: 0x00000002
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
-; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: true
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: false
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: __heap_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: __data_end
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: get_address_of_foo
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: get_address_of_global_var
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
-; CHECK-NEXT: - Type: ELEM
-; CHECK-NEXT: Segments:
-; CHECK-NEXT: - Offset:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1
-; CHECK-NEXT: Functions: [ 0 ]
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 4181808080000B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 41FFFFFFFF7F0B
-; CHECK-NEXT: - Locals:
-; CHECK-NEXT: Body: 41002802FFFFFFFF0F0B
-; CHECK-NEXT: - Type: CUSTOM
-; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 0
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 0B
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4180808080000B
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 4180808080000B
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 1082808080001A0B
; CHECK-NEXT: ...
diff --git a/test/wasm/whole-archive.test b/test/wasm/whole-archive.test
new file mode 100644
index 000000000000..814acbf432e7
--- /dev/null
+++ b/test/wasm/whole-archive.test
@@ -0,0 +1,34 @@
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
+RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+RUN: rm -f %t.a
+RUN: llvm-ar rcs %t.a %t.ret32.o
+
+Should not add symbols from the archive by default as they are not required
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a
+RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s
+NOTADDED: FunctionNames:
+NOTADDED-NOT: Name: ret32
+NOTADDED: ...
+
+Should add symbols from the archive if --whole-archive is used
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a
+RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s
+ADDED: FunctionNames:
+ADDED: Name: ret32
+ADDED: ...
+
+--no-whole-archive should restore default behaviour
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive --no-whole-archive %t.a
+RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s
+
+--whole-archive and --no-whole-archive should affect only archives which follow them
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a --whole-archive --no-whole-archive
+RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a --no-whole-archive
+RUN: obj2yaml %t.wasm | 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 %t.ret32.o
+RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %tthin.a
+RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
index 64e9aea25e39..4a8e3f7ec34a 100644
--- a/tools/lld/lld.cpp
+++ b/tools/lld/lld.cpp
@@ -7,12 +7,22 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the entry point to the lld driver. This is a thin wrapper which
-// dispatches to the given platform specific driver.
+// This file contains the main function of the lld executable. The main
+// function is a thin wrapper which dispatches to the 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].
+// lld is a single executable that contains four different linkers for ELF,
+// COFF, WebAssembly and Mach-O. The main function dispatches according to
+// argv[0] (i.e. command name). The most common name for each target is shown
+// below:
+//
+// - ld.lld: ELF (Unix)
+// - ld64: Mach-O (macOS)
+// - lld-link: COFF (Windows)
+// - ld-wasm: WebAssembly
+//
+// lld can be invoked as "lld" along with "-flavor" option. This is for
+// backward compatibility and not recommended.
//
//===----------------------------------------------------------------------===//
@@ -20,10 +30,9 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
+#include <cstdlib>
using namespace lld;
using namespace llvm;
@@ -102,28 +111,34 @@ static Flavor parseFlavor(std::vector<const char *> &V) {
return parseProgname(Arg0);
}
+// If this function returns true, lld calls _exit() so that it quickly
+// exits without invoking destructors of globally allocated objects.
+//
+// We don't want to do that if we are running tests though, because
+// doing that breaks leak sanitizer. So, lit sets this environment variable,
+// and we use it to detect whether we are running tests or not.
+static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; }
+
/// 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;
+ InitLLVM X(Argc, Argv);
std::vector<const char *> Args(Argv, Argv + Argc);
switch (parseFlavor(Args)) {
case Gnu:
if (isPETarget(Args))
return !mingw::link(Args);
- return !elf::link(Args, true);
+ return !elf::link(Args, canExitEarly());
case WinLink:
- return !coff::link(Args, true);
+ return !coff::link(Args, canExitEarly());
case Darwin:
- return !mach_o::link(Args);
+ return !mach_o::link(Args, canExitEarly());
case Wasm:
- return !wasm::link(Args, true);
+ return !wasm::link(Args, canExitEarly());
default:
die("lld is a generic driver.\n"
- "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");
+ "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld"
+ " (WebAssembly) instead");
}
}
diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp
index 696be69bc269..e2e634a4cb2d 100644
--- a/unittests/DriverTests/DarwinLdDriverTest.cpp
+++ b/unittests/DriverTests/DarwinLdDriverTest.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Darwin's ld driver tests.
+/// Darwin's ld driver tests.
///
//===----------------------------------------------------------------------===//
@@ -23,8 +23,7 @@ using namespace lld;
namespace lld {
namespace mach_o {
-bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
- raw_ostream &diagnostics);
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx);
}
}
@@ -42,9 +41,7 @@ protected:
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);
+ return mach_o::parse(args, _ctx);
}
MachOLinkingContext _ctx;
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
index 3e8793a0ef48..336bbdba6269 100644
--- a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
+++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
@@ -12,14 +12,17 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
#include "gtest/gtest.h"
#include <cstdint>
#include <memory>
+using llvm::SmallString;
using llvm::StringRef;
using llvm::MemoryBuffer;
+using llvm::Twine;
using namespace lld::mach_o::normalized;
using namespace llvm::MachO;
@@ -741,9 +744,11 @@ TEST(BinaryReaderTest, hello_obj_ppc) {
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));
+ SmallString<128> tmpFl;
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ llvm::Error ec2 = writeBinary(*f, tmpFl);
+ EXPECT_FALSE(ec2);
+ llvm::sys::fs::remove(tmpFl);
}
diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt
index 19b0d168437c..1a9e09b38429 100644
--- a/wasm/CMakeLists.txt
+++ b/wasm/CMakeLists.txt
@@ -2,10 +2,16 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)
add_public_tablegen_target(WasmOptionsTableGen)
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
add_lld_library(lldWasm
Driver.cpp
+ InputChunks.cpp
InputFiles.cpp
- InputSegment.cpp
+ LTO.cpp
+ MarkLive.cpp
OutputSections.cpp
SymbolTable.cpp
Symbols.cpp
@@ -17,10 +23,16 @@ add_lld_library(lldWasm
BinaryFormat
Core
Demangle
+ LTO
+ MC
Object
Option
Support
LINK_LIBS
lldCommon
- )
+
+ DEPENDS
+ WasmOptionsTableGen
+ ${tablegen_deps}
+ ) \ No newline at end of file
diff --git a/wasm/Config.h b/wasm/Config.h
index 82f49ce175bb..76a780567072 100644
--- a/wasm/Config.h
+++ b/wasm/Config.h
@@ -13,33 +13,43 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/Wasm.h"
-
-#include "Symbols.h"
-
-using llvm::wasm::WasmGlobal;
+#include "llvm/Support/CachePruning.h"
namespace lld {
namespace wasm {
struct Configuration {
bool AllowUndefined;
- bool CheckSignatures;
+ bool CompressRelocTargets;
bool Demangle;
- bool EmitRelocs;
+ bool DisableVerify;
+ bool ExportAll;
+ bool ExportTable;
+ bool GcSections;
bool ImportMemory;
+ bool ImportTable;
+ bool MergeDataSegments;
+ bool PrintGcSections;
bool Relocatable;
+ bool SaveTemps;
bool StripAll;
bool StripDebug;
+ bool StackFirst;
uint32_t GlobalBase;
uint32_t InitialMemory;
uint32_t MaxMemory;
uint32_t ZStackSize;
+ unsigned LTOPartitions;
+ unsigned LTOO;
+ unsigned Optimize;
+ unsigned ThinLTOJobs;
llvm::StringRef Entry;
llvm::StringRef OutputFile;
+ llvm::StringRef ThinLTOCacheDir;
llvm::StringSet<> AllowUndefinedSymbols;
std::vector<llvm::StringRef> SearchPaths;
- Symbol *StackPointerSymbol = nullptr;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
};
// The only instance of Configuration struct.
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 97ec262be308..329b5ae80a9c 100644
--- a/wasm/Driver.cpp
+++ b/wasm/Driver.cpp
@@ -9,11 +9,15 @@
#include "lld/Common/Driver.h"
#include "Config.h"
+#include "InputChunks.h"
+#include "InputGlobal.h"
+#include "MarkLive.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Twine.h"
@@ -22,6 +26,9 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetSelect.h"
+
+#define DEBUG_TYPE "lld"
using namespace llvm;
using namespace llvm::sys;
@@ -30,14 +37,9 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
-namespace {
+Configuration *lld::wasm::Config;
-// Parses command line options.
-class WasmOptTable : public llvm::opt::OptTable {
-public:
- WasmOptTable();
- llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
-};
+namespace {
// Create enum with OPT_xxx values for each option in Options.td
enum {
@@ -47,24 +49,36 @@ enum {
#undef OPTION
};
+// 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() {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+}
+
class LinkerDriver {
public:
void link(ArrayRef<const char *> ArgsArr);
private:
- void createFiles(llvm::opt::InputArgList &Args);
+ void createFiles(opt::InputArgList &Args);
void addFile(StringRef Path);
void addLibrary(StringRef Name);
+
+ // True if we are in --whole-archive and --no-whole-archive.
+ bool InWholeArchive = false;
+
std::vector<InputFile *> Files;
};
-
} // anonymous namespace
-Configuration *lld::wasm::Config;
-
bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorOS = &Error;
errorHandler().ColorDiagnostics = Error.has_colors();
errorHandler().ErrorLimitExceededMsg =
@@ -74,6 +88,7 @@ bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
Config = make<Configuration>();
Symtab = make<SymbolTable>();
+ initLLVM();
LinkerDriver().link(Args);
// Exit immediately if we don't need to return to the caller.
@@ -86,8 +101,6 @@ bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
return !errorCount();
}
-// Create OptTable
-
// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
@@ -102,6 +115,14 @@ static const opt::OptTable::Info OptInfo[] = {
#undef OPTION
};
+namespace {
+class WasmOptTable : public llvm::opt::OptTable {
+public:
+ WasmOptTable() : OptTable(OptInfo) {}
+ opt::InputArgList parse(ArrayRef<const char *> Argv);
+};
+} // namespace
+
// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &Args) {
@@ -109,19 +130,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) {
OPT_no_color_diagnostics);
if (!Arg)
return;
-
- if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
- if (S == "never")
+ else if (S == "never")
errorHandler().ColorDiagnostics = false;
- if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -134,25 +154,15 @@ static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
return None;
}
-// Inject a new undefined symbol into the link. This will cause the link to
-// fail unless this symbol can be found.
-static void addSyntheticUndefinedFunction(StringRef Name,
- const WasmSignature *Type) {
- log("injecting undefined func: " + Name);
- Symtab->addUndefinedFunction(Name, Type);
-}
-
-static void printHelp(const char *Argv0) {
- WasmOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false);
-}
-
-WasmOptTable::WasmOptTable() : OptTable(OptInfo) {}
-
opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
unsigned MissingIndex;
unsigned MissingCount;
+
+ // Expand response files (arguments in the form of @<filename>)
+ cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec);
+
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
@@ -161,16 +171,80 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
return Args;
}
+// Currently we allow a ".imports" to live alongside a library. This can
+// be used to specify a list of symbols which can be undefined at link
+// time (imported from the environment. For example libc.a include an
+// import file that lists the syscall functions it relies on at runtime.
+// In the long run this information would be better stored as a symbol
+// attribute/flag in the object file itself.
+// See: https://github.com/WebAssembly/tool-conventions/issues/35
+static void readImportFile(StringRef Filename) {
+ if (Optional<MemoryBufferRef> Buf = readFile(Filename))
+ for (StringRef Sym : args::getLines(*Buf))
+ Config->AllowUndefinedSymbols.insert(Sym);
+}
+
+// Returns slices of MB by parsing MB as an archive file.
+// Each slice consists of a member file in the archive.
+std::vector<MemoryBufferRef> static getArchiveMembers(
+ MemoryBufferRef MB) {
+ std::unique_ptr<Archive> File =
+ CHECK(Archive::create(MB),
+ MB.getBufferIdentifier() + ": failed to parse archive");
+
+ std::vector<MemoryBufferRef> V;
+ Error Err = Error::success();
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C =
+ CHECK(COrErr, MB.getBufferIdentifier() +
+ ": could not get the child of the archive");
+ MemoryBufferRef MBRef =
+ CHECK(C.getMemoryBufferRef(),
+ MB.getBufferIdentifier() +
+ ": could not get the buffer for a child of the archive");
+ V.push_back(MBRef);
+ }
+ if (Err)
+ fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
+ toString(std::move(Err)));
+
+ // Take ownership of memory buffers created for members of thin archives.
+ for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB));
+
+ return V;
+}
+
void LinkerDriver::addFile(StringRef Path) {
Optional<MemoryBufferRef> Buffer = readFile(Path);
if (!Buffer.hasValue())
return;
MemoryBufferRef MBRef = *Buffer;
- if (identify_magic(MBRef.getBuffer()) == file_magic::archive)
+ switch (identify_magic(MBRef.getBuffer())) {
+ case file_magic::archive: {
+ // Handle -whole-archive.
+ if (InWholeArchive) {
+ for (MemoryBufferRef &M : getArchiveMembers(MBRef))
+ Files.push_back(createObjectFile(M));
+ return;
+ }
+
+ SmallString<128> ImportFile = Path;
+ path::replace_extension(ImportFile, ".imports");
+ if (fs::exists(ImportFile))
+ readImportFile(ImportFile.str());
+
Files.push_back(make<ArchiveFile>(MBRef));
- else
- Files.push_back(make<ObjFile>(MBRef));
+ return;
+ }
+ case file_magic::bitcode:
+ case file_magic::wasm_object:
+ Files.push_back(createObjectFile(MBRef));
+ break;
+ default:
+ error("unknown file type: " + MBRef.getBufferIdentifier());
+ }
}
// Add a given library by searching it from input search paths.
@@ -194,11 +268,14 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_INPUT:
addFile(Arg->getValue());
break;
+ case OPT_whole_archive:
+ InWholeArchive = true;
+ break;
+ case OPT_no_whole_archive:
+ InWholeArchive = false;
+ break;
}
}
-
- if (Files.empty())
- error("no input files");
}
static StringRef getEntry(opt::InputArgList &Args, StringRef Default) {
@@ -210,13 +287,71 @@ static StringRef getEntry(opt::InputArgList &Args, StringRef Default) {
return Arg->getValue();
}
+static const uint8_t UnreachableFn[] = {
+ 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
+ 0x00 /* opcode unreachable */, 0x0b /* opcode end */
+};
+
+// For weak undefined functions, there may be "call" instructions that reference
+// the symbol. In this case, we need to synthesise a dummy/stub function that
+// will abort at runtime, so that relocations can still provided an operand to
+// the call instruction that passes Wasm validation.
+static void handleWeakUndefines() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (!Sym->isUndefined() || !Sym->isWeak())
+ continue;
+ auto *FuncSym = dyn_cast<FunctionSymbol>(Sym);
+ if (!FuncSym)
+ continue;
+
+ // It is possible for undefined functions not to have a signature (eg. if
+ // added via "--undefined"), but weak undefined ones do have a signature.
+ assert(FuncSym->FunctionType);
+ const WasmSignature &Sig = *FuncSym->FunctionType;
+
+ // Add a synthetic dummy for weak undefined functions. These dummies will
+ // be GC'd if not used as the target of any "call" instructions.
+ Optional<std::string> SymName = demangleItanium(Sym->getName());
+ StringRef DebugName =
+ Saver.save("undefined function " +
+ (SymName ? StringRef(*SymName) : Sym->getName()));
+ SyntheticFunction *Func =
+ make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
+ Func->setBody(UnreachableFn);
+ // Ensure it compares equal to the null pointer, and so that table relocs
+ // don't pull in the stub body (only call-operand relocs should do that).
+ Func->setTableIndex(0);
+ Symtab->SyntheticFunctions.emplace_back(Func);
+ // Hide our dummy to prevent export.
+ uint32_t Flags = WASM_SYMBOL_VISIBILITY_HIDDEN;
+ replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Flags, nullptr, Func);
+ }
+}
+
+// Force Sym to be entered in the output. Used for -u or equivalent.
+static Symbol *addUndefined(StringRef Name) {
+ Symbol *S = Symtab->addUndefinedFunction(Name, 0, nullptr, nullptr);
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ S->IsUsedInRegularObj = true;
+
+ return S;
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
WasmOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
// Handle --help
if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ Parser.PrintHelp(outs(), ArgsArr[0], "LLVM Linker", false);
+ return;
+ }
+
+ // Handle --version
+ if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
+ outs() << getLLDVersion() << "\n";
return;
}
@@ -229,26 +364,40 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
- if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
- outs() << getLLDVersion() << "\n";
- return;
- }
-
Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
- Config->CheckSignatures =
- Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false);
- Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+ Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start");
+ Config->ExportAll = Args.hasArg(OPT_export_all);
+ Config->ExportTable = Args.hasArg(OPT_export_table);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->ImportMemory = Args.hasArg(OPT_import_memory);
+ Config->ImportTable = Args.hasArg(OPT_import_table);
+ Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->Optimize = args::getInteger(Args, OPT_O, 0);
Config->OutputFile = Args.getLastArgValue(OPT_o);
Config->Relocatable = Args.hasArg(OPT_relocatable);
+ Config->GcSections =
+ Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable);
+ Config->MergeDataSegments =
+ Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
+ !Config->Relocatable);
+ Config->PrintGcSections =
+ Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->SearchPaths = args::getStrings(Args, OPT_L);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->StripDebug = Args.hasArg(OPT_strip_debug);
+ Config->StackFirst = Args.hasArg(OPT_stack_first);
+ Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy = CHECK(
+ parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
errorHandler().Verbose = Args.hasArg(OPT_verbose);
ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
- if (Config->Relocatable)
- Config->EmitRelocs = true;
Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0);
Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024);
@@ -256,33 +405,72 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->ZStackSize =
args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);
+ Config->CompressRelocTargets = Config->Optimize > 0 && !Config->Relocatable;
+
+ if (Config->LTOO > 3)
+ error("invalid optimization level for LTO: " + Twine(Config->LTOO));
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
+
if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
- if (Optional<MemoryBufferRef> Buf = readFile(Arg->getValue()))
- for (StringRef Sym : args::getLines(*Buf))
- Config->AllowUndefinedSymbols.insert(Sym);
+ readImportFile(Arg->getValue());
+
+ if (!Args.hasArg(OPT_INPUT)) {
+ error("no input files");
+ return;
+ }
if (Config->OutputFile.empty())
error("no output file specified");
- if (!Args.hasArg(OPT_INPUT))
- error("no input files");
+ if (Config->ImportTable && Config->ExportTable)
+ error("--import-table and --export-table may not be used together");
- if (Config->Relocatable && !Config->Entry.empty())
- error("entry point specified for relocatable output file");
- if (Config->Relocatable && Args.hasArg(OPT_undefined))
- error("undefined symbols specified for relocatable output file");
+ if (Config->Relocatable) {
+ if (!Config->Entry.empty())
+ error("entry point specified for relocatable output file");
+ if (Config->GcSections)
+ error("-r and --gc-sections may not be used together");
+ if (Args.hasArg(OPT_undefined))
+ error("-r -and --undefined may not be used together");
+ }
+ Symbol *EntrySym = nullptr;
if (!Config->Relocatable) {
- if (!Config->Entry.empty()) {
- static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
- addSyntheticUndefinedFunction(Config->Entry, &Signature);
- }
+ llvm::wasm::WasmGlobal Global;
+ Global.Type = {WASM_TYPE_I32, true};
+ Global.InitExpr.Value.Int32 = 0;
+ Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ Global.SymbolName = "__stack_pointer";
+ InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr);
+ StackPointer->Live = true;
+
+ static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT};
+
+ // Add synthetic symbols before any others
+ WasmSym::CallCtors = Symtab->addSyntheticFunction(
+ "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
+ // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global
+ // spec proposal is implemented in all major browsers.
+ // See: https://github.com/WebAssembly/mutable-global
+ WasmSym::StackPointer = Symtab->addSyntheticGlobal(
+ "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);
+ WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0);
+ WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
+ "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
+ WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0);
+
+ // For now, since we don't actually use the start function as the
+ // wasm start symbol, we don't need to care about it signature.
+ if (!Config->Entry.empty())
+ EntrySym = addUndefined(Config->Entry);
// Handle the `--undefined <sym>` options.
- for (StringRef S : args::getStrings(Args, OPT_undefined))
- addSyntheticUndefinedFunction(S, nullptr);
-
- Config->StackPointerSymbol = Symtab->addDefinedGlobal("__stack_pointer");
+ for (auto *Arg : Args.filtered(OPT_undefined))
+ addUndefined(Arg->getValue());
}
createFiles(Args);
@@ -293,29 +481,59 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// symbols that we need to the symbol table.
for (InputFile *F : Files)
Symtab->addFile(F);
+ if (errorCount())
+ return;
+
+ // Add synthetic dummies for weak undefined functions.
+ if (!Config->Relocatable)
+ handleWeakUndefines();
+
+ // Handle --export.
+ for (auto *Arg : Args.filtered(OPT_export)) {
+ StringRef Name = Arg->getValue();
+ Symbol *Sym = Symtab->find(Name);
+ if (Sym && Sym->isDefined())
+ Sym->ForceExport = true;
+ else if (!Config->AllowUndefined)
+ error("symbol exported via --export not found: " + Name);
+ }
+
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
+ Symtab->addCombinedLTOObject();
+ if (errorCount())
+ return;
// Make sure we have resolved all symbols.
if (!Config->Relocatable && !Config->AllowUndefined) {
Symtab->reportRemainingUndefines();
} else {
- // When we allow undefined symbols we cannot include those defined in
- // -u/--undefined since these undefined symbols have only names and no
- // function signature, which means they cannot be written to the final
- // output.
- for (StringRef S : args::getStrings(Args, OPT_undefined)) {
- Symbol *Sym = Symtab->find(S);
+ // Even when using --allow-undefined we still want to report the absence of
+ // our initial set of undefined symbols (i.e. the entry point and symbols
+ // specified via --undefined).
+ // Part of the reason for this is that these function don't have signatures
+ // so which means they cannot be written as wasm function imports.
+ for (auto *Arg : Args.filtered(OPT_undefined)) {
+ Symbol *Sym = Symtab->find(Arg->getValue());
if (!Sym->isDefined())
- error("function forced with --undefined not found: " + Sym->getName());
+ error("symbol forced with --undefined not found: " + Sym->getName());
}
+ if (EntrySym && !EntrySym->isDefined())
+ error("entry symbol not defined (pass --no-entry to supress): " +
+ EntrySym->getName());
}
if (errorCount())
return;
- if (!Config->Entry.empty() && !Symtab->find(Config->Entry)->isDefined())
- error("entry point not found: " + Config->Entry);
+ if (EntrySym)
+ EntrySym->setHidden(false);
+
if (errorCount())
return;
+ // Do size optimizations: garbage collection
+ markLive();
+
// Write the result to the file.
writeResult();
}
diff --git a/wasm/InputChunks.cpp b/wasm/InputChunks.cpp
new file mode 100644
index 000000000000..fcefac7d99b8
--- /dev/null
+++ b/wasm/InputChunks.cpp
@@ -0,0 +1,295 @@
+//===- InputChunks.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputChunks.h"
+#include "Config.h"
+#include "OutputSegment.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/Support/LEB128.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace llvm::wasm;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::wasm;
+
+static StringRef ReloctTypeToString(uint8_t RelocType) {
+ switch (RelocType) {
+#define WASM_RELOC(NAME, REL) case REL: return #NAME;
+#include "llvm/BinaryFormat/WasmRelocs.def"
+#undef WASM_RELOC
+ }
+ llvm_unreachable("unknown reloc type");
+}
+
+std::string lld::toString(const InputChunk *C) {
+ return (toString(C->File) + ":(" + C->getName() + ")").str();
+}
+
+StringRef InputChunk::getComdatName() const {
+ uint32_t Index = getComdat();
+ if (Index == UINT32_MAX)
+ return StringRef();
+ return File->getWasmObj()->linkingData().Comdats[Index];
+}
+
+void InputChunk::copyRelocations(const WasmSection &Section) {
+ if (Section.Relocations.empty())
+ return;
+ size_t Start = getInputSectionOffset();
+ size_t Size = getInputSize();
+ for (const WasmRelocation &R : Section.Relocations)
+ if (R.Offset >= Start && R.Offset < Start + Size)
+ Relocations.push_back(R);
+}
+
+void InputChunk::verifyRelocTargets() const {
+ for (const WasmRelocation &Rel : Relocations) {
+ uint32_t ExistingValue;
+ unsigned BytesRead = 0;
+ uint32_t Offset = Rel.Offset - getInputSectionOffset();
+ const uint8_t *Loc = data().data() + Offset;
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ ExistingValue = decodeULEB128(Loc, &BytesRead);
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead));
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_I32:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ ExistingValue = static_cast<uint32_t>(read32le(Loc));
+ break;
+ default:
+ llvm_unreachable("unknown relocation type");
+ }
+
+ if (BytesRead && BytesRead != 5)
+ warn("expected LEB at relocation site be 5-byte padded");
+ uint32_t ExpectedValue = File->calcExpectedValue(Rel);
+ if (ExpectedValue != ExistingValue)
+ warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) +
+ ": existing=" + Twine(ExistingValue) +
+ " expected=" + Twine(ExpectedValue));
+ }
+}
+
+// Copy this input chunk to an mmap'ed output file and apply relocations.
+void InputChunk::writeTo(uint8_t *Buf) const {
+ // Copy contents
+ memcpy(Buf + OutputOffset, data().data(), data().size());
+
+ // Apply relocations
+ if (Relocations.empty())
+ return;
+
+#ifndef NDEBUG
+ verifyRelocTargets();
+#endif
+
+ LLVM_DEBUG(dbgs() << "applying relocations: " << getName()
+ << " count=" << Relocations.size() << "\n");
+ int32_t Off = OutputOffset - getInputSectionOffset();
+
+ for (const WasmRelocation &Rel : Relocations) {
+ uint8_t *Loc = Buf + Rel.Offset + Off;
+ uint32_t Value = File->calcNewValue(Rel);
+ LLVM_DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type)
+ << " addend=" << Rel.Addend << " index=" << Rel.Index
+ << " value=" << Value << " offset=" << Rel.Offset
+ << "\n");
+
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ encodeULEB128(Value, Loc, 5);
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_I32:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ write32le(Loc, Value);
+ break;
+ default:
+ llvm_unreachable("unknown relocation type");
+ }
+ }
+}
+
+// Copy relocation entries to a given output stream.
+// This function is used only when a user passes "-r". For a regular link,
+// we consume relocations instead of copying them to an output file.
+void InputChunk::writeRelocations(raw_ostream &OS) const {
+ if (Relocations.empty())
+ return;
+
+ int32_t Off = OutputOffset - getInputSectionOffset();
+ LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()
+ << " offset=" << Twine(Off) << "\n");
+
+ for (const WasmRelocation &Rel : Relocations) {
+ writeUleb128(OS, Rel.Type, "reloc type");
+ writeUleb128(OS, Rel.Offset + Off, "reloc offset");
+ writeUleb128(OS, File->calcNewIndex(Rel), "reloc index");
+
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
+ break;
+ }
+ }
+}
+
+void InputFunction::setFunctionIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()
+ << " -> " << Index << "\n");
+ assert(!hasFunctionIndex());
+ FunctionIndex = Index;
+}
+
+void InputFunction::setTableIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "
+ << Index << "\n");
+ assert(!hasTableIndex());
+ TableIndex = Index;
+}
+
+// Write a relocation value without padding and return the number of bytes
+// witten.
+static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
+ uint32_t Value) {
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ return encodeULEB128(Value, Buf);
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ return encodeSLEB128(static_cast<int32_t>(Value), Buf);
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
+}
+
+static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ return 5;
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
+}
+
+static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
+ uint8_t Buf[5];
+ return writeCompressedReloc(Buf, Rel, Value);
+}
+
+// Relocations of type LEB and SLEB in the code section are padded to 5 bytes
+// so that a fast linker can blindly overwrite them without needing to worry
+// about the number of bytes needed to encode the values.
+// However, for optimal output the code section can be compressed to remove
+// the padding then outputting non-relocatable files.
+// In this case we need to perform a size calculation based on the value at each
+// relocation. At best we end up saving 4 bytes for each relocation entry.
+//
+// This function only computes the final output size. It must be called
+// before getSize() is used to calculate of layout of the code section.
+void InputFunction::calculateSize() {
+ if (!File || !Config->CompressRelocTargets)
+ return;
+
+ LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n");
+
+ const uint8_t *SecStart = File->CodeSection->Content.data();
+ const uint8_t *FuncStart = SecStart + getInputSectionOffset();
+ uint32_t FunctionSizeLength;
+ decodeULEB128(FuncStart, &FunctionSizeLength);
+
+ uint32_t Start = getInputSectionOffset();
+ uint32_t End = Start + Function->Size;
+
+ uint32_t LastRelocEnd = Start + FunctionSizeLength;
+ for (WasmRelocation &Rel : Relocations) {
+ LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n");
+ CompressedFuncSize += Rel.Offset - LastRelocEnd;
+ CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
+ LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel);
+ }
+ LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n");
+ CompressedFuncSize += End - LastRelocEnd;
+
+ // Now we know how long the resulting function is we can add the encoding
+ // of its length
+ uint8_t Buf[5];
+ CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf);
+
+ LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n");
+ LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n");
+}
+
+// Override the default writeTo method so that we can (optionally) write the
+// compressed version of the function.
+void InputFunction::writeTo(uint8_t *Buf) const {
+ if (!File || !Config->CompressRelocTargets)
+ return InputChunk::writeTo(Buf);
+
+ Buf += OutputOffset;
+ uint8_t *Orig = Buf; (void)Orig;
+
+ const uint8_t *SecStart = File->CodeSection->Content.data();
+ const uint8_t *FuncStart = SecStart + getInputSectionOffset();
+ const uint8_t *End = FuncStart + Function->Size;
+ uint32_t Count;
+ decodeULEB128(FuncStart, &Count);
+ FuncStart += Count;
+
+ LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n");
+ Buf += encodeULEB128(CompressedFuncSize, Buf);
+ const uint8_t *LastRelocEnd = FuncStart;
+ for (const WasmRelocation &Rel : Relocations) {
+ unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n");
+ memcpy(Buf, LastRelocEnd, ChunkSize);
+ Buf += ChunkSize;
+ Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel));
+ LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel);
+ }
+
+ unsigned ChunkSize = End - LastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n");
+ memcpy(Buf, LastRelocEnd, ChunkSize);
+ LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n");
+}
diff --git a/wasm/InputChunks.h b/wasm/InputChunks.h
new file mode 100644
index 000000000000..526e29870b21
--- /dev/null
+++ b/wasm/InputChunks.h
@@ -0,0 +1,236 @@
+//===- InputChunks.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An InputChunks represents an indivisible opaque region of a input wasm file.
+// i.e. a single wasm data segment or a single wasm function.
+//
+// They are written directly to the mmap'd output file after which relocations
+// are applied. Because each Chunk is independent they can be written in
+// parallel.
+//
+// Chunks are also unit on which garbage collection (--gc-sections) operates.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_CHUNKS_H
+#define LLD_WASM_INPUT_CHUNKS_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+using llvm::object::WasmSection;
+using llvm::object::WasmSegment;
+using llvm::wasm::WasmFunction;
+using llvm::wasm::WasmRelocation;
+using llvm::wasm::WasmSignature;
+
+namespace llvm {
+class raw_ostream;
+}
+
+namespace lld {
+namespace wasm {
+
+class ObjFile;
+class OutputSegment;
+
+class InputChunk {
+public:
+ enum Kind { DataSegment, Function, SyntheticFunction, Section };
+
+ Kind kind() const { return SectionKind; }
+
+ virtual uint32_t getSize() const { return data().size(); }
+
+ void copyRelocations(const WasmSection &Section);
+
+ virtual void writeTo(uint8_t *SectionStart) const;
+
+ ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
+
+ virtual StringRef getName() const = 0;
+ virtual StringRef getDebugName() const = 0;
+ virtual uint32_t getComdat() const = 0;
+ StringRef getComdatName() const;
+
+ size_t NumRelocations() const { return Relocations.size(); }
+ void writeRelocations(llvm::raw_ostream &OS) const;
+
+ ObjFile *File;
+ int32_t OutputOffset = 0;
+
+ // Signals that the section is part of the output. The garbage collector,
+ // and COMDAT handling can set a sections' Live bit.
+ // If GC is disabled, all sections start out as live by default.
+ unsigned Live : 1;
+
+protected:
+ InputChunk(ObjFile *F, Kind K)
+ : File(F), Live(!Config->GcSections), SectionKind(K) {}
+ virtual ~InputChunk() = default;
+ virtual ArrayRef<uint8_t> data() const = 0;
+ virtual uint32_t getInputSectionOffset() const = 0;
+ virtual uint32_t getInputSize() const { return getSize(); };
+
+ // Verifies the existing data at relocation targets matches our expectations.
+ // This is performed only debug builds as an extra sanity check.
+ void verifyRelocTargets() const;
+
+ std::vector<WasmRelocation> Relocations;
+ Kind SectionKind;
+};
+
+// Represents a WebAssembly data segment which can be included as part of
+// an output data segments. Note that in WebAssembly, unlike ELF and other
+// formats, used the term "data segment" to refer to the continous regions of
+// memory that make on the data section. See:
+// https://webassembly.github.io/spec/syntax/modules.html#syntax-data
+//
+// For example, by default, clang will produce a separate data section for
+// each global variable.
+class InputSegment : public InputChunk {
+public:
+ InputSegment(const WasmSegment &Seg, ObjFile *F)
+ : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {}
+
+ static bool classof(const InputChunk *C) { return C->kind() == DataSegment; }
+
+ uint32_t getAlignment() const { return Segment.Data.Alignment; }
+ StringRef getName() const override { return Segment.Data.Name; }
+ StringRef getDebugName() const override { return StringRef(); }
+ uint32_t getComdat() const override { return Segment.Data.Comdat; }
+
+ const OutputSegment *OutputSeg = nullptr;
+ int32_t OutputSegmentOffset = 0;
+
+protected:
+ ArrayRef<uint8_t> data() const override { return Segment.Data.Content; }
+ uint32_t getInputSectionOffset() const override {
+ return Segment.SectionOffset;
+ }
+
+ const WasmSegment &Segment;
+};
+
+// Represents a single wasm function within and input file. These are
+// combined to create the final output CODE section.
+class InputFunction : public InputChunk {
+public:
+ InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F)
+ : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {}
+
+ static bool classof(const InputChunk *C) {
+ return C->kind() == InputChunk::Function ||
+ C->kind() == InputChunk::SyntheticFunction;
+ }
+
+ void writeTo(uint8_t *SectionStart) const override;
+ StringRef getName() const override { return Function->SymbolName; }
+ StringRef getDebugName() const override { return Function->DebugName; }
+ uint32_t getComdat() const override { return Function->Comdat; }
+ uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
+ uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
+ uint32_t getSize() const override {
+ if (Config->CompressRelocTargets && File) {
+ assert(CompressedSize);
+ return CompressedSize;
+ }
+ return data().size();
+ }
+ uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
+ bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
+ void setFunctionIndex(uint32_t Index);
+ uint32_t getTableIndex() const { return TableIndex.getValue(); }
+ bool hasTableIndex() const { return TableIndex.hasValue(); }
+ void setTableIndex(uint32_t Index);
+
+ // The size of a given input function can depend on the values of the
+ // LEB relocations within it. This finalizeContents method is called after
+ // all the symbol values have be calcualted but before getSize() is ever
+ // called.
+ void calculateSize();
+
+ const WasmSignature &Signature;
+
+protected:
+ ArrayRef<uint8_t> data() const override {
+ assert(!Config->CompressRelocTargets);
+ return File->CodeSection->Content.slice(getInputSectionOffset(),
+ Function->Size);
+ }
+
+ uint32_t getInputSize() const override { return Function->Size; }
+
+ uint32_t getInputSectionOffset() const override {
+ return Function->CodeSectionOffset;
+ }
+
+ const WasmFunction *Function;
+ llvm::Optional<uint32_t> FunctionIndex;
+ llvm::Optional<uint32_t> TableIndex;
+ uint32_t CompressedFuncSize = 0;
+ uint32_t CompressedSize = 0;
+};
+
+class SyntheticFunction : public InputFunction {
+public:
+ SyntheticFunction(const WasmSignature &S, StringRef Name,
+ StringRef DebugName = {})
+ : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) {
+ SectionKind = InputChunk::SyntheticFunction;
+ }
+
+ static bool classof(const InputChunk *C) {
+ return C->kind() == InputChunk::SyntheticFunction;
+ }
+
+ StringRef getName() const override { return Name; }
+ StringRef getDebugName() const override { return DebugName; }
+ uint32_t getComdat() const override { return UINT32_MAX; }
+
+ void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; }
+
+protected:
+ ArrayRef<uint8_t> data() const override { return Body; }
+
+ StringRef Name;
+ StringRef DebugName;
+ ArrayRef<uint8_t> Body;
+};
+
+// Represents a single Wasm Section within an input file.
+class InputSection : public InputChunk {
+public:
+ InputSection(const WasmSection &S, ObjFile *F)
+ : InputChunk(F, InputChunk::Section), Section(S) {
+ assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
+ }
+
+ StringRef getName() const override { return Section.Name; }
+ StringRef getDebugName() const override { return StringRef(); }
+ uint32_t getComdat() const override { return UINT32_MAX; }
+
+protected:
+ ArrayRef<uint8_t> data() const override { return Section.Content; }
+
+ // Offset within the input section. This is only zero since this chunk
+ // type represents an entire input section, not part of one.
+ uint32_t getInputSectionOffset() const override { return 0; }
+
+ const WasmSection &Section;
+};
+
+} // namespace wasm
+
+std::string toString(const wasm::InputChunk *);
+} // namespace lld
+
+#endif // LLD_WASM_INPUT_CHUNKS_H
diff --git a/wasm/InputFiles.cpp b/wasm/InputFiles.cpp
index 1a1a6812c48e..53a24c3cffd4 100644
--- a/wasm/InputFiles.cpp
+++ b/wasm/InputFiles.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
-
#include "Config.h"
-#include "InputSegment.h"
+#include "InputChunks.h"
+#include "InputGlobal.h"
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -42,64 +42,126 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
return MBRef;
}
-void ObjFile::dumpInfo() const {
- log("reloc info for: " + getName() + "\n" +
- " FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" +
- " NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" +
- " NumGlobalImports : " + Twine(NumGlobalImports()) + "\n");
-}
+InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB) {
+ file_magic Magic = identify_magic(MB.getBuffer());
+ if (Magic == file_magic::wasm_object)
+ return make<ObjFile>(MB);
-bool ObjFile::isImportedFunction(uint32_t Index) const {
- return Index < NumFunctionImports();
-}
+ if (Magic == file_magic::bitcode)
+ return make<BitcodeFile>(MB);
-Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
- return FunctionSymbols[Index];
+ fatal("unknown file type: " + MB.getBufferIdentifier());
}
-Symbol *ObjFile::getTableSymbol(uint32_t Index) const {
- return TableSymbols[Index];
-}
-
-Symbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
- return GlobalSymbols[Index];
-}
-
-uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const {
- return getGlobalSymbol(Index)->getVirtualAddress();
+void ObjFile::dumpInfo() const {
+ log("info for: " + getName() +
+ "\n Symbols : " + Twine(Symbols.size()) +
+ "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) +
+ "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()));
}
-uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
- Symbol *Sym = getFunctionSymbol(Original);
- uint32_t Index = Sym->getOutputIndex();
- DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": "
- << Original << " -> " << Index << "\n");
- return Index;
+// Relocations contain either symbol or type indices. This function takes a
+// relocation and returns relocated index (i.e. translates from the input
+// sybmol/type space to the output symbol/type space).
+uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
+ if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) {
+ assert(TypeIsUsed[Reloc.Index]);
+ return TypeMap[Reloc.Index];
+ }
+ return Symbols[Reloc.Index]->getOutputSymbolIndex();
}
-uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
- return TypeMap[Original];
+// Relocations can contain addend for combined sections. This function takes a
+// relocation and returns updated addend by offset in the output section.
+uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
+ switch (Reloc.Type) {
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ return Reloc.Addend;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
}
-uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
- Symbol *Sym = getTableSymbol(Original);
- uint32_t Index = Sym->getTableIndex();
- DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
- << " -> " << Index << "\n");
- return Index;
+// Calculate the value we expect to find at the relocation location.
+// This is used as a sanity check before applying a relocation to a given
+// location. It is useful for catching bugs in the compiler and linker.
+uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
+ switch (Reloc.Type) {
+ case R_WEBASSEMBLY_TABLE_INDEX_I32:
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB: {
+ const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index];
+ return TableEntries[Sym.Info.ElementIndex];
+ }
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB: {
+ const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index];
+ if (Sym.isUndefined())
+ return 0;
+ const WasmSegment& Segment = WasmObj->dataSegments()[Sym.Info.DataRef.Segment];
+ return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
+ Reloc.Addend;
+ }
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
+ return Sym->Function->getFunctionInputOffset() +
+ Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
+ }
+ return 0;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return Reloc.Addend;
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ return Reloc.Index;
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: {
+ const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index];
+ return Sym.Info.ElementIndex;
+ }
+ default:
+ llvm_unreachable("unknown relocation type");
+ }
}
-uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const {
- Symbol *Sym = getGlobalSymbol(Original);
- uint32_t Index = Sym->getOutputIndex();
- DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original
- << " -> " << Index << "\n");
- return Index;
+// Translate from the relocation's index into the final linked output value.
+uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
+ switch (Reloc.Type) {
+ case R_WEBASSEMBLY_TABLE_INDEX_I32:
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ return getFunctionSymbol(Reloc.Index)->getTableIndex();
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index)))
+ if (Sym->isLive())
+ return Sym->getVirtualAddress() + Reloc.Addend;
+ return 0;
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ return TypeMap[Reloc.Index];
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
+ return Sym->Function->OutputOffset +
+ Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
+ }
+ return 0;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
+ default:
+ llvm_unreachable("unknown relocation type");
+ }
}
void ObjFile::parse() {
// Parse a memory buffer as a wasm file.
- DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this));
auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
@@ -111,156 +173,175 @@ void ObjFile::parse() {
Bin.release();
WasmObj.reset(Obj);
+ // Build up a map of function indices to table indices for use when
+ // verifying the existing table index relocations
+ uint32_t TotalFunctions =
+ WasmObj->getNumImportedFunctions() + WasmObj->functions().size();
+ TableEntries.resize(TotalFunctions);
+ for (const WasmElemSegment &Seg : WasmObj->elements()) {
+ if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST)
+ fatal(toString(this) + ": invalid table elements");
+ uint32_t Offset = Seg.Offset.Value.Int32;
+ for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) {
+
+ uint32_t FunctionIndex = Seg.Functions[Index];
+ TableEntries[FunctionIndex] = Offset + Index;
+ }
+ }
+
// Find the code and data sections. Wasm objects can have at most one code
// and one data section.
+ uint32_t SectionIndex = 0;
for (const SectionRef &Sec : WasmObj->sections()) {
const WasmSection &Section = WasmObj->getWasmSection(Sec);
- if (Section.Type == WASM_SEC_CODE)
+ if (Section.Type == WASM_SEC_CODE) {
CodeSection = &Section;
- else if (Section.Type == WASM_SEC_DATA)
+ } else if (Section.Type == WASM_SEC_DATA) {
DataSection = &Section;
+ } else if (Section.Type == WASM_SEC_CUSTOM) {
+ CustomSections.emplace_back(make<InputSection>(Section, this));
+ CustomSections.back()->copyRelocations(Section);
+ CustomSectionsByIndex[SectionIndex] = CustomSections.back();
+ }
+ SectionIndex++;
}
- initializeSymbols();
-}
+ TypeMap.resize(getWasmObj()->types().size());
+ TypeIsUsed.resize(getWasmObj()->types().size(), false);
-// Return the InputSegment in which a given symbol is defined.
-InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) {
- uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym);
- for (InputSegment *Segment : Segments) {
- if (Address >= Segment->startVA() && Address < Segment->endVA()) {
- DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> "
- << Segment->getName() << "\n");
+ ArrayRef<StringRef> Comdats = WasmObj->linkingData().Comdats;
+ UsedComdats.resize(Comdats.size());
+ for (unsigned I = 0; I < Comdats.size(); ++I)
+ UsedComdats[I] = Symtab->addComdat(Comdats[I]);
- return Segment;
- }
+ // Populate `Segments`.
+ for (const WasmSegment &S : WasmObj->dataSegments()) {
+ InputSegment *Seg = make<InputSegment>(S, this);
+ Seg->copyRelocations(*DataSection);
+ Segments.emplace_back(Seg);
+ }
+
+ // Populate `Functions`.
+ ArrayRef<WasmFunction> Funcs = WasmObj->functions();
+ ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
+ ArrayRef<WasmSignature> Types = WasmObj->types();
+ Functions.reserve(Funcs.size());
+
+ for (size_t I = 0, E = Funcs.size(); I != E; ++I) {
+ InputFunction *F =
+ make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this);
+ F->copyRelocations(*CodeSection);
+ Functions.emplace_back(F);
+ }
+
+ // Populate `Globals`.
+ for (const WasmGlobal &G : WasmObj->globals())
+ Globals.emplace_back(make<InputGlobal>(G, this));
+
+ // Populate `Symbols` based on the WasmSymbols in the object.
+ Symbols.reserve(WasmObj->getNumberOfSymbols());
+ for (const SymbolRef &Sym : WasmObj->symbols()) {
+ const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
+ if (Symbol *Sym = createDefined(WasmSym))
+ Symbols.push_back(Sym);
+ else
+ Symbols.push_back(createUndefined(WasmSym));
}
- error("symbol not found in any segment: " + WasmSym.Name);
- return nullptr;
}
-static void copyRelocationsRange(std::vector<WasmRelocation> &To,
- ArrayRef<WasmRelocation> From, size_t Start,
- size_t End) {
- for (const WasmRelocation &R : From)
- if (R.Offset >= Start && R.Offset < End)
- To.push_back(R);
+bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
+ uint32_t C = Chunk->getComdat();
+ if (C == UINT32_MAX)
+ return false;
+ return !UsedComdats[C];
}
-void ObjFile::initializeSymbols() {
- Symbols.reserve(WasmObj->getNumberOfSymbols());
+FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
+ return cast<FunctionSymbol>(Symbols[Index]);
+}
- for (const WasmImport &Import : WasmObj->imports()) {
- switch (Import.Kind) {
- case WASM_EXTERNAL_FUNCTION:
- ++FunctionImports;
- break;
- case WASM_EXTERNAL_GLOBAL:
- ++GlobalImports;
- break;
- }
- }
+GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
+ return cast<GlobalSymbol>(Symbols[Index]);
+}
- FunctionSymbols.resize(FunctionImports + WasmObj->functions().size());
- GlobalSymbols.resize(GlobalImports + WasmObj->globals().size());
+SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
+ return cast<SectionSymbol>(Symbols[Index]);
+}
- for (const WasmSegment &S : WasmObj->dataSegments()) {
- InputSegment *Seg = make<InputSegment>(&S, this);
- copyRelocationsRange(Seg->Relocations, DataSection->Relocations,
- Seg->getInputSectionOffset(),
- Seg->getInputSectionOffset() + Seg->getSize());
- Segments.emplace_back(Seg);
- }
+DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
+ return cast<DataSymbol>(Symbols[Index]);
+}
- // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols
- // in the object
- for (const SymbolRef &Sym : WasmObj->symbols()) {
- const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
- Symbol *S;
- switch (WasmSym.Type) {
- case WasmSymbol::SymbolType::FUNCTION_IMPORT:
- case WasmSymbol::SymbolType::GLOBAL_IMPORT:
- S = createUndefined(WasmSym);
- break;
- case WasmSymbol::SymbolType::GLOBAL_EXPORT:
- S = createDefined(WasmSym, getSegment(WasmSym));
- break;
- case WasmSymbol::SymbolType::FUNCTION_EXPORT:
- S = createDefined(WasmSym);
- break;
- case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
- // These are for debugging only, no need to create linker symbols for them
- continue;
- }
+Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
+ if (!Sym.isDefined())
+ return nullptr;
- Symbols.push_back(S);
- if (WasmSym.isFunction()) {
- DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> "
- << toString(*S) << "\n");
- FunctionSymbols[WasmSym.ElementIndex] = S;
- if (WasmSym.HasAltIndex)
- FunctionSymbols[WasmSym.AltIndex] = S;
- } else {
- DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> "
- << toString(*S) << "\n");
- GlobalSymbols[WasmSym.ElementIndex] = S;
- if (WasmSym.HasAltIndex)
- GlobalSymbols[WasmSym.AltIndex] = S;
+ StringRef Name = Sym.Info.Name;
+ uint32_t Flags = Sym.Info.Flags;
+
+ switch (Sym.Info.Kind) {
+ case WASM_SYMBOL_TYPE_FUNCTION: {
+ InputFunction *Func =
+ Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()];
+ if (isExcludedByComdat(Func)) {
+ Func->Live = false;
+ return nullptr;
}
- }
- DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I)
- assert(FunctionSymbols[I] != nullptr);
- for (size_t I = 0; I < GlobalSymbols.size(); ++I)
- assert(GlobalSymbols[I] != nullptr););
-
- // Populate `TableSymbols` with all symbols that are called indirectly
- uint32_t SegmentCount = WasmObj->elements().size();
- if (SegmentCount) {
- if (SegmentCount > 1)
- fatal(getName() + ": contains more than one element segment");
- const WasmElemSegment &Segment = WasmObj->elements()[0];
- if (Segment.Offset.Opcode != WASM_OPCODE_I32_CONST)
- fatal(getName() + ": unsupported element segment");
- if (Segment.TableIndex != 0)
- fatal(getName() + ": unsupported table index in elem segment");
- if (Segment.Offset.Value.Int32 != 0)
- fatal(getName() + ": unsupported element segment offset");
- TableSymbols.reserve(Segment.Functions.size());
- for (uint64_t FunctionIndex : Segment.Functions)
- TableSymbols.push_back(getFunctionSymbol(FunctionIndex));
+ if (Sym.isBindingLocal())
+ return make<DefinedFunction>(Name, Flags, this, Func);
+ return Symtab->addDefinedFunction(Name, Flags, this, Func);
}
+ case WASM_SYMBOL_TYPE_DATA: {
+ InputSegment *Seg = Segments[Sym.Info.DataRef.Segment];
+ if (isExcludedByComdat(Seg)) {
+ Seg->Live = false;
+ return nullptr;
+ }
- DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n");
- DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n");
- DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n");
-}
+ uint32_t Offset = Sym.Info.DataRef.Offset;
+ uint32_t Size = Sym.Info.DataRef.Size;
-Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
- return Symtab->addUndefined(this, &Sym);
+ if (Sym.isBindingLocal())
+ return make<DefinedData>(Name, Flags, this, Seg, Offset, Size);
+ return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size);
+ }
+ case WASM_SYMBOL_TYPE_GLOBAL: {
+ InputGlobal *Global =
+ Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()];
+ if (Sym.isBindingLocal())
+ return make<DefinedGlobal>(Name, Flags, this, Global);
+ return Symtab->addDefinedGlobal(Name, Flags, this, Global);
+ }
+ case WASM_SYMBOL_TYPE_SECTION: {
+ InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
+ assert(Sym.isBindingLocal());
+ return make<SectionSymbol>(Name, Flags, Section, this);
+ }
+ }
+ llvm_unreachable("unknown symbol kind");
}
-Symbol *ObjFile::createDefined(const WasmSymbol &Sym,
- const InputSegment *Segment) {
- Symbol *S;
- if (Sym.isLocal()) {
- S = make<Symbol>(Sym.Name, true);
- Symbol::Kind Kind;
- if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT)
- Kind = Symbol::Kind::DefinedFunctionKind;
- else if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
- Kind = Symbol::Kind::DefinedGlobalKind;
- else
- llvm_unreachable("invalid local symbol type");
- S->update(Kind, this, &Sym, Segment);
- return S;
+Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
+ StringRef Name = Sym.Info.Name;
+ uint32_t Flags = Sym.Info.Flags;
+
+ switch (Sym.Info.Kind) {
+ case WASM_SYMBOL_TYPE_FUNCTION:
+ return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType);
+ case WASM_SYMBOL_TYPE_DATA:
+ return Symtab->addUndefinedData(Name, Flags, this);
+ case WASM_SYMBOL_TYPE_GLOBAL:
+ return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType);
+ case WASM_SYMBOL_TYPE_SECTION:
+ llvm_unreachable("section symbols cannot be undefined");
}
- return Symtab->addDefined(this, &Sym, Segment);
+ llvm_unreachable("unknown symbol kind");
}
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
- DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
File = CHECK(Archive::create(MB), toString(this));
// Read the symbol table to construct Lazy symbols.
@@ -269,7 +350,7 @@ void ArchiveFile::parse() {
Symtab->addLazy(this, &Sym);
++Count;
}
- DEBUG(dbgs() << "Read " << Count << " symbols\n");
+ LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n");
}
void ArchiveFile::addMember(const Archive::Symbol *Sym) {
@@ -282,22 +363,59 @@ void ArchiveFile::addMember(const Archive::Symbol *Sym) {
if (!Seen.insert(C.getChildOffset()).second)
return;
- DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
- DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
"could not get the buffer for the member defining symbol " +
Sym->getName());
- if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) {
- error("unknown file type: " + MB.getBufferIdentifier());
+ InputFile *Obj = createObjectFile(MB);
+ Obj->ArchiveName = getName();
+ Symtab->addFile(Obj);
+}
+
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
+ switch (GvVisibility) {
+ case GlobalValue::DefaultVisibility:
+ return WASM_SYMBOL_VISIBILITY_DEFAULT;
+ case GlobalValue::HiddenVisibility:
+ case GlobalValue::ProtectedVisibility:
+ return WASM_SYMBOL_VISIBILITY_HIDDEN;
+ }
+ llvm_unreachable("unknown visibility");
+}
+
+static Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &ObjSym,
+ BitcodeFile &F) {
+ StringRef Name = Saver.save(ObjSym.getName());
+
+ uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
+ Flags |= mapVisibility(ObjSym.getVisibility());
+
+ if (ObjSym.isUndefined()) {
+ if (ObjSym.isExecutable())
+ return Symtab->addUndefinedFunction(Name, Flags, &F, nullptr);
+ return Symtab->addUndefinedData(Name, Flags, &F);
+ }
+
+ if (ObjSym.isExecutable())
+ return Symtab->addDefinedFunction(Name, Flags, &F, nullptr);
+ return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0);
+}
+
+void BitcodeFile::parse() {
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier()))));
+ Triple T(Obj->getTargetTriple());
+ if (T.getArch() != Triple::wasm32) {
+ error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32");
return;
}
- InputFile *Obj = make<ObjFile>(MB);
- Obj->ParentName = ParentName;
- Symtab->addFile(Obj);
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
+ Symbols.push_back(createBitcodeSymbol(ObjSym, *this));
}
// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
@@ -305,8 +423,8 @@ std::string lld::toString(const wasm::InputFile *File) {
if (!File)
return "<internal>";
- if (File->ParentName.empty())
+ if (File->ArchiveName.empty())
return File->getName();
- return (File->ParentName + "(" + File->getName() + ")").str();
+ return (File->ArchiveName + "(" + File->getName() + ")").str();
}
diff --git a/wasm/InputFiles.h b/wasm/InputFiles.h
index 158cc53cafb1..ec77446e6308 100644
--- a/wasm/InputFiles.h
+++ b/wasm/InputFiles.h
@@ -10,34 +10,46 @@
#ifndef LLD_WASM_INPUT_FILES_H
#define LLD_WASM_INPUT_FILES_H
+#include "Symbols.h"
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/MemoryBuffer.h"
-
-#include "WriterUtils.h"
-
#include <vector>
using llvm::object::Archive;
using llvm::object::WasmObjectFile;
using llvm::object::WasmSection;
using llvm::object::WasmSymbol;
+using llvm::wasm::WasmGlobal;
using llvm::wasm::WasmImport;
+using llvm::wasm::WasmRelocation;
+using llvm::wasm::WasmSignature;
+
+namespace llvm {
+namespace lto {
+class InputFile;
+}
+} // namespace llvm
namespace lld {
namespace wasm {
-class Symbol;
+class InputChunk;
+class InputFunction;
class InputSegment;
+class InputGlobal;
+class InputSection;
class InputFile {
public:
enum Kind {
ObjectKind,
ArchiveKind,
+ BitcodeKind,
};
virtual ~InputFile() {}
@@ -51,12 +63,17 @@ public:
Kind kind() const { return FileKind; }
// An archive file name if this file is created from an archive.
- StringRef ParentName;
+ StringRef ArchiveName;
+
+ ArrayRef<Symbol *> getSymbols() const { return Symbols; }
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
MemoryBufferRef MB;
+ // List of all symbols referenced or defined by this file.
+ std::vector<Symbol *> Symbols;
+
private:
const Kind FileKind;
};
@@ -89,58 +106,54 @@ public:
void dumpInfo() const;
- uint32_t relocateTypeIndex(uint32_t Original) const;
- uint32_t relocateFunctionIndex(uint32_t Original) const;
- uint32_t relocateGlobalIndex(uint32_t Original) const;
- uint32_t relocateTableIndex(uint32_t Original) const;
- uint32_t getRelocatedAddress(uint32_t Index) const;
-
- // Returns true if the given function index is an imported function,
- // as opposed to the locally defined function.
- bool isImportedFunction(uint32_t Index) const;
-
- size_t NumFunctionImports() const { return FunctionImports; }
- size_t NumGlobalImports() const { return GlobalImports; }
+ uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
+ uint32_t calcNewValue(const WasmRelocation &Reloc) const;
+ uint32_t calcNewAddend(const WasmRelocation &Reloc) const;
+ uint32_t calcExpectedValue(const WasmRelocation &Reloc) const;
- int32_t FunctionIndexOffset = 0;
const WasmSection *CodeSection = nullptr;
- std::vector<OutputRelocation> CodeRelocations;
- int32_t CodeOffset = 0;
const WasmSection *DataSection = nullptr;
+ // Maps input type indices to output type indices
std::vector<uint32_t> TypeMap;
+ std::vector<bool> TypeIsUsed;
+ // Maps function indices to table indices
+ std::vector<uint32_t> TableEntries;
+ std::vector<bool> UsedComdats;
std::vector<InputSegment *> Segments;
+ std::vector<InputFunction *> Functions;
+ std::vector<InputGlobal *> Globals;
+ std::vector<InputSection *> CustomSections;
+ llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
- ArrayRef<Symbol *> getSymbols() { return Symbols; }
- ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; }
+ Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
+ FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
+ DataSymbol *getDataSymbol(uint32_t Index) const;
+ GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
+ SectionSymbol *getSectionSymbol(uint32_t Index) const;
private:
- Symbol *createDefined(const WasmSymbol &Sym,
- const InputSegment *Segment = nullptr);
+ Symbol *createDefined(const WasmSymbol &Sym);
Symbol *createUndefined(const WasmSymbol &Sym);
- void initializeSymbols();
- InputSegment *getSegment(const WasmSymbol &WasmSym);
- Symbol *getFunctionSymbol(uint32_t FunctionIndex) const;
- Symbol *getTableSymbol(uint32_t TableIndex) const;
- Symbol *getGlobalSymbol(uint32_t GlobalIndex) const;
- // List of all symbols referenced or defined by this file.
- std::vector<Symbol *> Symbols;
-
- // List of all function symbols indexed by the function index space
- std::vector<Symbol *> FunctionSymbols;
+ bool isExcludedByComdat(InputChunk *Chunk) const;
- // List of all global symbols indexed by the global index space
- std::vector<Symbol *> GlobalSymbols;
+ std::unique_ptr<WasmObjectFile> WasmObj;
+};
- // List of all indirect symbols indexed by table index space.
- std::vector<Symbol *> TableSymbols;
+class BitcodeFile : public InputFile {
+public:
+ explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
- uint32_t GlobalImports = 0;
- uint32_t FunctionImports = 0;
- std::unique_ptr<WasmObjectFile> WasmObj;
+ void parse() override;
+ std::unique_ptr<llvm::lto::InputFile> Obj;
};
+// Will report a fatal() error if the input buffer is not a valid bitcode
+// or was object file.
+InputFile *createObjectFile(MemoryBufferRef MB);
+
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
diff --git a/wasm/InputGlobal.h b/wasm/InputGlobal.h
new file mode 100644
index 000000000000..37d0ab903706
--- /dev/null
+++ b/wasm/InputGlobal.h
@@ -0,0 +1,59 @@
+//===- InputGlobal.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_GLOBAL_H
+#define LLD_WASM_INPUT_GLOBAL_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+using llvm::wasm::WasmGlobal;
+using llvm::wasm::WasmInitExpr;
+
+namespace lld {
+namespace wasm {
+
+// Represents a single Wasm Global Variable within an input file. These are
+// combined to form the final GLOBALS section.
+class InputGlobal {
+public:
+ InputGlobal(const WasmGlobal &G, ObjFile *F)
+ : File(F), Global(G), Live(!Config->GcSections) {}
+
+ StringRef getName() const { return Global.SymbolName; }
+ const WasmGlobalType &getType() const { return Global.Type; }
+
+ uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); }
+ bool hasGlobalIndex() const { return GlobalIndex.hasValue(); }
+ void setGlobalIndex(uint32_t Index) {
+ assert(!hasGlobalIndex());
+ GlobalIndex = Index;
+ }
+
+ ObjFile *File;
+ WasmGlobal Global;
+
+ bool Live = false;
+
+protected:
+ llvm::Optional<uint32_t> GlobalIndex;
+};
+
+} // namespace wasm
+
+inline std::string toString(const wasm::InputGlobal *G) {
+ return (toString(G->File) + ":(" + G->getName() + ")").str();
+}
+
+} // namespace lld
+
+#endif // LLD_WASM_INPUT_GLOBAL_H
diff --git a/wasm/InputSegment.cpp b/wasm/InputSegment.cpp
deleted file mode 100644
index 650914386259..000000000000
--- a/wasm/InputSegment.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//===- InputSegment.cpp ---------------------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "InputSegment.h"
-#include "OutputSegment.h"
-#include "lld/Common/LLVM.h"
-
-#define DEBUG_TYPE "lld"
-
-using namespace llvm;
-using namespace lld::wasm;
-
-uint32_t InputSegment::translateVA(uint32_t Address) const {
- assert(Address >= startVA() && Address < endVA());
- int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA();
- DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta
- << " Address=" << Address << "\n");
- return Address + Delta;
-}
diff --git a/wasm/InputSegment.h b/wasm/InputSegment.h
deleted file mode 100644
index f70a3ded895e..000000000000
--- a/wasm/InputSegment.h
+++ /dev/null
@@ -1,76 +0,0 @@
-//===- InputSegment.h -------------------------------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Represents a WebAssembly data segment which can be included as part of
-// an output data segments. Note that in WebAssembly, unlike ELF and other
-// formats, used the term "data segment" to refer to the continous regions of
-// memory that make on the data section. See:
-// https://webassembly.github.io/spec/syntax/modules.html#syntax-data
-//
-// For example, by default, clang will produce a separate data section for
-// each global variable.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_WASM_INPUT_SEGMENT_H
-#define LLD_WASM_INPUT_SEGMENT_H
-
-#include "WriterUtils.h"
-#include "lld/Common/ErrorHandler.h"
-#include "llvm/Object/Wasm.h"
-
-using llvm::object::WasmSegment;
-using llvm::wasm::WasmRelocation;
-
-namespace lld {
-namespace wasm {
-
-class ObjFile;
-class OutputSegment;
-
-class InputSegment {
-public:
- InputSegment(const WasmSegment *Seg, const ObjFile *F)
- : Segment(Seg), File(F) {}
-
- // Translate an offset in the input segment to an offset in the output
- // segment.
- uint32_t translateVA(uint32_t Address) const;
-
- const OutputSegment *getOutputSegment() const { return OutputSeg; }
-
- uint32_t getOutputSegmentOffset() const { return OutputSegmentOffset; }
-
- uint32_t getInputSectionOffset() const { return Segment->SectionOffset; }
-
- void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) {
- OutputSeg = Segment;
- OutputSegmentOffset = Offset;
- }
-
- uint32_t getSize() const { return Segment->Data.Content.size(); }
- uint32_t getAlignment() const { return Segment->Data.Alignment; }
- uint32_t startVA() const { return Segment->Data.Offset.Value.Int32; }
- uint32_t endVA() const { return startVA() + getSize(); }
- StringRef getName() const { return Segment->Data.Name; }
-
- const WasmSegment *Segment;
- const ObjFile *File;
- std::vector<WasmRelocation> Relocations;
- std::vector<OutputRelocation> OutRelocations;
-
-protected:
- const OutputSegment *OutputSeg = nullptr;
- uint32_t OutputSegmentOffset = 0;
-};
-
-} // namespace wasm
-} // namespace lld
-
-#endif // LLD_WASM_INPUT_SEGMENT_H
diff --git a/wasm/LTO.cpp b/wasm/LTO.cpp
new file mode 100644
index 000000000000..f15551da8b80
--- /dev/null
+++ b/wasm/LTO.cpp
@@ -0,0 +1,155 @@
+//===- 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 "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::wasm;
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+
+ // Always emit a section per function/data with LTO.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
+
+ // Wasm currently only supports ThreadModel::Single
+ C.Options.ThreadModel = ThreadModel::Single;
+
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+
+ if (Config->SaveTemps)
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOJobs != -1U)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ if (isa<DefinedFunction>(S))
+ replaceSymbol<UndefinedFunction>(S, S->getName(), 0);
+ else if (isa<DefinedData>(S))
+ replaceSymbol<UndefinedData>(S, S->getName(), 0);
+ else
+ llvm_unreachable("unexpected symbol kind");
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ Symbol *Sym = Syms[SymNum];
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
+ R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
+ (R.Prevailing && Sym->isExported());
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buf.resize(MaxTasks);
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ },
+ Cache));
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buf[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
+ else
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ }
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(File->getBuffer());
+
+ return Ret;
+}
diff --git a/wasm/LTO.h b/wasm/LTO.h
new file mode 100644
index 000000000000..cf726de5643a
--- /dev/null
+++ b/wasm/LTO.h
@@ -0,0 +1,57 @@
+//===- 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 wasm
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular wasm files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a wasm file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_LTO_H
+#define LLD_WASM_LTO_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+} // namespace llvm
+
+namespace lld {
+namespace wasm {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<StringRef> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
+};
+} // namespace wasm
+} // namespace lld
+
+#endif
diff --git a/wasm/MarkLive.cpp b/wasm/MarkLive.cpp
new file mode 100644
index 000000000000..dfaa712c3296
--- /dev/null
+++ b/wasm/MarkLive.cpp
@@ -0,0 +1,118 @@
+//===- 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
+// chunks from the output. Unused chunks are those that are not reachable from
+// known root symbols or chunks. This feature is implemented as a mark-sweep
+// garbage collector.
+//
+// Here's how it works. Each InputChunk has a "Live" bit. The bit is off by
+// default. Starting with the GC-roots, visit all reachable chunks and set their
+// Live bits. The Writer will then ignore chunks whose Live bits are off, so
+// that such chunk are not appear in the output.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MarkLive.h"
+#include "Config.h"
+#include "InputChunks.h"
+#include "InputGlobal.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace llvm::wasm;
+using namespace lld;
+using namespace lld::wasm;
+
+void lld::wasm::markLive() {
+ if (!Config->GcSections)
+ return;
+
+ LLVM_DEBUG(dbgs() << "markLive\n");
+ SmallVector<InputChunk *, 256> Q;
+
+ auto Enqueue = [&](Symbol *Sym) {
+ if (!Sym || Sym->isLive())
+ return;
+ LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n");
+ Sym->markLive();
+ if (InputChunk *Chunk = Sym->getChunk())
+ Q.push_back(Chunk);
+ };
+
+ // Add GC root symbols.
+ if (!Config->Entry.empty())
+ Enqueue(Symtab->find(Config->Entry));
+ Enqueue(WasmSym::CallCtors);
+
+ // We need to preserve any exported symbol
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (Sym->isExported())
+ Enqueue(Sym);
+
+ // The ctor functions are all used in the synthetic __wasm_call_ctors
+ // function, but since this function is created in-place it doesn't contain
+ // relocations which mean we have to manually mark the ctors.
+ for (const ObjFile *Obj : Symtab->ObjectFiles) {
+ const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
+ for (const WasmInitFunc &F : L.InitFunctions)
+ Enqueue(Obj->getFunctionSymbol(F.Symbol));
+ }
+
+ // Follow relocations to mark all reachable chunks.
+ while (!Q.empty()) {
+ InputChunk *C = Q.pop_back_val();
+
+ for (const WasmRelocation Reloc : C->getRelocations()) {
+ if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB)
+ continue;
+ Symbol *Sym = C->File->getSymbol(Reloc.Index);
+
+ // If the function has been assigned the special index zero in the table,
+ // the relocation doesn't pull in the function body, since the function
+ // won't actually go in the table (the runtime will trap attempts to call
+ // that index, since we don't use it). A function with a table index of
+ // zero is only reachable via "call", not via "call_indirect". The stub
+ // functions used for weak-undefined symbols have this behaviour (compare
+ // equal to null pointer, only reachable via direct call).
+ if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB ||
+ Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32) {
+ FunctionSymbol *FuncSym = cast<FunctionSymbol>(Sym);
+ if (FuncSym->hasTableIndex() && FuncSym->getTableIndex() == 0)
+ continue;
+ }
+
+ Enqueue(Sym);
+ }
+ }
+
+ // Report garbage-collected sections.
+ if (Config->PrintGcSections) {
+ for (const ObjFile *Obj : Symtab->ObjectFiles) {
+ for (InputChunk *C : Obj->Functions)
+ if (!C->Live)
+ message("removing unused section " + toString(C));
+ for (InputChunk *C : Obj->Segments)
+ if (!C->Live)
+ message("removing unused section " + toString(C));
+ for (InputGlobal *G : Obj->Globals)
+ if (!G->Live)
+ message("removing unused section " + toString(G));
+ }
+ for (InputChunk *C : Symtab->SyntheticFunctions)
+ if (!C->Live)
+ message("removing unused section " + toString(C));
+ for (InputGlobal *G : Symtab->SyntheticGlobals)
+ if (!G->Live)
+ message("removing unused section " + toString(G));
+ }
+}
diff --git a/wasm/MarkLive.h b/wasm/MarkLive.h
new file mode 100644
index 000000000000..0b58f153ce45
--- /dev/null
+++ b/wasm/MarkLive.h
@@ -0,0 +1,21 @@
+//===- MarkLive.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_MARKLIVE_H
+#define LLD_WASM_MARKLIVE_H
+
+namespace lld {
+namespace wasm {
+
+void markLive();
+
+} // namespace wasm
+} // namespace lld
+
+#endif // LLD_WASM_MARKLIVE_H
diff --git a/wasm/Options.td b/wasm/Options.td
index df0c6d708072..43588a830e31 100644
--- a/wasm/Options.td
+++ b/wasm/Options.td
@@ -11,21 +11,47 @@ multiclass Eq<string name> {
def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
}
-def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
- HelpText<"Add a directory to the library search path">;
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--", "-"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+}
+// The follow flags are shared with the ELF linker
def color_diagnostics: F<"color-diagnostics">,
HelpText<"Use colors in diagnostics">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
+
+defm demangle: B<"demangle",
+ "Demangle symbol names",
+ "Do not demangle symbol names">;
+
+def entry: S<"entry">, MetaVarName<"<entry>">,
+ HelpText<"Name of entry point symbol">;
+
+def error_limit: J<"error-limit=">,
+ HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+def fatal_warnings: F<"fatal-warnings">,
+ HelpText<"Treat warnings as errors">;
+
+defm gc_sections: B<"gc-sections",
+ "Enable garbage collection of unused sections",
+ "Disable garbage collection of unused sections">;
+
+defm merge_data_segments: B<"merge-data-segments",
+ "Enable merging data segments",
+ "Disable merging data segments">;
-// The follow flags are shared with the ELF linker
def help: F<"help">, HelpText<"Print option help">;
def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">;
+def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Add a directory to the library search path">;
+
def mllvm: S<"mllvm">, HelpText<"Options to pass to LLVM">;
def no_threads: F<"no-threads">,
@@ -34,70 +60,99 @@ def no_threads: F<"no-threads">,
def no_color_diagnostics: F<"no-color-diagnostics">,
HelpText<"Do not use colors in diagnostics">;
-def no_check_signatures: F<"no-check-signatures">, HelpText<"Don't check function signatures">;
+def no_fatal_warnings: F<"no-fatal-warnings">;
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
-def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-def check_signatures: F<"check-signatures">, HelpText<"Check function signatures">;
-
-def v: Flag<["-"], "v">, HelpText<"Display the version number">;
-
-def version: F<"version">, HelpText<"Display the version number and exit">;
-
-def verbose: F<"verbose">, HelpText<"Verbose mode">;
+defm print_gc_sections: B<"print-gc-sections",
+ "List removed unused sections",
+ "Do not list removed unused sections">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
-def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
-
def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+
defm undefined: Eq<"undefined">,
HelpText<"Force undefined symbol during linking">;
+def v: Flag<["-"], "v">, HelpText<"Display the version number">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def version: F<"version">, HelpText<"Display the version number and exit">;
+
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
-def entry: S<"entry">, MetaVarName<"<entry>">,
- HelpText<"Name of entry point symbol">;
+// The follow flags are unique to wasm
-def no_entry: F<"no-entry">,
- HelpText<"Do not output any entry point">;
+def allow_undefined: F<"allow-undefined">,
+ HelpText<"Allow undefined symbols in linked binary">;
-def error_limit: J<"error-limit=">,
- HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+def allow_undefined_file: J<"allow-undefined-file=">,
+ HelpText<"Allow symbols listed in <file> to be undefined in linked binary">;
-// The follow flags are unique to wasm
+def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">,
+ Alias<allow_undefined_file>;
+
+defm export: Eq<"export">,
+ HelpText<"Force a symbol to be exported">;
+
+def export_all: F<"export-all">,
+ HelpText<"Export all symbols (normally combined with --no-gc-sections)">;
+
+def export_table: F<"export-table">,
+ HelpText<"Export function table to the environment">;
def global_base: J<"global-base=">,
HelpText<"Where to start to place global data">;
+def import_memory: F<"import-memory">,
+ HelpText<"Import memory from the environment">;
+
+def import_table: F<"import-table">,
+ HelpText<"Import function table from the environment">;
+
def initial_memory: J<"initial-memory=">,
HelpText<"Initial size of the linear memory">;
def max_memory: J<"max-memory=">,
HelpText<"Maximum size of the linear memory">;
-def import_memory: F<"import-memory">,
- HelpText<"Import memory from the environment">;
-
-def allow_undefined: F<"allow-undefined">,
- HelpText<"Allow undefined symbols in linked binary">;
+def no_entry: F<"no-entry">,
+ HelpText<"Do not output any entry point">;
-def allow_undefined_file: J<"allow-undefined-file=">,
- HelpText<"Allow symbols listed in <file> to be undefined in linked binary">;
+def stack_first: F<"stack-first">,
+ HelpText<"Place stack at start of linear memory rather than after data">;
-def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias<allow_undefined_file>;
+defm whole_archive: B<"whole-archive",
+ "Force load of all members in a static library",
+ "Do not force load of all members in a static library (default)">;
// Aliases
+def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_initial_memory_i: Flag<["-"], "i">, Alias<initial_memory>;
def alias_max_memory_m: Flag<["-"], "m">, Alias<max_memory>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
-def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+
+// LTO-related options.
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp
index a55538269065..256a9884f947 100644
--- a/wasm/OutputSections.cpp
+++ b/wasm/OutputSections.cpp
@@ -8,13 +8,11 @@
//===----------------------------------------------------------------------===//
#include "OutputSections.h"
-
-#include "Config.h"
+#include "InputChunks.h"
#include "InputFiles.h"
#include "OutputSegment.h"
-#include "SymbolTable.h"
+#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Memory.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/LEB128.h"
@@ -26,12 +24,6 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
-enum class RelocEncoding {
- Uleb128,
- Sleb128,
- I32,
-};
-
static StringRef sectionTypeToString(uint32_t SectionType) {
switch (SectionType) {
case WASM_SEC_CUSTOM:
@@ -63,159 +55,40 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
}
}
-std::string lld::toString(const OutputSection &Section) {
- std::string rtn = Section.getSectionName();
- if (!Section.Name.empty())
- rtn += "(" + Section.Name + ")";
- return rtn;
-}
-
-static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
- DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type
- << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value
- << " offset=" << Reloc.Reloc.Offset << "\n");
- Buf += Reloc.Reloc.Offset;
- int64_t ExistingValue;
- switch (Reloc.Reloc.Type) {
- case R_WEBASSEMBLY_TYPE_INDEX_LEB:
- case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
- ExistingValue = decodeULEB128(Buf);
- if (ExistingValue != Reloc.Reloc.Index) {
- DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
- assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
- }
- LLVM_FALLTHROUGH;
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
- encodeULEB128(Reloc.Value, Buf, 5);
- break;
- case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
- ExistingValue = decodeSLEB128(Buf);
- if (ExistingValue != Reloc.Reloc.Index) {
- DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n");
- assert(decodeSLEB128(Buf) == Reloc.Reloc.Index);
- }
- LLVM_FALLTHROUGH;
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
- break;
- case R_WEBASSEMBLY_TABLE_INDEX_I32:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- support::endian::write32<support::little>(Buf, Reloc.Value);
- break;
- default:
- llvm_unreachable("unknown relocation type");
- }
-}
-
-static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> Relocs) {
- if (!Relocs.size())
- return;
- log("applyRelocations: count=" + Twine(Relocs.size()));
- for (const OutputRelocation &Reloc : Relocs)
- applyRelocation(Buf, Reloc);
-}
-
-// Relocations contain an index into the function, global or table index
-// space of the input file. This function takes a relocation and returns the
-// relocated index (i.e. translates from the input index space to the output
-// index space).
-static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) {
- switch (Reloc.Type) {
- case R_WEBASSEMBLY_TYPE_INDEX_LEB:
- return File.relocateTypeIndex(Reloc.Index);
- case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
- return File.relocateFunctionIndex(Reloc.Index);
- case R_WEBASSEMBLY_TABLE_INDEX_I32:
- case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
- return File.relocateTableIndex(Reloc.Index);
- case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- return File.relocateGlobalIndex(Reloc.Index);
- default:
- llvm_unreachable("unknown relocation type");
- }
-}
-
-// Take a vector of relocations from an input file and create output
-// relocations based on them. Calculates the updated index and offset for
-// each relocation as well as the value to write out in the final binary.
-static void calcRelocations(const ObjFile &File,
- ArrayRef<WasmRelocation> Relocs,
- std::vector<OutputRelocation> &OutputRelocs,
- int32_t OutputOffset) {
- log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset));
- for (const WasmRelocation &Reloc : Relocs) {
- OutputRelocation NewReloc;
- NewReloc.Reloc = Reloc;
- NewReloc.Reloc.Offset += OutputOffset;
- DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index
- << " offset=" << Reloc.Offset
- << " newOffset=" << NewReloc.Reloc.Offset << "\n");
-
- if (Config->EmitRelocs)
- NewReloc.NewIndex = calcNewIndex(File, Reloc);
- else
- NewReloc.NewIndex = UINT32_MAX;
-
- switch (Reloc.Type) {
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- NewReloc.Value = File.getRelocatedAddress(Reloc.Index);
- if (NewReloc.Value != UINT32_MAX)
- NewReloc.Value += Reloc.Addend;
- break;
- default:
- NewReloc.Value = calcNewIndex(File, Reloc);
- break;
- }
-
- OutputRelocs.emplace_back(NewReloc);
- }
+// Returns a string, e.g. "FUNCTION(.text)".
+std::string lld::toString(const OutputSection &Sec) {
+ if (!Sec.Name.empty())
+ return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
+ return Sec.getSectionName();
}
-std::string OutputSection::getSectionName() const {
+StringRef OutputSection::getSectionName() const {
return sectionTypeToString(Type);
}
-std::string SubSection::getSectionName() const {
- return std::string("subsection <type=") + std::to_string(Type) + ">";
-}
-
void OutputSection::createHeader(size_t BodySize) {
raw_string_ostream OS(Header);
- debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]");
- writeUleb128(OS, Type, nullptr);
+ debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
+ encodeULEB128(Type, OS);
writeUleb128(OS, BodySize, "section size");
OS.flush();
log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
" total=" + Twine(getSize()));
}
-CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
- : OutputSection(WASM_SEC_CODE), InputObjects(Objs) {
+CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
+ : OutputSection(WASM_SEC_CODE), Functions(Functions) {
+ assert(Functions.size() > 0);
+
raw_string_ostream OS(CodeSectionHeader);
- writeUleb128(OS, NumFunctions, "function count");
+ writeUleb128(OS, Functions.size(), "function count");
OS.flush();
BodySize = CodeSectionHeader.size();
- for (ObjFile *File : InputObjects) {
- if (!File->CodeSection)
- continue;
-
- File->CodeOffset = BodySize;
- ArrayRef<uint8_t> Content = File->CodeSection->Content;
- unsigned HeaderSize = 0;
- decodeULEB128(Content.data(), &HeaderSize);
-
- calcRelocations(*File, File->CodeSection->Relocations,
- File->CodeRelocations, BodySize - HeaderSize);
-
- size_t PayloadSize = Content.size() - HeaderSize;
- BodySize += PayloadSize;
+ for (InputFunction *Func : Functions) {
+ Func->OutputOffset = BodySize;
+ Func->calculateSize();
+ BodySize += Func->getSize();
}
createHeader(BodySize);
@@ -224,49 +97,32 @@ CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
void CodeSection::writeTo(uint8_t *Buf) {
log("writing " + toString(*this));
log(" size=" + Twine(getSize()));
+ log(" headersize=" + Twine(Header.size()));
+ log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
Buf += Offset;
// Write section header
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
- uint8_t *ContentsStart = Buf;
-
// Write code section headers
memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
- Buf += CodeSectionHeader.size();
// Write code section bodies
- parallelForEach(InputObjects, [ContentsStart](ObjFile *File) {
- if (!File->CodeSection)
- return;
-
- ArrayRef<uint8_t> Content(File->CodeSection->Content);
-
- // Payload doesn't include the initial header (function count)
- unsigned HeaderSize = 0;
- decodeULEB128(Content.data(), &HeaderSize);
-
- size_t PayloadSize = Content.size() - HeaderSize;
- memcpy(ContentsStart + File->CodeOffset, Content.data() + HeaderSize,
- PayloadSize);
-
- log("applying relocations for: " + File->getName());
- applyRelocations(ContentsStart, File->CodeRelocations);
- });
+ parallelForEach(Functions,
+ [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); });
}
uint32_t CodeSection::numRelocations() const {
uint32_t Count = 0;
- for (ObjFile *File : InputObjects)
- Count += File->CodeRelocations.size();
+ for (const InputChunk *Func : Functions)
+ Count += Func->NumRelocations();
return Count;
}
void CodeSection::writeRelocations(raw_ostream &OS) const {
- for (ObjFile *File : InputObjects)
- for (const OutputRelocation &Reloc : File->CodeRelocations)
- writeReloc(OS, Reloc);
+ for (const InputChunk *C : Functions)
+ C->writeRelocations(OS);
}
DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
@@ -285,18 +141,14 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
- Segment->setSectionOffset(BodySize);
- BodySize += Segment->Header.size();
+
+ Segment->SectionOffset = BodySize;
+ BodySize += Segment->Header.size() + Segment->Size;
log("Data segment: size=" + Twine(Segment->Size));
- for (InputSegment *InputSeg : Segment->InputSegments) {
- uint32_t InputOffset = InputSeg->getInputSectionOffset();
- uint32_t OutputOffset = Segment->getSectionOffset() +
- Segment->Header.size() +
- InputSeg->getOutputSegmentOffset();
- calcRelocations(*InputSeg->File, InputSeg->Relocations,
- InputSeg->OutRelocations, OutputOffset - InputOffset);
- }
- BodySize += Segment->Size;
+
+ for (InputSegment *InputSeg : Segment->InputSegments)
+ InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
+ InputSeg->OutputSegmentOffset;
}
createHeader(BodySize);
@@ -311,38 +163,77 @@ void DataSection::writeTo(uint8_t *Buf) {
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
- uint8_t *ContentsStart = Buf;
-
// Write data section headers
memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
- parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
+ parallelForEach(Segments, [&](const OutputSegment *Segment) {
// Write data segment header
- uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
+ uint8_t *SegStart = Buf + Segment->SectionOffset;
memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
// Write segment data payload
- for (const InputSegment *Input : Segment->InputSegments) {
- ArrayRef<uint8_t> Content(Input->Segment->Data.Content);
- memcpy(SegStart + Segment->Header.size() +
- Input->getOutputSegmentOffset(),
- Content.data(), Content.size());
- applyRelocations(ContentsStart, Input->OutRelocations);
- }
+ for (const InputChunk *Chunk : Segment->InputSegments)
+ Chunk->writeTo(Buf);
});
}
uint32_t DataSection::numRelocations() const {
uint32_t Count = 0;
for (const OutputSegment *Seg : Segments)
- for (const InputSegment *InputSeg : Seg->InputSegments)
- Count += InputSeg->OutRelocations.size();
+ for (const InputChunk *InputSeg : Seg->InputSegments)
+ Count += InputSeg->NumRelocations();
return Count;
}
void DataSection::writeRelocations(raw_ostream &OS) const {
for (const OutputSegment *Seg : Segments)
- for (const InputSegment *InputSeg : Seg->InputSegments)
- for (const OutputRelocation &Reloc : InputSeg->OutRelocations)
- writeReloc(OS, Reloc);
+ for (const InputChunk *C : Seg->InputSegments)
+ C->writeRelocations(OS);
+}
+
+CustomSection::CustomSection(std::string Name,
+ ArrayRef<InputSection *> InputSections)
+ : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
+ InputSections(InputSections) {
+ raw_string_ostream OS(NameData);
+ encodeULEB128(Name.size(), OS);
+ OS << Name;
+ OS.flush();
+
+ for (InputSection *Section : InputSections) {
+ Section->OutputOffset = PayloadSize;
+ PayloadSize += Section->getSize();
+ }
+
+ createHeader(PayloadSize + NameData.size());
+}
+
+void CustomSection::writeTo(uint8_t *Buf) {
+ log("writing " + toString(*this) + " size=" + Twine(getSize()) +
+ " chunks=" + Twine(InputSections.size()));
+
+ assert(Offset);
+ Buf += Offset;
+
+ // Write section header
+ memcpy(Buf, Header.data(), Header.size());
+ Buf += Header.size();
+ memcpy(Buf, NameData.data(), NameData.size());
+ Buf += NameData.size();
+
+ // Write custom sections payload
+ parallelForEach(InputSections,
+ [&](const InputSection *Section) { Section->writeTo(Buf); });
+}
+
+uint32_t CustomSection::numRelocations() const {
+ uint32_t Count = 0;
+ for (const InputSection *InputSect : InputSections)
+ Count += InputSect->NumRelocations();
+ return Count;
+}
+
+void CustomSection::writeRelocations(raw_ostream &OS) const {
+ for (const InputSection *S : InputSections)
+ S->writeRelocations(OS);
}
diff --git a/wasm/OutputSections.h b/wasm/OutputSections.h
index fc73f36ad286..189d6507c4b3 100644
--- a/wasm/OutputSections.h
+++ b/wasm/OutputSections.h
@@ -10,7 +10,7 @@
#ifndef LLD_WASM_OUTPUT_SECTIONS_H
#define LLD_WASM_OUTPUT_SECTIONS_H
-#include "InputSegment.h"
+#include "InputChunks.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/DenseMap.h"
@@ -28,7 +28,6 @@ std::string toString(const wasm::OutputSection &Section);
namespace wasm {
class OutputSegment;
-class ObjFile;
class OutputSection {
public:
@@ -36,7 +35,7 @@ public:
: Type(Type), Name(Name) {}
virtual ~OutputSection() = default;
- std::string getSectionName() const;
+ StringRef getSectionName() const;
void setOffset(size_t NewOffset) {
log("setOffset: " + toString(*this) + ": " + Twine(NewOffset));
Offset = NewOffset;
@@ -61,7 +60,7 @@ public:
SyntheticSection(uint32_t Type, std::string Name = "")
: OutputSection(Type, Name), BodyOutputStream(Body) {
if (!Name.empty())
- writeStr(BodyOutputStream, Name);
+ writeStr(BodyOutputStream, Name, "section name");
}
void writeTo(uint8_t *Buf) override {
@@ -86,32 +85,16 @@ protected:
raw_string_ostream BodyOutputStream;
};
-// Some synthetic sections (e.g. "name" and "linking") have subsections.
-// Just like the synthetic sections themselves these need to be created before
-// they can be written out (since they are preceded by their length). This
-// class is used to create subsections and then write them into the stream
-// of the parent section.
-class SubSection : public SyntheticSection {
-public:
- explicit SubSection(uint32_t Type) : SyntheticSection(Type) {}
-
- std::string getSectionName() const;
- void writeToStream(raw_ostream &OS) {
- writeBytes(OS, Header.data(), Header.size());
- writeBytes(OS, Body.data(), Body.size());
- }
-};
-
class CodeSection : public OutputSection {
public:
- explicit CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs);
+ explicit CodeSection(ArrayRef<InputFunction *> Functions);
size_t getSize() const override { return Header.size() + BodySize; }
void writeTo(uint8_t *Buf) override;
uint32_t numRelocations() const override;
void writeRelocations(raw_ostream &OS) const override;
protected:
- ArrayRef<ObjFile *> InputObjects;
+ ArrayRef<InputFunction *> Functions;
std::string CodeSectionHeader;
size_t BodySize = 0;
};
@@ -130,6 +113,29 @@ protected:
size_t BodySize = 0;
};
+// Represents a custom section in the output file. Wasm custom sections are
+// used for storing user-defined metadata. Unlike the core sections types
+// they are identified by their string name.
+// The linker combines custom sections that have the same name by simply
+// concatenating them.
+// Note that some custom sections such as "name" and "linking" are handled
+// separately and are instead synthesized by the linker.
+class CustomSection : public OutputSection {
+public:
+ CustomSection(std::string Name, ArrayRef<InputSection *> InputSections);
+ size_t getSize() const override {
+ return Header.size() + NameData.size() + PayloadSize;
+ }
+ void writeTo(uint8_t *Buf) override;
+ uint32_t numRelocations() const override;
+ void writeRelocations(raw_ostream &OS) const override;
+
+protected:
+ size_t PayloadSize;
+ ArrayRef<InputSection *> InputSections;
+ std::string NameData;
+};
+
} // namespace wasm
} // namespace lld
diff --git a/wasm/OutputSegment.h b/wasm/OutputSegment.h
index a22c80234420..d5c89cd19f4c 100644
--- a/wasm/OutputSegment.h
+++ b/wasm/OutputSegment.h
@@ -10,7 +10,7 @@
#ifndef LLD_WASM_OUTPUT_SEGMENT_H
#define LLD_WASM_OUTPUT_SEGMENT_H
-#include "InputSegment.h"
+#include "InputChunks.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/Wasm.h"
@@ -21,21 +21,20 @@ class InputSegment;
class OutputSegment {
public:
- OutputSegment(StringRef N) : Name(N) {}
-
- void addInputSegment(InputSegment *Segment) {
- Alignment = std::max(Alignment, Segment->getAlignment());
- InputSegments.push_back(Segment);
- Size = llvm::alignTo(Size, Segment->getAlignment());
- Segment->setOutputSegment(this, Size);
- Size += Segment->getSize();
+ OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {}
+
+ void addInputSegment(InputSegment *InSeg) {
+ Alignment = std::max(Alignment, InSeg->getAlignment());
+ InputSegments.push_back(InSeg);
+ Size = llvm::alignTo(Size, InSeg->getAlignment());
+ InSeg->OutputSeg = this;
+ InSeg->OutputSegmentOffset = Size;
+ Size += InSeg->getSize();
}
- uint32_t getSectionOffset() const { return SectionOffset; }
-
- void setSectionOffset(uint32_t Offset) { SectionOffset = Offset; }
-
StringRef Name;
+ const uint32_t Index;
+ uint32_t SectionOffset = 0;
uint32_t Alignment = 0;
uint32_t StartVA = 0;
std::vector<InputSegment *> InputSegments;
@@ -45,9 +44,6 @@ public:
// Segment header
std::string Header;
-
-private:
- uint32_t SectionOffset = 0;
};
} // namespace wasm
diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp
index 751008da0536..e1ba23769738 100644
--- a/wasm/SymbolTable.cpp
+++ b/wasm/SymbolTable.cpp
@@ -8,17 +8,18 @@
//===----------------------------------------------------------------------===//
#include "SymbolTable.h"
-
#include "Config.h"
+#include "InputChunks.h"
+#include "InputGlobal.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
-
-#include <unordered_set>
+#include "llvm/ADT/SetVector.h"
#define DEBUG_TYPE "lld"
using namespace llvm;
+using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
@@ -28,17 +29,46 @@ void SymbolTable::addFile(InputFile *File) {
log("Processing: " + toString(File));
File->parse();
- if (auto *F = dyn_cast<ObjFile>(File))
+ // LLVM bitcode file
+ if (auto *F = dyn_cast<BitcodeFile>(File))
+ BitcodeFiles.push_back(F);
+ else if (auto *F = dyn_cast<ObjFile>(File))
ObjectFiles.push_back(F);
}
+// 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 the program consists of are passed
+// to the compiler at once, it can do whole-program optimization.
+void SymbolTable::addCombinedLTOObject() {
+ if (BitcodeFiles.empty())
+ return;
+
+ // Compile bitcode files and replace bitcode symbols.
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+
+ for (StringRef Filename : LTO->compile()) {
+ auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
+ Obj->parse();
+ ObjectFiles.push_back(Obj);
+ }
+}
+
void SymbolTable::reportRemainingUndefines() {
- std::unordered_set<Symbol *> Undefs;
+ SetVector<Symbol *> Undefs;
for (Symbol *Sym : SymVector) {
- if (Sym->isUndefined() && !Sym->isWeak() &&
- Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
- Undefs.insert(Sym);
- }
+ if (!Sym->isUndefined() || Sym->isWeak())
+ continue;
+ if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+ Undefs.insert(Sym);
}
if (Undefs.empty())
@@ -55,183 +85,281 @@ void SymbolTable::reportRemainingUndefines() {
}
Symbol *SymbolTable::find(StringRef Name) {
- auto It = SymMap.find(CachedHashStringRef(Name));
- if (It == SymMap.end())
- return nullptr;
- return It->second;
+ return SymMap.lookup(CachedHashStringRef(Name));
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
if (Sym)
return {Sym, false};
- Sym = make<Symbol>(Name, false);
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
SymVector.emplace_back(Sym);
return {Sym, true};
}
-void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
- toString(Existing->getFile()) + "\n>>> defined in " +
- toString(NewFile));
+static void reportTypeError(const Symbol *Existing, const InputFile *File,
+ llvm::wasm::WasmSymbolType Type) {
+ error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
+ toString(Existing->getWasmType()) + " in " +
+ toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
+ " in " + toString(File));
}
-// Get the signature for a given function symbol, either by looking
-// it up in function sections (for defined functions), of the imports section
-// (for imported functions).
-static const WasmSignature *getFunctionSig(const ObjFile &Obj,
- const WasmSymbol &Sym) {
- DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n");
- const WasmObjectFile *WasmObj = Obj.getWasmObj();
- return &WasmObj->types()[Sym.FunctionType];
+static void checkFunctionType(Symbol *Existing, const InputFile *File,
+ const WasmSignature *NewSig) {
+ auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
+ if (!ExistingFunction) {
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
+ return;
+ }
+
+ if (!NewSig)
+ return;
+
+ const WasmSignature *OldSig = ExistingFunction->FunctionType;
+ if (!OldSig) {
+ ExistingFunction->FunctionType = NewSig;
+ return;
+ }
+
+ if (*NewSig != *OldSig)
+ warn("function signature mismatch: " + Existing->getName() +
+ "\n>>> defined as " + toString(*OldSig) + " in " +
+ toString(Existing->getFile()) + "\n>>> defined as " +
+ toString(*NewSig) + " in " + toString(File));
}
// Check the type of new symbol matches that of the symbol is replacing.
// For functions this can also involve verifying that the signatures match.
-static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
- const WasmSymbol &New,
- const WasmSignature *NewSig) {
- if (Existing.isLazy())
+static void checkGlobalType(const Symbol *Existing, const InputFile *File,
+ const WasmGlobalType *NewType) {
+ if (!isa<GlobalSymbol>(Existing)) {
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
return;
+ }
- bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
- New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
-
- // First check the symbol types match (i.e. either both are function
- // symbols or both are data symbols).
- if (Existing.isFunction() != NewIsFunction) {
- error("symbol type mismatch: " + New.Name + "\n>>> defined as " +
- (Existing.isFunction() ? "Function" : "Global") + " in " +
- toString(Existing.getFile()) + "\n>>> defined as " +
- (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
- return;
+ const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
+ if (*NewType != *OldType) {
+ error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
+ toString(*OldType) + " in " + toString(Existing->getFile()) +
+ "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
}
+}
- // For function symbols, optionally check the function signature matches too.
- if (!NewIsFunction || !Config->CheckSignatures)
- return;
- // Skip the signature check if the existing function has no signature (e.g.
- // if it is an undefined symbol generated by --undefined command line flag).
- if (!Existing.hasFunctionType())
- return;
+static void checkDataType(const Symbol *Existing, const InputFile *File) {
+ if (!isa<DataSymbol>(Existing))
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
+}
- DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n");
- assert(NewSig);
+DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
+ uint32_t Flags,
+ InputFunction *Function) {
+ LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
+ assert(!find(Name));
+ SyntheticFunctions.emplace_back(Function);
+ return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
+ nullptr, Function);
+}
- const WasmSignature &OldSig = Existing.getFunctionType();
- if (*NewSig == OldSig)
- return;
+DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
+ uint32_t Flags) {
+ LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
+ assert(!find(Name));
+ return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags);
+}
- error("function signature mismatch: " + New.Name + "\n>>> defined as " +
- toString(OldSig) + " in " + toString(Existing.getFile()) +
- "\n>>> defined as " + toString(*NewSig) + " in " + F.getName());
+DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
+ InputGlobal *Global) {
+ LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
+ << "\n");
+ assert(!find(Name));
+ SyntheticGlobals.emplace_back(Global);
+ return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
+ Global);
}
-Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
- DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
+static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
+ uint32_t NewFlags) {
+ // If existing symbol is undefined, replace it.
+ if (!Existing->isDefined()) {
+ LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
+ << Existing->getName() << "\n");
+ return true;
+ }
+
+ // Now we have two defined symbols. If the new one is weak, we can ignore it.
+ if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
+ LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
+ return false;
+ }
+
+ // If the existing symbol is weak, we should replace it.
+ if (Existing->isWeak()) {
+ LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
+ return true;
+ }
+
+ // Neither symbol is week. They conflict.
+ error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
+ toString(Existing->getFile()) + "\n>>> defined in " +
+ toString(NewFile));
+ return true;
+}
+
+Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
+ InputFile *File,
+ InputFunction *Function) {
+ LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
- if (WasInserted)
- S->update(Symbol::DefinedGlobalKind);
- else if (!S->isGlobal())
- error("symbol type mismatch: " + Name);
+
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted || S->isLazy()) {
+ replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
+ return S;
+ }
+
+ if (Function)
+ checkFunctionType(S, File, &Function->Signature);
+
+ if (shouldReplace(S, File, Flags))
+ replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
return S;
}
-Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
- const InputSegment *Segment) {
- DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n");
+Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
+ InputFile *File, InputSegment *Segment,
+ uint32_t Address, uint32_t Size) {
+ LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
+ << "\n");
Symbol *S;
bool WasInserted;
- Symbol::Kind Kind = Symbol::DefinedFunctionKind;
- const WasmSignature *NewSig = nullptr;
- if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
- Kind = Symbol::DefinedGlobalKind;
- else
- NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
+ std::tie(S, WasInserted) = insert(Name);
- std::tie(S, WasInserted) = insert(Sym->Name);
- if (WasInserted) {
- S->update(Kind, F, Sym, Segment, NewSig);
- } else if (S->isLazy()) {
- // The existing symbol is lazy. Replace it without checking types since
- // lazy symbols don't have any type information.
- DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n");
- S->update(Kind, F, Sym, Segment, NewSig);
- } else if (!S->isDefined()) {
- // The existing symbol table entry is undefined. The new symbol replaces
- // it, after checking the type matches
- DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
- << "\n");
- checkSymbolTypes(*S, *F, *Sym, NewSig);
- S->update(Kind, F, Sym, Segment, NewSig);
- } else if (Sym->isWeak()) {
- // the new symbol is weak we can ignore it
- DEBUG(dbgs() << "existing symbol takes precedence\n");
- } else if (S->isWeak()) {
- // the new symbol is not weak and the existing symbol is, so we replace
- // it
- DEBUG(dbgs() << "replacing existing weak symbol\n");
- checkSymbolTypes(*S, *F, *Sym, NewSig);
- S->update(Kind, F, Sym, Segment, NewSig);
- } else {
- // neither symbol is week. They conflict.
- reportDuplicate(S, F);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted || S->isLazy()) {
+ replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
+ return S;
}
+
+ checkDataType(S, File);
+
+ if (shouldReplace(S, File, Flags))
+ replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
return S;
}
-Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
- const WasmSignature *Type) {
+Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
+ InputFile *File, InputGlobal *Global) {
+ LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type);
- } else if (!S->isFunction()) {
- error("symbol type mismatch: " + Name);
+
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted || S->isLazy()) {
+ replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
+ return S;
}
+
+ checkGlobalType(S, File, &Global->getType());
+
+ if (shouldReplace(S, File, Flags))
+ replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
return S;
}
-Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) {
- DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n");
+Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
+ InputFile *File,
+ const WasmSignature *Sig) {
+ LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
+
Symbol *S;
bool WasInserted;
- Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
- const WasmSignature *NewSig = nullptr;
- if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
- Kind = Symbol::UndefinedGlobalKind;
+ std::tie(S, WasInserted) = insert(Name);
+
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted)
+ replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
+ else if (auto *Lazy = dyn_cast<LazySymbol>(S))
+ Lazy->fetch();
else
- NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
- std::tie(S, WasInserted) = insert(Sym->Name);
- if (WasInserted) {
- S->update(Kind, F, Sym, nullptr, NewSig);
- } else if (S->isLazy()) {
- DEBUG(dbgs() << "resolved by existing lazy\n");
- auto *AF = cast<ArchiveFile>(S->getFile());
- AF->addMember(&S->getArchiveSymbol());
- } else if (S->isDefined()) {
- DEBUG(dbgs() << "resolved by existing\n");
- checkSymbolTypes(*S, *F, *Sym, NewSig);
- }
+ checkFunctionType(S, File, Sig);
+
+ return S;
+}
+
+Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
+ InputFile *File) {
+ LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
+
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name);
+
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted)
+ replaceSymbol<UndefinedData>(S, Name, Flags, File);
+ else if (auto *Lazy = dyn_cast<LazySymbol>(S))
+ Lazy->fetch();
+ else if (S->isDefined())
+ checkDataType(S, File);
return S;
}
-void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
- DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
+Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
+ InputFile *File,
+ const WasmGlobalType *Type) {
+ LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
+
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name);
+
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
+ if (WasInserted)
+ replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
+ else if (auto *Lazy = dyn_cast<LazySymbol>(S))
+ Lazy->fetch();
+ else if (S->isDefined())
+ checkGlobalType(S, File, Type);
+ return S;
+}
+
+void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
+ LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
StringRef Name = Sym->getName();
+
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+
if (WasInserted) {
- S->update(Symbol::LazyKind, F);
- S->setArchiveSymbol(*Sym);
- } else if (S->isUndefined()) {
- // There is an existing undefined symbol. The can load from the
- // archive.
- DEBUG(dbgs() << "replacing existing undefined\n");
- F->addMember(Sym);
+ replaceSymbol<LazySymbol>(S, Name, File, *Sym);
+ return;
+ }
+
+ // If there is an existing undefined symbol, load a new one from the archive.
+ if (S->isUndefined()) {
+ LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
+ File->addMember(Sym);
}
}
+
+bool SymbolTable::addComdat(StringRef Name) {
+ return Comdats.insert(CachedHashStringRef(Name)).second;
+}
diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h
index fbb74ed14796..26242e6cddd6 100644
--- a/wasm/SymbolTable.h
+++ b/wasm/SymbolTable.h
@@ -11,13 +11,13 @@
#define LLD_WASM_SYMBOL_TABLE_H
#include "InputFiles.h"
+#include "LTO.h"
#include "Symbols.h"
-
#include "llvm/ADT/CachedHashString.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/raw_ostream.h"
-using llvm::object::WasmSymbol;
+using llvm::wasm::WasmGlobalType;
using llvm::wasm::WasmSignature;
namespace lld {
@@ -40,27 +40,52 @@ class InputSegment;
class SymbolTable {
public:
void addFile(InputFile *File);
+ void addCombinedLTOObject();
std::vector<ObjFile *> ObjectFiles;
+ std::vector<BitcodeFile *> BitcodeFiles;
+ std::vector<InputFunction *> SyntheticFunctions;
+ std::vector<InputGlobal *> SyntheticGlobals;
- void reportDuplicate(Symbol *Existing, InputFile *NewFile);
void reportRemainingUndefines();
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
Symbol *find(StringRef Name);
- Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
- const InputSegment *Segment = nullptr);
- Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym);
- Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type);
- Symbol *addDefinedGlobal(StringRef Name);
+ Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
+ InputFunction *Function);
+ Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File,
+ InputSegment *Segment, uint32_t Address,
+ uint32_t Size);
+ Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
+ InputGlobal *G);
+
+ Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
+ const WasmSignature *Signature);
+ Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File);
+ Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
+ const WasmGlobalType *Type);
+
void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
+ bool addComdat(StringRef Name);
+
+ DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags);
+ DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags,
+ InputGlobal *Global);
+ DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags,
+ InputFunction *Function);
+
private:
std::pair<Symbol *, bool> insert(StringRef Name);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
std::vector<Symbol *> SymVector;
+
+ llvm::DenseSet<llvm::CachedHashStringRef> Comdats;
+
+ // For LTO.
+ std::unique_ptr<BitcodeCompiler> LTO;
};
extern SymbolTable *Symtab;
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp
index 6bf5459c2663..a11081cbcf77 100644
--- a/wasm/Symbols.cpp
+++ b/wasm/Symbols.cpp
@@ -8,92 +8,224 @@
//===----------------------------------------------------------------------===//
#include "Symbols.h"
-
#include "Config.h"
+#include "InputChunks.h"
#include "InputFiles.h"
-#include "InputSegment.h"
+#include "InputGlobal.h"
+#include "OutputSegment.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#define DEBUG_TYPE "lld"
using namespace llvm;
+using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
-uint32_t Symbol::getGlobalIndex() const {
- assert(!Sym->isFunction());
- return Sym->ElementIndex;
+DefinedFunction *WasmSym::CallCtors;
+DefinedData *WasmSym::DsoHandle;
+DefinedData *WasmSym::DataEnd;
+DefinedData *WasmSym::HeapBase;
+DefinedGlobal *WasmSym::StackPointer;
+
+WasmSymbolType Symbol::getWasmType() const {
+ if (isa<FunctionSymbol>(this))
+ return WASM_SYMBOL_TYPE_FUNCTION;
+ if (isa<DataSymbol>(this))
+ return WASM_SYMBOL_TYPE_DATA;
+ if (isa<GlobalSymbol>(this))
+ return WASM_SYMBOL_TYPE_GLOBAL;
+ if (isa<SectionSymbol>(this))
+ return WASM_SYMBOL_TYPE_SECTION;
+ llvm_unreachable("invalid symbol kind");
+}
+
+InputChunk *Symbol::getChunk() const {
+ if (auto *F = dyn_cast<DefinedFunction>(this))
+ return F->Function;
+ if (auto *D = dyn_cast<DefinedData>(this))
+ return D->Segment;
+ return nullptr;
+}
+
+bool Symbol::isLive() const {
+ if (auto *G = dyn_cast<DefinedGlobal>(this))
+ return G->Global->Live;
+ if (InputChunk *C = getChunk())
+ return C->Live;
+ return Referenced;
}
-uint32_t Symbol::getFunctionIndex() const {
- assert(Sym->isFunction());
- return Sym->ElementIndex;
+void Symbol::markLive() {
+ if (auto *G = dyn_cast<DefinedGlobal>(this))
+ G->Global->Live = true;
+ if (InputChunk *C = getChunk())
+ C->Live = true;
+ Referenced = true;
}
-const WasmSignature &Symbol::getFunctionType() const {
- assert(FunctionType != nullptr);
- return *FunctionType;
+uint32_t Symbol::getOutputSymbolIndex() const {
+ assert(OutputSymbolIndex != INVALID_INDEX);
+ return OutputSymbolIndex;
}
-uint32_t Symbol::getVirtualAddress() const {
- assert(isGlobal());
- DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
- if (isUndefined())
- return UINT32_MAX;
- if (VirtualAddress.hasValue())
- return VirtualAddress.getValue();
+void Symbol::setOutputSymbolIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
+ << "\n");
+ assert(OutputSymbolIndex == INVALID_INDEX);
+ OutputSymbolIndex = Index;
+}
+
+bool Symbol::isWeak() const {
+ return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
+}
- assert(Sym != nullptr);
- ObjFile *Obj = cast<ObjFile>(File);
- const WasmGlobal &Global =
- Obj->getWasmObj()->globals()[getGlobalIndex() - Obj->NumGlobalImports()];
- assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
- assert(Segment);
- return Segment->translateVA(Global.InitExpr.Value.Int32);
+bool Symbol::isLocal() const {
+ return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
}
-uint32_t Symbol::getOutputIndex() const {
- if (isUndefined() && isWeak())
- return 0;
- return OutputIndex.getValue();
+bool Symbol::isHidden() const {
+ return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
}
-void Symbol::setVirtualAddress(uint32_t Value) {
- DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
- assert(!VirtualAddress.hasValue());
- VirtualAddress = Value;
+void Symbol::setHidden(bool IsHidden) {
+ LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
+ Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
+ if (IsHidden)
+ Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
+ else
+ Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
}
-void Symbol::setOutputIndex(uint32_t Index) {
- DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n");
- assert(!OutputIndex.hasValue());
- OutputIndex = Index;
+bool Symbol::isExported() const {
+ if (!isDefined() || isLocal())
+ return false;
+
+ if (ForceExport || Config->ExportAll)
+ return true;
+
+ return !isHidden();
}
-void Symbol::setTableIndex(uint32_t Index) {
- DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
- assert(!TableIndex.hasValue());
+uint32_t FunctionSymbol::getFunctionIndex() const {
+ if (auto *F = dyn_cast<DefinedFunction>(this))
+ return F->Function->getFunctionIndex();
+ assert(FunctionIndex != INVALID_INDEX);
+ return FunctionIndex;
+}
+
+void FunctionSymbol::setFunctionIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
+ assert(FunctionIndex == INVALID_INDEX);
+ FunctionIndex = Index;
+}
+
+bool FunctionSymbol::hasFunctionIndex() const {
+ if (auto *F = dyn_cast<DefinedFunction>(this))
+ return F->Function->hasFunctionIndex();
+ return FunctionIndex != INVALID_INDEX;
+}
+
+uint32_t FunctionSymbol::getTableIndex() const {
+ if (auto *F = dyn_cast<DefinedFunction>(this))
+ return F->Function->getTableIndex();
+ assert(TableIndex != INVALID_INDEX);
+ return TableIndex;
+}
+
+bool FunctionSymbol::hasTableIndex() const {
+ if (auto *F = dyn_cast<DefinedFunction>(this))
+ return F->Function->hasTableIndex();
+ return TableIndex != INVALID_INDEX;
+}
+
+void FunctionSymbol::setTableIndex(uint32_t Index) {
+ // For imports, we set the table index here on the Symbol; for defined
+ // functions we set the index on the InputFunction so that we don't export
+ // the same thing twice (keeps the table size down).
+ if (auto *F = dyn_cast<DefinedFunction>(this)) {
+ F->Function->setTableIndex(Index);
+ return;
+ }
+ LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
+ assert(TableIndex == INVALID_INDEX);
TableIndex = Index;
}
-void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym,
- const InputSegment *Seg, const WasmSignature *Sig) {
- SymbolKind = K;
- File = F;
- Sym = WasmSym;
- Segment = Seg;
- FunctionType = Sig;
+DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
+ InputFunction *Function)
+ : FunctionSymbol(Name, DefinedFunctionKind, Flags, F,
+ Function ? &Function->Signature : nullptr),
+ Function(Function) {}
+
+uint32_t DefinedData::getVirtualAddress() const {
+ LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
+ if (Segment)
+ return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
+ return Offset;
+}
+
+void DefinedData::setVirtualAddress(uint32_t Value) {
+ LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
+ assert(!Segment);
+ Offset = Value;
+}
+
+uint32_t DefinedData::getOutputSegmentOffset() const {
+ LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
+ return Segment->OutputSegmentOffset + Offset;
+}
+
+uint32_t DefinedData::getOutputSegmentIndex() const {
+ LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
+ return Segment->OutputSeg->Index;
+}
+
+uint32_t GlobalSymbol::getGlobalIndex() const {
+ if (auto *F = dyn_cast<DefinedGlobal>(this))
+ return F->Global->getGlobalIndex();
+ assert(GlobalIndex != INVALID_INDEX);
+ return GlobalIndex;
+}
+
+void GlobalSymbol::setGlobalIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
+ assert(GlobalIndex == INVALID_INDEX);
+ GlobalIndex = Index;
+}
+
+bool GlobalSymbol::hasGlobalIndex() const {
+ if (auto *F = dyn_cast<DefinedGlobal>(this))
+ return F->Global->hasGlobalIndex();
+ return GlobalIndex != INVALID_INDEX;
}
-bool Symbol::isWeak() const { return Sym && Sym->isWeak(); }
+DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
+ InputGlobal *Global)
+ : GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
+ Global ? &Global->getType() : nullptr),
+ Global(Global) {}
+
+uint32_t SectionSymbol::getOutputSectionIndex() const {
+ LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
+ assert(OutputSectionIndex != INVALID_INDEX);
+ return OutputSectionIndex;
+}
+
+void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index
+ << "\n");
+ assert(Index != INVALID_INDEX);
+ OutputSectionIndex = Index;
+}
-bool Symbol::isHidden() const { return Sym && Sym->isHidden(); }
+void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
std::string lld::toString(const wasm::Symbol &Sym) {
if (Config->Demangle)
if (Optional<std::string> S = demangleItanium(Sym.getName()))
- return "`" + *S + "'";
+ return *S;
return Sym.getName();
}
@@ -101,14 +233,20 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
switch (Kind) {
case wasm::Symbol::DefinedFunctionKind:
return "DefinedFunction";
+ case wasm::Symbol::DefinedDataKind:
+ return "DefinedData";
case wasm::Symbol::DefinedGlobalKind:
return "DefinedGlobal";
case wasm::Symbol::UndefinedFunctionKind:
return "UndefinedFunction";
+ case wasm::Symbol::UndefinedDataKind:
+ return "UndefinedData";
case wasm::Symbol::UndefinedGlobalKind:
return "UndefinedGlobal";
case wasm::Symbol::LazyKind:
return "LazyKind";
+ case wasm::Symbol::SectionKind:
+ return "SectionKind";
}
- llvm_unreachable("Invalid symbol kind!");
+ llvm_unreachable("invalid symbol kind");
}
diff --git a/wasm/Symbols.h b/wasm/Symbols.h
index 8194bcaca383..815cc97d22d1 100644
--- a/wasm/Symbols.h
+++ b/wasm/Symbols.h
@@ -10,53 +10,59 @@
#ifndef LLD_WASM_SYMBOLS_H
#define LLD_WASM_SYMBOLS_H
+#include "Config.h"
#include "lld/Common/LLVM.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Wasm.h"
using llvm::object::Archive;
using llvm::object::WasmSymbol;
-using llvm::wasm::WasmExport;
-using llvm::wasm::WasmImport;
+using llvm::wasm::WasmGlobal;
+using llvm::wasm::WasmGlobalType;
using llvm::wasm::WasmSignature;
+using llvm::wasm::WasmSymbolType;
namespace lld {
namespace wasm {
class InputFile;
+class InputChunk;
class InputSegment;
+class InputFunction;
+class InputGlobal;
+class InputSection;
+#define INVALID_INDEX UINT32_MAX
+
+// The base class for real symbol classes.
class Symbol {
public:
enum Kind {
DefinedFunctionKind,
+ DefinedDataKind,
DefinedGlobalKind,
-
- LazyKind,
+ SectionKind,
UndefinedFunctionKind,
+ UndefinedDataKind,
UndefinedGlobalKind,
-
- LastDefinedKind = DefinedGlobalKind,
- InvalidKind,
+ LazyKind,
};
- Symbol(StringRef Name, bool IsLocal)
- : WrittenToSymtab(0), WrittenToNameSec(0), IsLocal(IsLocal), Name(Name) {}
+ Kind kind() const { return SymbolKind; }
- Kind getKind() const { return SymbolKind; }
+ bool isDefined() const {
+ return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
+ SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind;
+ }
- bool isLazy() const { return SymbolKind == LazyKind; }
- bool isDefined() const { return SymbolKind <= LastDefinedKind; }
bool isUndefined() const {
- return SymbolKind == UndefinedGlobalKind ||
- SymbolKind == UndefinedFunctionKind;
+ return SymbolKind == UndefinedFunctionKind ||
+ SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind;
}
- bool isFunction() const {
- return SymbolKind == DefinedFunctionKind ||
- SymbolKind == UndefinedFunctionKind;
- }
- bool isGlobal() const { return !isFunction(); }
- bool isLocal() const { return IsLocal; }
+
+ bool isLazy() const { return SymbolKind == LazyKind; }
+
+ bool isLocal() const;
bool isWeak() const;
bool isHidden() const;
@@ -66,57 +72,278 @@ public:
// Returns the file from which this symbol was created.
InputFile *getFile() const { return File; }
- uint32_t getGlobalIndex() const;
- uint32_t getFunctionIndex() const;
+ InputChunk *getChunk() const;
- bool hasFunctionType() const { return FunctionType != nullptr; }
- const WasmSignature &getFunctionType() const;
- uint32_t getOutputIndex() const;
- uint32_t getTableIndex() const { return TableIndex.getValue(); }
+ // Indicates that the section or import for this symbol will be included in
+ // the final image.
+ bool isLive() const;
- // Returns the virtual address of a defined global.
- // Only works for globals, not functions.
- uint32_t getVirtualAddress() const;
+ // Marks the symbol's InputChunk as Live, so that it will be included in the
+ // final image.
+ void markLive();
+
+ void setHidden(bool IsHidden);
- // Set the output index of the symbol (in the function or global index
- // space of the output object.
- void setOutputIndex(uint32_t Index);
+ // Get/set the index in the output symbol table. This is only used for
+ // relocatable output.
+ uint32_t getOutputSymbolIndex() const;
+ void setOutputSymbolIndex(uint32_t Index);
- // Returns true if a table index has been set for this symbol
- bool hasTableIndex() const { return TableIndex.hasValue(); }
+ WasmSymbolType getWasmType() const;
+ bool isExported() const;
- // Set the table index of the symbol
+ // True if this symbol was referenced by a regular (non-bitcode) object.
+ unsigned IsUsedInRegularObj : 1;
+ unsigned ForceExport : 1;
+
+protected:
+ Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
+ : IsUsedInRegularObj(false), ForceExport(false), Name(Name),
+ SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {}
+
+ StringRef Name;
+ Kind SymbolKind;
+ uint32_t Flags;
+ InputFile *File;
+ uint32_t OutputSymbolIndex = INVALID_INDEX;
+ bool Referenced;
+};
+
+class FunctionSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedFunctionKind ||
+ S->kind() == UndefinedFunctionKind;
+ }
+
+ // Get/set the table index
void setTableIndex(uint32_t Index);
+ uint32_t getTableIndex() const;
+ bool hasTableIndex() const;
+
+ // Get/set the function index
+ uint32_t getFunctionIndex() const;
+ void setFunctionIndex(uint32_t Index);
+ bool hasFunctionIndex() const;
+ const WasmSignature *FunctionType;
+
+protected:
+ FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
+ const WasmSignature *Type)
+ : Symbol(Name, K, Flags, F), FunctionType(Type) {}
+
+ uint32_t TableIndex = INVALID_INDEX;
+ uint32_t FunctionIndex = INVALID_INDEX;
+};
+
+class DefinedFunction : public FunctionSymbol {
+public:
+ DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
+ InputFunction *Function);
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedFunctionKind;
+ }
+
+ InputFunction *Function;
+};
+
+class UndefinedFunction : public FunctionSymbol {
+public:
+ UndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File = nullptr,
+ const WasmSignature *Type = nullptr)
+ : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == UndefinedFunctionKind;
+ }
+};
+
+class SectionSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
+
+ SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S,
+ InputFile *F = nullptr)
+ : Symbol(Name, SectionKind, Flags, F), Section(S) {}
+
+ const InputSection *Section;
+
+ uint32_t getOutputSectionIndex() const;
+ void setOutputSectionIndex(uint32_t Index);
+
+protected:
+ uint32_t OutputSectionIndex = INVALID_INDEX;
+};
+
+class DataSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind;
+ }
+
+protected:
+ DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
+ : Symbol(Name, K, Flags, F) {}
+};
+
+class DefinedData : public DataSymbol {
+public:
+ // Constructor for regular data symbols originating from input files.
+ DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
+ InputSegment *Segment, uint32_t Offset, uint32_t Size)
+ : DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
+ Offset(Offset), Size(Size) {}
+
+ // Constructor for linker synthetic data symbols.
+ DefinedData(StringRef Name, uint32_t Flags)
+ : DataSymbol(Name, DefinedDataKind, Flags, nullptr) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; }
+
+ // Returns the output virtual address of a defined data symbol.
+ uint32_t getVirtualAddress() const;
void setVirtualAddress(uint32_t VA);
- void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr,
- const InputSegment *Segment = nullptr,
- const WasmSignature *Sig = nullptr);
+ // Returns the offset of a defined data symbol within its OutputSegment.
+ uint32_t getOutputSegmentOffset() const;
+ uint32_t getOutputSegmentIndex() const;
+ uint32_t getSize() const { return Size; }
+
+ InputSegment *Segment = nullptr;
+
+protected:
+ uint32_t Offset = 0;
+ uint32_t Size = 0;
+};
+
+class UndefinedData : public DataSymbol {
+public:
+ UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr)
+ : DataSymbol(Name, UndefinedDataKind, Flags, File) {}
+ static bool classof(const Symbol *S) {
+ return S->kind() == UndefinedDataKind;
+ }
+};
- void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
- const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
+class GlobalSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
+ }
- // This bit is used by Writer::writeNameSection() to prevent
- // symbols from being written to the symbol table more than once.
- unsigned WrittenToSymtab : 1;
- unsigned WrittenToNameSec : 1;
+ const WasmGlobalType *getGlobalType() const { return GlobalType; }
+
+ // Get/set the global index
+ uint32_t getGlobalIndex() const;
+ void setGlobalIndex(uint32_t Index);
+ bool hasGlobalIndex() const;
protected:
- unsigned IsLocal : 1;
+ GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
+ const WasmGlobalType *GlobalType)
+ : Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
- StringRef Name;
- Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
- Kind SymbolKind = InvalidKind;
- InputFile *File = nullptr;
- const WasmSymbol *Sym = nullptr;
- const InputSegment *Segment = nullptr;
- llvm::Optional<uint32_t> OutputIndex;
- llvm::Optional<uint32_t> TableIndex;
- llvm::Optional<uint32_t> VirtualAddress;
- const WasmSignature *FunctionType;
+ // Explicit function type, needed for undefined or synthetic functions only.
+ // For regular defined globals this information comes from the InputChunk.
+ const WasmGlobalType *GlobalType;
+ uint32_t GlobalIndex = INVALID_INDEX;
};
+class DefinedGlobal : public GlobalSymbol {
+public:
+ DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
+ InputGlobal *Global);
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedGlobalKind;
+ }
+
+ InputGlobal *Global;
+};
+
+class UndefinedGlobal : public GlobalSymbol {
+public:
+ UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr,
+ const WasmGlobalType *Type = nullptr)
+ : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == UndefinedGlobalKind;
+ }
+};
+
+class LazySymbol : public Symbol {
+public:
+ LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym)
+ : Symbol(Name, LazyKind, 0, File), ArchiveSymbol(Sym) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
+ void fetch();
+
+private:
+ Archive::Symbol ArchiveSymbol;
+};
+
+// linker-generated symbols
+struct WasmSym {
+ // __stack_pointer
+ // Global that holds the address of the top of the explicit value stack in
+ // linear memory.
+ static DefinedGlobal *StackPointer;
+
+ // __data_end
+ // Symbol marking the end of the data and bss.
+ static DefinedData *DataEnd;
+
+ // __heap_base
+ // Symbol marking the end of the data, bss and explicit stack. Any linear
+ // memory following this address is not used by the linked code and can
+ // therefore be used as a backing store for brk()/malloc() implementations.
+ static DefinedData *HeapBase;
+
+ // __wasm_call_ctors
+ // Function that directly calls all ctors in priority order.
+ static DefinedFunction *CallCtors;
+
+ // __dso_handle
+ // Symbol used in calls to __cxa_atexit to determine current DLL
+ static DefinedData *DsoHandle;
+};
+
+// A buffer class that is large enough to hold any Symbol-derived
+// object. We allocate memory using this class and instantiate a symbol
+// using the placement new.
+union SymbolUnion {
+ alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
+ alignas(DefinedData) char B[sizeof(DefinedData)];
+ alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
+ alignas(LazySymbol) char D[sizeof(LazySymbol)];
+ alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)];
+ alignas(UndefinedData) char F[sizeof(UndefinedData)];
+ alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)];
+ alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
+};
+
+template <typename T, typename... ArgT>
+T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
+ static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
+ static_assert(alignof(T) <= alignof(SymbolUnion),
+ "SymbolUnion not aligned enough");
+ assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
+ "Not a Symbol");
+
+ Symbol SymCopy = *S;
+
+ T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
+ S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
+ S2->ForceExport = SymCopy.ForceExport;
+ return S2;
+}
+
} // namespace wasm
// Returns a symbol name for an error message.
diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp
index e7dd49d52213..37ad32452a91 100644
--- a/wasm/Writer.cpp
+++ b/wasm/Writer.cpp
@@ -8,21 +8,28 @@
//===----------------------------------------------------------------------===//
#include "Writer.h"
-
#include "Config.h"
+#include "InputChunks.h"
+#include "InputGlobal.h"
#include "OutputSections.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Object/WasmTraits.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
#include <cstdarg>
+#include <map>
#define DEBUG_TYPE "lld"
@@ -32,31 +39,16 @@ using namespace lld;
using namespace lld::wasm;
static constexpr int kStackAlignment = 16;
+static constexpr int kInitialTableOffset = 1;
+static constexpr const char *kFunctionTableName = "__indirect_function_table";
namespace {
-// Traits for using WasmSignature in a DenseMap.
-struct WasmSignatureDenseMapInfo {
- static WasmSignature getEmptyKey() {
- WasmSignature Sig;
- Sig.ReturnType = 1;
- return Sig;
- }
- static WasmSignature getTombstoneKey() {
- WasmSignature Sig;
- Sig.ReturnType = 2;
- return Sig;
- }
- static unsigned getHashValue(const WasmSignature &Sig) {
- uintptr_t Value = 0;
- Value += DenseMapInfo<int32_t>::getHashValue(Sig.ReturnType);
- for (int32_t Param : Sig.ParamTypes)
- Value += DenseMapInfo<int32_t>::getHashValue(Param);
- return Value;
- }
- static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
- return LHS == RHS;
- }
+// An init entry to be written to either the synthetic init func or the
+// linking metadata.
+struct WasmInitEntry {
+ const FunctionSymbol *Sym;
+ uint32_t Priority;
};
// The writer writes a SymbolTable result to a file.
@@ -67,17 +59,22 @@ public:
private:
void openFile();
- uint32_t getTypeIndex(const WasmSignature &Sig);
- void assignSymbolIndexes();
+ uint32_t lookupType(const WasmSignature &Sig);
+ uint32_t registerType(const WasmSignature &Sig);
+
+ void createCtorFunction();
+ void calculateInitFunctions();
+ void assignIndexes();
void calculateImports();
- void calculateOffsets();
+ void calculateExports();
+ void calculateCustomSections();
+ void assignSymtab();
void calculateTypes();
void createOutputSegments();
void layoutMemory();
void createHeader();
void createSections();
- SyntheticSection *createSyntheticSection(uint32_t Type,
- std::string Name = "");
+ SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = "");
// Builtin sections
void createTypeSection();
@@ -88,9 +85,9 @@ private:
void createImportSection();
void createMemorySection();
void createElemSection();
- void createStartSection();
void createCodeSection();
void createDataSection();
+ void createCustomSections();
// Custom sections
void createRelocSections();
@@ -101,17 +98,24 @@ private:
void writeSections();
uint64_t FileSize = 0;
- uint32_t DataSize = 0;
- uint32_t NumFunctions = 0;
uint32_t NumMemoryPages = 0;
- uint32_t InitialTableOffset = 0;
+ uint32_t MaxMemoryPages = 0;
std::vector<const WasmSignature *> Types;
- DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
- std::vector<const Symbol *> FunctionImports;
- std::vector<const Symbol *> GlobalImports;
- std::vector<const Symbol *> DefinedGlobals;
- std::vector<const Symbol *> IndirectFunctions;
+ DenseMap<WasmSignature, int32_t> TypeIndices;
+ std::vector<const Symbol *> ImportedSymbols;
+ unsigned NumImportedFunctions = 0;
+ unsigned NumImportedGlobals = 0;
+ std::vector<WasmExport> Exports;
+ std::vector<const DefinedData *> DefinedFakeGlobals;
+ std::vector<InputGlobal *> InputGlobals;
+ std::vector<InputFunction *> InputFunctions;
+ std::vector<const FunctionSymbol *> IndirectFunctions;
+ std::vector<const Symbol *> SymtabEntries;
+ std::vector<WasmInitEntry> InitFunctions;
+
+ llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
+ llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
// Elements that are used to construct the final output
std::string Header;
@@ -125,20 +129,12 @@ private:
} // anonymous namespace
-static void debugPrint(const char *fmt, ...) {
- if (!errorHandler().Verbose)
- return;
- fprintf(stderr, "lld: ");
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
void Writer::createImportSection() {
- uint32_t NumImports = FunctionImports.size() + GlobalImports.size();
+ uint32_t NumImports = ImportedSymbols.size();
if (Config->ImportMemory)
++NumImports;
+ if (Config->ImportTable)
+ ++NumImports;
if (NumImports == 0)
return;
@@ -148,16 +144,6 @@ void Writer::createImportSection() {
writeUleb128(OS, NumImports, "import count");
- for (const Symbol *Sym : FunctionImports) {
- WasmImport Import;
- Import.Module = "env";
- Import.Field = Sym->getName();
- Import.Kind = WASM_EXTERNAL_FUNCTION;
- assert(TypeIndices.count(Sym->getFunctionType()) > 0);
- Import.SigIndex = TypeIndices.lookup(Sym->getFunctionType());
- writeImport(OS, Import);
- }
-
if (Config->ImportMemory) {
WasmImport Import;
Import.Module = "env";
@@ -165,16 +151,36 @@ void Writer::createImportSection() {
Import.Kind = WASM_EXTERNAL_MEMORY;
Import.Memory.Flags = 0;
Import.Memory.Initial = NumMemoryPages;
+ if (MaxMemoryPages != 0) {
+ Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
+ Import.Memory.Maximum = MaxMemoryPages;
+ }
writeImport(OS, Import);
}
- for (const Symbol *Sym : GlobalImports) {
+ if (Config->ImportTable) {
+ uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
+ WasmImport Import;
+ Import.Module = "env";
+ Import.Field = kFunctionTableName;
+ Import.Kind = WASM_EXTERNAL_TABLE;
+ Import.Table.ElemType = WASM_TYPE_ANYFUNC;
+ Import.Table.Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
+ writeImport(OS, Import);
+ }
+
+ for (const Symbol *Sym : ImportedSymbols) {
WasmImport Import;
Import.Module = "env";
Import.Field = Sym->getName();
- Import.Kind = WASM_EXTERNAL_GLOBAL;
- Import.Global.Mutable = false;
- Import.Global.Type = WASM_TYPE_I32;
+ if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
+ Import.Kind = WASM_EXTERNAL_FUNCTION;
+ Import.SigIndex = lookupType(*FunctionSym->FunctionType);
+ } else {
+ auto *GlobalSym = cast<GlobalSymbol>(Sym);
+ Import.Kind = WASM_EXTERNAL_GLOBAL;
+ Import.Global = *GlobalSym->getGlobalType();
+ }
writeImport(OS, Import);
}
}
@@ -188,16 +194,15 @@ void Writer::createTypeSection() {
}
void Writer::createFunctionSection() {
- if (!NumFunctions)
+ if (InputFunctions.empty())
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, NumFunctions, "function count");
- for (ObjFile *File : Symtab->ObjectFiles)
- for (uint32_t Sig : File->getWasmObj()->functionTypes())
- writeUleb128(OS, File->relocateTypeIndex(Sig), "sig index");
+ writeUleb128(OS, InputFunctions.size(), "function count");
+ for (const InputFunction *Func : InputFunctions)
+ writeUleb128(OS, lookupType(Func->Signature), "sig index");
}
void Writer::createMemorySection() {
@@ -207,23 +212,29 @@ void Writer::createMemorySection() {
SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY);
raw_ostream &OS = Section->getStream();
+ bool HasMax = MaxMemoryPages != 0;
writeUleb128(OS, 1, "memory count");
- writeUleb128(OS, 0, "memory limits flags");
+ writeUleb128(OS, HasMax ? static_cast<unsigned>(WASM_LIMITS_FLAG_HAS_MAX) : 0,
+ "memory limits flags");
writeUleb128(OS, NumMemoryPages, "initial pages");
+ if (HasMax)
+ writeUleb128(OS, MaxMemoryPages, "max pages");
}
void Writer::createGlobalSection() {
- if (DefinedGlobals.empty())
+ unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size();
+ if (NumGlobals == 0)
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, DefinedGlobals.size(), "global count");
- for (const Symbol *Sym : DefinedGlobals) {
+ writeUleb128(OS, NumGlobals, "global count");
+ for (const InputGlobal *G : InputGlobals)
+ writeGlobal(OS, G->Global);
+ for (const DefinedData *Sym : DefinedFakeGlobals) {
WasmGlobal Global;
- Global.Type = WASM_TYPE_I32;
- Global.Mutable = Sym == Config->StackPointerSymbol;
+ Global.Type = {WASM_TYPE_I32, false};
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
writeGlobal(OS, Global);
@@ -231,88 +242,73 @@ void Writer::createGlobalSection() {
}
void Writer::createTableSection() {
- // Always output a table section, even if there are no indirect calls.
- // There are two reasons for this:
+ if (Config->ImportTable)
+ return;
+
+ // Always output a table section (or table import), even if there are no
+ // indirect calls. There are two reasons for this:
// 1. For executables it is useful to have an empty table slot at 0
// which can be filled with a null function call handler.
// 2. If we don't do this, any program that contains a call_indirect but
// no address-taken function will fail at validation time since it is
// a validation error to include a call_indirect instruction if there
// is not table.
- uint32_t TableSize = InitialTableOffset + IndirectFunctions.size();
+ uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
raw_ostream &OS = Section->getStream();
writeUleb128(OS, 1, "table count");
- writeSleb128(OS, WASM_TYPE_ANYFUNC, "table type");
- writeUleb128(OS, WASM_LIMITS_FLAG_HAS_MAX, "table flags");
- writeUleb128(OS, TableSize, "table initial size");
- writeUleb128(OS, TableSize, "table max size");
+ WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
+ writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits});
}
void Writer::createExportSection() {
- bool ExportMemory = !Config->Relocatable && !Config->ImportMemory;
- Symbol *EntrySym = Symtab->find(Config->Entry);
- bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined();
- bool ExportHidden = Config->EmitRelocs;
-
- uint32_t NumExports = ExportMemory ? 1 : 0;
-
- std::vector<const Symbol *> SymbolExports;
- if (ExportEntry)
- SymbolExports.emplace_back(EntrySym);
-
- for (const Symbol *Sym : Symtab->getSymbols()) {
- if (Sym->isUndefined() || Sym->isGlobal())
- continue;
- if (Sym->isHidden() && !ExportHidden)
- continue;
- if (ExportEntry && Sym == EntrySym)
- continue;
- SymbolExports.emplace_back(Sym);
- }
-
- for (const Symbol *Sym : DefinedGlobals) {
- // Can't export the SP right now because it mutable and mutable globals
- // connot be exported.
- if (Sym == Config->StackPointerSymbol)
- continue;
- SymbolExports.emplace_back(Sym);
- }
-
- NumExports += SymbolExports.size();
- if (!NumExports)
+ if (!Exports.size())
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, NumExports, "export count");
+ writeUleb128(OS, Exports.size(), "export count");
+ for (const WasmExport &Export : Exports)
+ writeExport(OS, Export);
+}
- if (ExportMemory) {
- WasmExport MemoryExport;
- MemoryExport.Name = "memory";
- MemoryExport.Kind = WASM_EXTERNAL_MEMORY;
- MemoryExport.Index = 0;
- writeExport(OS, MemoryExport);
+void Writer::calculateCustomSections() {
+ log("calculateCustomSections");
+ bool StripDebug = Config->StripDebug || Config->StripAll;
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ for (InputSection *Section : File->CustomSections) {
+ StringRef Name = Section->getName();
+ // These custom sections are known the linker and synthesized rather than
+ // blindly copied
+ if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
+ continue;
+ // .. or it is a debug section
+ if (StripDebug && Name.startswith(".debug_"))
+ continue;
+ CustomSectionMapping[Name].push_back(Section);
+ }
}
+}
- for (const Symbol *Sym : SymbolExports) {
- log("Export: " + Sym->getName());
- WasmExport Export;
- Export.Name = Sym->getName();
- Export.Index = Sym->getOutputIndex();
- if (Sym->isFunction())
- Export.Kind = WASM_EXTERNAL_FUNCTION;
- else
- Export.Kind = WASM_EXTERNAL_GLOBAL;
- writeExport(OS, Export);
+void Writer::createCustomSections() {
+ log("createCustomSections");
+ for (auto &Pair : CustomSectionMapping) {
+ StringRef Name = Pair.first();
+
+ auto P = CustomSectionSymbols.find(Name);
+ if (P != CustomSectionSymbols.end()) {
+ uint32_t SectionIndex = OutputSections.size();
+ P->second->setOutputSectionIndex(SectionIndex);
+ }
+
+ LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
+ OutputSections.push_back(make<CustomSection>(Name, Pair.second));
}
}
-void Writer::createStartSection() {}
-
void Writer::createElemSection() {
if (IndirectFunctions.empty())
return;
@@ -324,25 +320,25 @@ void Writer::createElemSection() {
writeUleb128(OS, 0, "table index");
WasmInitExpr InitExpr;
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = InitialTableOffset;
+ InitExpr.Value.Int32 = kInitialTableOffset;
writeInitExpr(OS, InitExpr);
writeUleb128(OS, IndirectFunctions.size(), "elem count");
- uint32_t TableIndex = InitialTableOffset;
- for (const Symbol *Sym : IndirectFunctions) {
+ uint32_t TableIndex = kInitialTableOffset;
+ for (const FunctionSymbol *Sym : IndirectFunctions) {
assert(Sym->getTableIndex() == TableIndex);
- writeUleb128(OS, Sym->getOutputIndex(), "function index");
+ writeUleb128(OS, Sym->getFunctionIndex(), "function index");
++TableIndex;
}
}
void Writer::createCodeSection() {
- if (!NumFunctions)
+ if (InputFunctions.empty())
return;
log("createCodeSection");
- auto Section = make<CodeSection>(NumFunctions, Symtab->ObjectFiles);
+ auto Section = make<CodeSection>(InputFunctions);
OutputSections.push_back(Section);
}
@@ -361,28 +357,68 @@ void Writer::createRelocSections() {
log("createRelocSections");
// Don't use iterator here since we are adding to OutputSection
size_t OrigSize = OutputSections.size();
- for (size_t i = 0; i < OrigSize; i++) {
- OutputSection *S = OutputSections[i];
- const char *name;
- uint32_t Count = S->numRelocations();
+ for (size_t I = 0; I < OrigSize; I++) {
+ OutputSection *OSec = OutputSections[I];
+ uint32_t Count = OSec->numRelocations();
if (!Count)
continue;
- if (S->Type == WASM_SEC_DATA)
- name = "reloc.DATA";
- else if (S->Type == WASM_SEC_CODE)
- name = "reloc.CODE";
+ StringRef Name;
+ if (OSec->Type == WASM_SEC_DATA)
+ Name = "reloc.DATA";
+ else if (OSec->Type == WASM_SEC_CODE)
+ Name = "reloc.CODE";
+ else if (OSec->Type == WASM_SEC_CUSTOM)
+ Name = Saver.save("reloc." + OSec->Name);
else
- llvm_unreachable("relocations only supported for code and data");
+ llvm_unreachable(
+ "relocations only supported for code, data, or custom sections");
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, name);
+ SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, S->Type, "reloc section");
+ writeUleb128(OS, I, "reloc section");
writeUleb128(OS, Count, "reloc count");
- S->writeRelocations(OS);
+ OSec->writeRelocations(OS);
}
}
+static uint32_t getWasmFlags(const Symbol *Sym) {
+ uint32_t Flags = 0;
+ if (Sym->isLocal())
+ Flags |= WASM_SYMBOL_BINDING_LOCAL;
+ if (Sym->isWeak())
+ Flags |= WASM_SYMBOL_BINDING_WEAK;
+ if (Sym->isHidden())
+ Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
+ if (Sym->isUndefined())
+ Flags |= WASM_SYMBOL_UNDEFINED;
+ return Flags;
+}
+
+// Some synthetic sections (e.g. "name" and "linking") have subsections.
+// Just like the synthetic sections themselves these need to be created before
+// they can be written out (since they are preceded by their length). This
+// class is used to create subsections and then write them into the stream
+// of the parent section.
+class SubSection {
+public:
+ explicit SubSection(uint32_t Type) : Type(Type) {}
+
+ void writeTo(raw_ostream &To) {
+ OS.flush();
+ writeUleb128(To, Type, "subsection type");
+ writeUleb128(To, Body.size(), "subsection size");
+ To.write(Body.data(), Body.size());
+ }
+
+private:
+ uint32_t Type;
+ std::string Body;
+
+public:
+ raw_string_ostream OS{Body};
+};
+
// Create the custom "linking" section containing linker metadata.
// This is only created when relocatable output is requested.
void Writer::createLinkingSection() {
@@ -390,82 +426,145 @@ void Writer::createLinkingSection() {
createSyntheticSection(WASM_SEC_CUSTOM, "linking");
raw_ostream &OS = Section->getStream();
- SubSection DataSizeSubSection(WASM_DATA_SIZE);
- writeUleb128(DataSizeSubSection.getStream(), DataSize, "data size");
- DataSizeSubSection.finalizeContents();
- DataSizeSubSection.writeToStream(OS);
+ writeUleb128(OS, WasmMetadataVersion, "Version");
+
+ if (!SymtabEntries.empty()) {
+ SubSection Sub(WASM_SYMBOL_TABLE);
+ writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
+
+ for (const Symbol *Sym : SymtabEntries) {
+ assert(Sym->isDefined() || Sym->isUndefined());
+ WasmSymbolType Kind = Sym->getWasmType();
+ uint32_t Flags = getWasmFlags(Sym);
+
+ writeU8(Sub.OS, Kind, "sym kind");
+ writeUleb128(Sub.OS, Flags, "sym flags");
+
+ if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
+ writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
+ if (Sym->isDefined())
+ writeStr(Sub.OS, Sym->getName(), "sym name");
+ } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
+ writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
+ if (Sym->isDefined())
+ writeStr(Sub.OS, Sym->getName(), "sym name");
+ } else if (isa<DataSymbol>(Sym)) {
+ writeStr(Sub.OS, Sym->getName(), "sym name");
+ if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
+ writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
+ writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
+ "data offset");
+ writeUleb128(Sub.OS, DataSym->getSize(), "data size");
+ }
+ } else {
+ auto *S = cast<SectionSymbol>(Sym);
+ writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
+ }
+ }
- if (!Config->Relocatable)
- return;
+ Sub.writeTo(OS);
+ }
if (Segments.size()) {
- SubSection SubSection(WASM_SEGMENT_INFO);
- writeUleb128(SubSection.getStream(), Segments.size(), "num data segments");
+ SubSection Sub(WASM_SEGMENT_INFO);
+ writeUleb128(Sub.OS, Segments.size(), "num data segments");
for (const OutputSegment *S : Segments) {
- writeStr(SubSection.getStream(), S->Name, "segment name");
- writeUleb128(SubSection.getStream(), S->Alignment, "alignment");
- writeUleb128(SubSection.getStream(), 0, "flags");
+ writeStr(Sub.OS, S->Name, "segment name");
+ writeUleb128(Sub.OS, S->Alignment, "alignment");
+ writeUleb128(Sub.OS, 0, "flags");
}
- SubSection.finalizeContents();
- SubSection.writeToStream(OS);
+ Sub.writeTo(OS);
}
- std::vector<WasmInitFunc> InitFunctions;
- for (ObjFile *File : Symtab->ObjectFiles) {
- const WasmLinkingData &L = File->getWasmObj()->linkingData();
- InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size());
- for (const WasmInitFunc &F : L.InitFunctions)
- InitFunctions.emplace_back(WasmInitFunc{
- F.Priority, File->relocateFunctionIndex(F.FunctionIndex)});
+ if (!InitFunctions.empty()) {
+ SubSection Sub(WASM_INIT_FUNCS);
+ writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
+ for (const WasmInitEntry &F : InitFunctions) {
+ writeUleb128(Sub.OS, F.Priority, "priority");
+ writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
+ }
+ Sub.writeTo(OS);
}
- if (!InitFunctions.empty()) {
- SubSection SubSection(WASM_INIT_FUNCS);
- writeUleb128(SubSection.getStream(), InitFunctions.size(),
- "num init functionsw");
- for (const WasmInitFunc &F : InitFunctions) {
- writeUleb128(SubSection.getStream(), F.Priority, "priority");
- writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index");
+ struct ComdatEntry {
+ unsigned Kind;
+ uint32_t Index;
+ };
+ std::map<StringRef, std::vector<ComdatEntry>> Comdats;
+
+ for (const InputFunction *F : InputFunctions) {
+ StringRef Comdat = F->getComdatName();
+ if (!Comdat.empty())
+ Comdats[Comdat].emplace_back(
+ ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
+ }
+ for (uint32_t I = 0; I < Segments.size(); ++I) {
+ const auto &InputSegments = Segments[I]->InputSegments;
+ if (InputSegments.empty())
+ continue;
+ StringRef Comdat = InputSegments[0]->getComdatName();
+#ifndef NDEBUG
+ for (const InputSegment *IS : InputSegments)
+ assert(IS->getComdatName() == Comdat);
+#endif
+ if (!Comdat.empty())
+ Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
+ }
+
+ if (!Comdats.empty()) {
+ SubSection Sub(WASM_COMDAT_INFO);
+ writeUleb128(Sub.OS, Comdats.size(), "num comdats");
+ for (const auto &C : Comdats) {
+ writeStr(Sub.OS, C.first, "comdat name");
+ writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use
+ writeUleb128(Sub.OS, C.second.size(), "num entries");
+ for (const ComdatEntry &Entry : C.second) {
+ writeU8(Sub.OS, Entry.Kind, "entry kind");
+ writeUleb128(Sub.OS, Entry.Index, "entry index");
+ }
}
- SubSection.finalizeContents();
- SubSection.writeToStream(OS);
+ Sub.writeTo(OS);
}
}
// Create the custom "name" section containing debug symbol names.
void Writer::createNameSection() {
- // Create an array of all function sorted by function index space
- std::vector<const Symbol *> Names;
+ unsigned NumNames = NumImportedFunctions;
+ for (const InputFunction *F : InputFunctions)
+ if (!F->getName().empty() || !F->getDebugName().empty())
+ ++NumNames;
- for (ObjFile *File : Symtab->ObjectFiles) {
- Names.reserve(Names.size() + File->getSymbols().size());
- for (Symbol *S : File->getSymbols()) {
- if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec)
- continue;
- S->WrittenToNameSec = true;
- Names.emplace_back(S);
- }
- }
+ if (NumNames == 0)
+ return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
- std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) {
- return A->getOutputIndex() < B->getOutputIndex();
- });
-
- SubSection FunctionSubsection(WASM_NAMES_FUNCTION);
- raw_ostream &OS = FunctionSubsection.getStream();
- writeUleb128(OS, Names.size(), "name count");
-
- // We have to iterate through the inputs twice so that all the imports
- // appear first before any of the local function names.
- for (const Symbol *S : Names) {
- writeUleb128(OS, S->getOutputIndex(), "func index");
- writeStr(OS, S->getName(), "symbol name");
+ SubSection Sub(WASM_NAMES_FUNCTION);
+ writeUleb128(Sub.OS, NumNames, "name count");
+
+ // Names must appear in function index order. As it happens ImportedSymbols
+ // and InputFunctions are numbered in order with imported functions coming
+ // first.
+ for (const Symbol *S : ImportedSymbols) {
+ if (auto *F = dyn_cast<FunctionSymbol>(S)) {
+ writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
+ Optional<std::string> Name = demangleItanium(F->getName());
+ writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
+ }
+ }
+ for (const InputFunction *F : InputFunctions) {
+ if (!F->getName().empty()) {
+ writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
+ if (!F->getDebugName().empty()) {
+ writeStr(Sub.OS, F->getDebugName(), "symbol name");
+ } else {
+ Optional<std::string> Name = demangleItanium(F->getName());
+ writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
+ }
+ }
}
- FunctionSubsection.finalizeContents();
- FunctionSubsection.writeToStream(Section->getStream());
+ Sub.writeTo(Section->getStream());
}
void Writer::writeHeader() {
@@ -479,48 +578,98 @@ void Writer::writeSections() {
// Fix the memory layout of the output binary. This assigns memory offsets
// to each of the input data sections as well as the explicit stack region.
+// The default memory layout is as follows, from low to high.
+//
+// - initialized data (starting at Config->GlobalBase)
+// - BSS data (not currently implemented in llvm)
+// - explicit stack (Config->ZStackSize)
+// - heap start / unallocated
+//
+// The --stack-first option means that stack is placed before any static data.
+// This can be useful since it means that stack overflow traps immediately rather
+// than overwriting global data, but also increases code size since all static
+// data loads and stores requires larger offsets.
void Writer::layoutMemory() {
+ createOutputSegments();
+
uint32_t MemoryPtr = 0;
- if (!Config->Relocatable) {
+
+ auto PlaceStack = [&]() {
+ if (Config->Relocatable)
+ return;
+ MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
+ if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
+ error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
+ log("mem: stack size = " + Twine(Config->ZStackSize));
+ log("mem: stack base = " + Twine(MemoryPtr));
+ MemoryPtr += Config->ZStackSize;
+ WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
+ log("mem: stack top = " + Twine(MemoryPtr));
+ };
+
+ if (Config->StackFirst) {
+ PlaceStack();
+ } else {
MemoryPtr = Config->GlobalBase;
- debugPrint("mem: global base = %d\n", Config->GlobalBase);
+ log("mem: global base = " + Twine(Config->GlobalBase));
}
- createOutputSegments();
+ uint32_t DataStart = MemoryPtr;
+
+ // Arbitrarily set __dso_handle handle to point to the start of the data
+ // segments.
+ if (WasmSym::DsoHandle)
+ WasmSym::DsoHandle->setVirtualAddress(DataStart);
- // Static data comes first
for (OutputSegment *Seg : Segments) {
MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
Seg->StartVA = MemoryPtr;
- debugPrint("mem: %-10s offset=%-8d size=%-4d align=%d\n",
- Seg->Name.str().c_str(), MemoryPtr, Seg->Size, Seg->Alignment);
+ log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
+ MemoryPtr, Seg->Size, Seg->Alignment));
MemoryPtr += Seg->Size;
}
- DataSize = MemoryPtr;
- if (!Config->Relocatable)
- DataSize -= Config->GlobalBase;
- debugPrint("mem: static data = %d\n", DataSize);
+ // TODO: Add .bss space here.
+ if (WasmSym::DataEnd)
+ WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
+
+ log("mem: static data = " + Twine(MemoryPtr - DataStart));
- // Stack comes after static data
+ if (!Config->StackFirst)
+ PlaceStack();
+
+ // Set `__heap_base` to directly follow the end of the stack or global data.
+ // The fact that this comes last means that a malloc/brk implementation
+ // can grow the heap at runtime.
if (!Config->Relocatable) {
- MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
- if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
- error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
- debugPrint("mem: stack size = %d\n", Config->ZStackSize);
- debugPrint("mem: stack base = %d\n", MemoryPtr);
- MemoryPtr += Config->ZStackSize;
- Config->StackPointerSymbol->setVirtualAddress(MemoryPtr);
- debugPrint("mem: stack top = %d\n", MemoryPtr);
+ WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
+ log("mem: heap base = " + Twine(MemoryPtr));
}
+ if (Config->InitialMemory != 0) {
+ if (Config->InitialMemory != alignTo(Config->InitialMemory, WasmPageSize))
+ error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
+ if (MemoryPtr > Config->InitialMemory)
+ error("initial memory too small, " + Twine(MemoryPtr) + " bytes needed");
+ else
+ MemoryPtr = Config->InitialMemory;
+ }
uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize);
NumMemoryPages = MemSize / WasmPageSize;
- debugPrint("mem: total pages = %d\n", NumMemoryPages);
+ log("mem: total pages = " + Twine(NumMemoryPages));
+
+ if (Config->MaxMemory != 0) {
+ if (Config->MaxMemory != alignTo(Config->MaxMemory, WasmPageSize))
+ error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
+ if (MemoryPtr > Config->MaxMemory)
+ error("maximum memory too small, " + Twine(MemoryPtr) + " bytes needed");
+ MaxMemoryPages = Config->MaxMemory / WasmPageSize;
+ log("mem: max pages = " + Twine(MaxMemoryPages));
+ }
}
SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
- std::string Name) {
+ StringRef Name) {
auto Sec = make<SyntheticSection>(Type, Name);
log("createSection: " + toString(*Sec));
OutputSections.push_back(Sec);
@@ -536,15 +685,16 @@ void Writer::createSections() {
createMemorySection();
createGlobalSection();
createExportSection();
- createStartSection();
createElemSection();
createCodeSection();
createDataSection();
+ createCustomSections();
// Custom sections
- if (Config->EmitRelocs)
+ if (Config->Relocatable) {
+ createLinkingSection();
createRelocSections();
- createLinkingSection();
+ }
if (!Config->StripDebug && !Config->StripAll)
createNameSection();
@@ -555,149 +705,336 @@ void Writer::createSections() {
}
}
-void Writer::calculateOffsets() {
- for (ObjFile *File : Symtab->ObjectFiles) {
- const WasmObjectFile *WasmFile = File->getWasmObj();
-
- // Function Index
- File->FunctionIndexOffset =
- FunctionImports.size() - File->NumFunctionImports() + NumFunctions;
- NumFunctions += WasmFile->functions().size();
+void Writer::calculateImports() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (!Sym->isUndefined())
+ continue;
+ if (isa<DataSymbol>(Sym))
+ continue;
+ if (Sym->isWeak() && !Config->Relocatable)
+ continue;
+ if (!Sym->isLive())
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
- // Memory
- if (WasmFile->memories().size() > 1)
- fatal(File->getName() + ": contains more than one memory");
+ LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
+ ImportedSymbols.emplace_back(Sym);
+ if (auto *F = dyn_cast<FunctionSymbol>(Sym))
+ F->setFunctionIndex(NumImportedFunctions++);
+ else
+ cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++);
}
}
-void Writer::calculateImports() {
+void Writer::calculateExports() {
+ if (Config->Relocatable)
+ return;
+
+ if (!Config->Relocatable && !Config->ImportMemory)
+ Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
+
+ if (!Config->Relocatable && Config->ExportTable)
+ Exports.push_back(WasmExport{kFunctionTableName, WASM_EXTERNAL_TABLE, 0});
+
+ unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
+
for (Symbol *Sym : Symtab->getSymbols()) {
- if (!Sym->isUndefined() || Sym->isWeak())
+ if (!Sym->isExported())
+ continue;
+ if (!Sym->isLive())
continue;
- if (Sym->isFunction()) {
- Sym->setOutputIndex(FunctionImports.size());
- FunctionImports.push_back(Sym);
+ StringRef Name = Sym->getName();
+ WasmExport Export;
+ if (auto *F = dyn_cast<DefinedFunction>(Sym)) {
+ Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()};
+ } else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
+ // TODO(sbc): Remove this check once to mutable global proposal is
+ // implement in all major browsers.
+ // See: https://github.com/WebAssembly/mutable-global
+ if (G->getGlobalType()->Mutable) {
+ // Only the __stack_pointer should ever be create as mutable.
+ assert(G == WasmSym::StackPointer);
+ continue;
+ }
+ Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
} else {
- Sym->setOutputIndex(GlobalImports.size());
- GlobalImports.push_back(Sym);
+ auto *D = cast<DefinedData>(Sym);
+ DefinedFakeGlobals.emplace_back(D);
+ Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
}
+
+ LLVM_DEBUG(dbgs() << "Export: " << Name << "\n");
+ Exports.push_back(Export);
+ }
+}
+
+void Writer::assignSymtab() {
+ if (!Config->Relocatable)
+ return;
+
+ StringMap<uint32_t> SectionSymbolIndices;
+
+ unsigned SymbolIndex = SymtabEntries.size();
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ LLVM_DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
+ for (Symbol *Sym : File->getSymbols()) {
+ if (Sym->getFile() != File)
+ continue;
+
+ if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
+ StringRef Name = S->getName();
+ if (CustomSectionMapping.count(Name) == 0)
+ continue;
+
+ auto SSI = SectionSymbolIndices.find(Name);
+ if (SSI != SectionSymbolIndices.end()) {
+ Sym->setOutputSymbolIndex(SSI->second);
+ continue;
+ }
+
+ SectionSymbolIndices[Name] = SymbolIndex;
+ CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
+
+ Sym->markLive();
+ }
+
+ // (Since this is relocatable output, GC is not performed so symbols must
+ // be live.)
+ assert(Sym->isLive());
+ Sym->setOutputSymbolIndex(SymbolIndex++);
+ SymtabEntries.emplace_back(Sym);
+ }
+ }
+
+ // For the moment, relocatable output doesn't contain any synthetic functions,
+ // so no need to look through the Symtab for symbols not referenced by
+ // Symtab->ObjectFiles.
+}
+
+uint32_t Writer::lookupType(const WasmSignature &Sig) {
+ auto It = TypeIndices.find(Sig);
+ if (It == TypeIndices.end()) {
+ error("type not found: " + toString(Sig));
+ return 0;
}
+ return It->second;
}
-uint32_t Writer::getTypeIndex(const WasmSignature &Sig) {
+uint32_t Writer::registerType(const WasmSignature &Sig) {
auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
- if (Pair.second)
+ if (Pair.second) {
+ LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n");
Types.push_back(&Sig);
+ }
return Pair.first->second;
}
void Writer::calculateTypes() {
+ // The output type section is the union of the following sets:
+ // 1. Any signature used in the TYPE relocation
+ // 2. The signatures of all imported functions
+ // 3. The signatures of all defined functions
+
for (ObjFile *File : Symtab->ObjectFiles) {
- File->TypeMap.reserve(File->getWasmObj()->types().size());
- for (const WasmSignature &Sig : File->getWasmObj()->types())
- File->TypeMap.push_back(getTypeIndex(Sig));
+ ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
+ for (uint32_t I = 0; I < Types.size(); I++)
+ if (File->TypeIsUsed[I])
+ File->TypeMap[I] = registerType(Types[I]);
}
-}
-void Writer::assignSymbolIndexes() {
- uint32_t GlobalIndex = GlobalImports.size();
+ for (const Symbol *Sym : ImportedSymbols)
+ if (auto *F = dyn_cast<FunctionSymbol>(Sym))
+ registerType(*F->FunctionType);
- if (Config->StackPointerSymbol) {
- DefinedGlobals.emplace_back(Config->StackPointerSymbol);
- Config->StackPointerSymbol->setOutputIndex(GlobalIndex++);
- }
+ for (const InputFunction *F : InputFunctions)
+ registerType(F->Signature);
+}
- if (Config->EmitRelocs)
- DefinedGlobals.reserve(Symtab->getSymbols().size());
+void Writer::assignIndexes() {
+ uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size();
+ auto AddDefinedFunction = [&](InputFunction *Func) {
+ if (!Func->Live)
+ return;
+ InputFunctions.emplace_back(Func);
+ Func->setFunctionIndex(FunctionIndex++);
+ };
- uint32_t TableIndex = InitialTableOffset;
+ for (InputFunction *Func : Symtab->SyntheticFunctions)
+ AddDefinedFunction(Func);
for (ObjFile *File : Symtab->ObjectFiles) {
- DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n");
-
- for (Symbol *Sym : File->getSymbols()) {
- // Assign indexes for symbols defined with this file.
- if (!Sym->isDefined() || File != Sym->getFile())
- continue;
- if (Sym->isFunction()) {
- auto *Obj = cast<ObjFile>(Sym->getFile());
- Sym->setOutputIndex(Obj->FunctionIndexOffset +
- Sym->getFunctionIndex());
- } else if (Config->EmitRelocs) {
- DefinedGlobals.emplace_back(Sym);
- Sym->setOutputIndex(GlobalIndex++);
- }
- }
+ LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
+ for (InputFunction *Func : File->Functions)
+ AddDefinedFunction(Func);
+ }
- for (Symbol *Sym : File->getTableSymbols()) {
- if (!Sym->hasTableIndex()) {
+ uint32_t TableIndex = kInitialTableOffset;
+ auto HandleRelocs = [&](InputChunk *Chunk) {
+ if (!Chunk->Live)
+ return;
+ ObjFile *File = Chunk->File;
+ ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
+ for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
+ if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||
+ Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) {
+ FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
+ if (Sym->hasTableIndex() || !Sym->hasFunctionIndex())
+ continue;
Sym->setTableIndex(TableIndex++);
IndirectFunctions.emplace_back(Sym);
+ } else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) {
+ // Mark target type as live
+ File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
+ File->TypeIsUsed[Reloc.Index] = true;
}
}
+ };
+
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
+ for (InputChunk *Chunk : File->Functions)
+ HandleRelocs(Chunk);
+ for (InputChunk *Chunk : File->Segments)
+ HandleRelocs(Chunk);
+ for (auto &P : File->CustomSections)
+ HandleRelocs(P);
+ }
+
+ uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
+ auto AddDefinedGlobal = [&](InputGlobal *Global) {
+ if (Global->Live) {
+ LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
+ Global->setGlobalIndex(GlobalIndex++);
+ InputGlobals.push_back(Global);
+ }
+ };
+
+ for (InputGlobal *Global : Symtab->SyntheticGlobals)
+ AddDefinedGlobal(Global);
+
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
+ for (InputGlobal *Global : File->Globals)
+ AddDefinedGlobal(Global);
}
}
static StringRef getOutputDataSegmentName(StringRef Name) {
- if (Config->Relocatable)
+ if (!Config->MergeDataSegments)
return Name;
-
- for (StringRef V :
- {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
- ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
- ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
- StringRef Prefix = V.drop_back();
- if (Name.startswith(V) || Name == Prefix)
- return Prefix;
- }
-
+ if (Name.startswith(".text."))
+ return ".text";
+ if (Name.startswith(".data."))
+ return ".data";
+ if (Name.startswith(".bss."))
+ return ".bss";
return Name;
}
void Writer::createOutputSegments() {
for (ObjFile *File : Symtab->ObjectFiles) {
for (InputSegment *Segment : File->Segments) {
+ if (!Segment->Live)
+ continue;
StringRef Name = getOutputDataSegmentName(Segment->getName());
OutputSegment *&S = SegmentMap[Name];
if (S == nullptr) {
- DEBUG(dbgs() << "new segment: " << Name << "\n");
- S = make<OutputSegment>(Name);
+ LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
+ S = make<OutputSegment>(Name, Segments.size());
Segments.push_back(S);
}
S->addInputSegment(Segment);
- DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
+ LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
}
}
}
+static const int OPCODE_CALL = 0x10;
+static const int OPCODE_END = 0xb;
+
+// Create synthetic "__wasm_call_ctors" function based on ctor functions
+// in input object.
+void Writer::createCtorFunction() {
+ // First write the body's contents to a string.
+ std::string BodyContent;
+ {
+ raw_string_ostream OS(BodyContent);
+ writeUleb128(OS, 0, "num locals");
+ for (const WasmInitEntry &F : InitFunctions) {
+ writeU8(OS, OPCODE_CALL, "CALL");
+ writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
+ }
+ writeU8(OS, OPCODE_END, "END");
+ }
+
+ // Once we know the size of the body we can create the final function body
+ std::string FunctionBody;
+ {
+ raw_string_ostream OS(FunctionBody);
+ writeUleb128(OS, BodyContent.size(), "function size");
+ OS << BodyContent;
+ }
+
+ ArrayRef<uint8_t> Body = toArrayRef(Saver.save(FunctionBody));
+ cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
+}
+
+// Populate InitFunctions vector with init functions from all input objects.
+// This is then used either when creating the output linking section or to
+// synthesize the "__wasm_call_ctors" function.
+void Writer::calculateInitFunctions() {
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ const WasmLinkingData &L = File->getWasmObj()->linkingData();
+ for (const WasmInitFunc &F : L.InitFunctions) {
+ FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
+ if (*Sym->FunctionType != WasmSignature{{}, WASM_TYPE_NORESULT})
+ error("invalid signature for init func: " + toString(*Sym));
+ InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
+ }
+ }
+
+ // Sort in order of priority (lowest first) so that they are called
+ // in the correct order.
+ std::stable_sort(InitFunctions.begin(), InitFunctions.end(),
+ [](const WasmInitEntry &L, const WasmInitEntry &R) {
+ return L.Priority < R.Priority;
+ });
+}
+
void Writer::run() {
- if (!Config->Relocatable)
- InitialTableOffset = 1;
+ if (Config->Relocatable)
+ Config->GlobalBase = 0;
- log("-- calculateTypes");
- calculateTypes();
log("-- calculateImports");
calculateImports();
- log("-- calculateOffsets");
- calculateOffsets();
+ log("-- assignIndexes");
+ assignIndexes();
+ log("-- calculateInitFunctions");
+ calculateInitFunctions();
+ if (!Config->Relocatable)
+ createCtorFunction();
+ log("-- calculateTypes");
+ calculateTypes();
+ log("-- layoutMemory");
+ layoutMemory();
+ log("-- calculateExports");
+ calculateExports();
+ log("-- calculateCustomSections");
+ calculateCustomSections();
+ log("-- assignSymtab");
+ assignSymtab();
if (errorHandler().Verbose) {
- log("Defined Functions: " + Twine(NumFunctions));
- log("Defined Globals : " + Twine(DefinedGlobals.size()));
- log("Function Imports : " + Twine(FunctionImports.size()));
- log("Global Imports : " + Twine(GlobalImports.size()));
- log("Total Imports : " +
- Twine(FunctionImports.size() + GlobalImports.size()));
+ log("Defined Functions: " + Twine(InputFunctions.size()));
+ log("Defined Globals : " + Twine(InputGlobals.size()));
+ log("Function Imports : " + Twine(NumImportedFunctions));
+ log("Global Imports : " + Twine(NumImportedGlobals));
for (ObjFile *File : Symtab->ObjectFiles)
File->dumpInfo();
}
- log("-- assignSymbolIndexes");
- assignSymbolIndexes();
- log("-- layoutMemory");
- layoutMemory();
-
createHeader();
log("-- createSections");
createSections();
@@ -721,7 +1058,6 @@ void Writer::run() {
// Open a result file.
void Writer::openFile() {
log("writing: " + Config->OutputFile);
- ::remove(Config->OutputFile.str().c_str());
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize,
diff --git a/wasm/WriterUtils.cpp b/wasm/WriterUtils.cpp
index 5bdf0d2e3f65..201529edeaa6 100644
--- a/wasm/WriterUtils.cpp
+++ b/wasm/WriterUtils.cpp
@@ -8,12 +8,9 @@
//===----------------------------------------------------------------------===//
#include "WriterUtils.h"
-
#include "lld/Common/ErrorHandler.h"
-
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
#define DEBUG_TYPE "lld"
@@ -22,7 +19,7 @@ using namespace llvm;
using namespace llvm::wasm;
using namespace lld::wasm;
-static const char *valueTypeToString(int32_t Type) {
+static const char *valueTypeToString(uint8_t Type) {
switch (Type) {
case WASM_TYPE_I32:
return "i32";
@@ -39,61 +36,57 @@ static const char *valueTypeToString(int32_t Type) {
namespace lld {
-void wasm::debugWrite(uint64_t offset, Twine msg) {
- DEBUG(dbgs() << format(" | %08" PRIx64 ": ", offset) << msg << "\n");
+void wasm::debugWrite(uint64_t Offset, const Twine &Msg) {
+ LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
}
-void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg) {
- if (msg)
- debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
+void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
+ debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
encodeULEB128(Number, OS);
}
-void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *msg) {
- if (msg)
- debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
+void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) {
+ debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
encodeSLEB128(Number, OS);
}
-void wasm::writeBytes(raw_ostream &OS, const char *bytes, size_t count,
- const char *msg) {
- if (msg)
- debugWrite(OS.tell(), msg + formatv(" [data[{0}]]", count));
- OS.write(bytes, count);
+void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count,
+ const Twine &Msg) {
+ debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]");
+ OS.write(Bytes, Count);
}
-void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *msg) {
- if (msg)
- debugWrite(OS.tell(),
- msg + formatv(" [str[{0}]: {1}]", String.size(), String));
- writeUleb128(OS, String.size(), nullptr);
- writeBytes(OS, String.data(), String.size());
+void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) {
+ debugWrite(OS.tell(),
+ Msg + " [str[" + Twine(String.size()) + "]: " + String + "]");
+ encodeULEB128(String.size(), OS);
+ OS.write(String.data(), String.size());
}
-void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *msg) {
- OS << byte;
+void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) {
+ debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]");
+ OS << Byte;
}
-void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *msg) {
- debugWrite(OS.tell(), msg + formatv("[{0:x}]", Number));
- support::endian::Writer<support::little>(OS).write(Number);
+void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
+ debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
+ support::endian::write(OS, Number, support::little);
}
-void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *msg) {
- debugWrite(OS.tell(), msg + formatv("[type: {0}]", valueTypeToString(Type)));
- writeSleb128(OS, Type, nullptr);
+void wasm::writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg) {
+ writeU8(OS, Type, Msg + "[type: " + valueTypeToString(Type) + "]");
}
void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
- writeSleb128(OS, WASM_TYPE_FUNC, "signature type");
- writeUleb128(OS, Sig.ParamTypes.size(), "param count");
- for (int32_t ParamType : Sig.ParamTypes) {
+ writeU8(OS, WASM_TYPE_FUNC, "signature type");
+ writeUleb128(OS, Sig.ParamTypes.size(), "param Count");
+ for (uint8_t ParamType : Sig.ParamTypes) {
writeValueType(OS, ParamType, "param type");
}
if (Sig.ReturnType == WASM_TYPE_NORESULT) {
- writeUleb128(OS, 0, "result count");
+ writeUleb128(OS, 0, "result Count");
} else {
- writeUleb128(OS, 1, "result count");
+ writeUleb128(OS, 1, "result Count");
writeValueType(OS, Sig.ReturnType, "result type");
}
}
@@ -117,18 +110,27 @@ void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
}
void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
- writeUleb128(OS, Limits.Flags, "limits flags");
+ writeU8(OS, Limits.Flags, "limits flags");
writeUleb128(OS, Limits.Initial, "limits initial");
if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
writeUleb128(OS, Limits.Maximum, "limits max");
}
+void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
+ writeValueType(OS, Type.Type, "global type");
+ writeU8(OS, Type.Mutable, "global mutable");
+}
+
void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
- writeValueType(OS, Global.Type, "global type");
- writeUleb128(OS, Global.Mutable, "global mutable");
+ writeGlobalType(OS, Global.Type);
writeInitExpr(OS, Global.InitExpr);
}
+void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
+ writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
+ writeLimits(OS, Type.Limits);
+}
+
void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
writeStr(OS, Import.Module, "import module name");
writeStr(OS, Import.Field, "import field name");
@@ -138,12 +140,14 @@ void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
writeUleb128(OS, Import.SigIndex, "import sig index");
break;
case WASM_EXTERNAL_GLOBAL:
- writeValueType(OS, Import.Global.Type, "import global type");
- writeUleb128(OS, Import.Global.Mutable, "import global mutable");
+ writeGlobalType(OS, Import.Global);
break;
case WASM_EXTERNAL_MEMORY:
writeLimits(OS, Import.Memory);
break;
+ case WASM_EXTERNAL_TABLE:
+ writeTableType(OS, Import.Table);
+ break;
default:
fatal("unsupported import type: " + Twine(Import.Kind));
}
@@ -162,27 +166,13 @@ void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
case WASM_EXTERNAL_MEMORY:
writeUleb128(OS, Export.Index, "memory index");
break;
- default:
- fatal("unsupported export type: " + Twine(Export.Kind));
- }
-}
-
-void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) {
- writeUleb128(OS, Reloc.Reloc.Type, "reloc type");
- writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset");
- writeUleb128(OS, Reloc.NewIndex, "reloc index");
-
- switch (Reloc.Reloc.Type) {
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend");
+ case WASM_EXTERNAL_TABLE:
+ writeUleb128(OS, Export.Index, "table index");
break;
default:
- break;
+ fatal("unsupported export type: " + Twine(Export.Kind));
}
}
-
} // namespace lld
std::string lld::toString(ValType Type) {
@@ -195,6 +185,8 @@ std::string lld::toString(ValType Type) {
return "F32";
case ValType::F64:
return "F64";
+ case ValType::EXCEPT_REF:
+ return "except_ref";
}
llvm_unreachable("Invalid wasm::ValType");
}
@@ -213,3 +205,8 @@ std::string lld::toString(const WasmSignature &Sig) {
S += toString(static_cast<ValType>(Sig.ReturnType));
return S.str();
}
+
+std::string lld::toString(const WasmGlobalType &Sig) {
+ return (Sig.Mutable ? "var " : "const ") +
+ toString(static_cast<ValType>(Sig.Type));
+}
diff --git a/wasm/WriterUtils.h b/wasm/WriterUtils.h
index c1ed90793f78..74d727b24b40 100644
--- a/wasm/WriterUtils.h
+++ b/wasm/WriterUtils.h
@@ -10,49 +10,32 @@
#ifndef LLD_WASM_WRITERUTILS_H
#define LLD_WASM_WRITERUTILS_H
+#include "lld/Common/LLVM.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/raw_ostream.h"
using llvm::raw_ostream;
-// Needed for WasmSignatureDenseMapInfo
-inline bool operator==(const llvm::wasm::WasmSignature &LHS,
- const llvm::wasm::WasmSignature &RHS) {
- return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes;
-}
-
-inline bool operator!=(const llvm::wasm::WasmSignature &LHS,
- const llvm::wasm::WasmSignature &RHS) {
- return !(LHS == RHS);
-}
-
namespace lld {
namespace wasm {
-struct OutputRelocation {
- llvm::wasm::WasmRelocation Reloc;
- uint32_t NewIndex;
- uint32_t Value;
-};
-
-void debugWrite(uint64_t offset, llvm::Twine msg);
+void debugWrite(uint64_t Offset, const Twine &Msg);
-void writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg);
+void writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg);
-void writeSleb128(raw_ostream &OS, int32_t Number, const char *msg);
+void writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg);
-void writeBytes(raw_ostream &OS, const char *bytes, size_t count,
- const char *msg = nullptr);
+void writeBytes(raw_ostream &OS, const char *Bytes, size_t count,
+ const Twine &Msg);
-void writeStr(raw_ostream &OS, const llvm::StringRef String,
- const char *msg = nullptr);
+void writeStr(raw_ostream &OS, StringRef String, const Twine &Msg);
-void writeU8(raw_ostream &OS, uint8_t byte, const char *msg);
+void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg);
-void writeU32(raw_ostream &OS, uint32_t Number, const char *msg);
+void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg);
-void writeValueType(raw_ostream &OS, int32_t Type, const char *msg);
+void writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg);
void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig);
@@ -60,18 +43,21 @@ void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr);
void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits);
+void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type);
+
void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
+void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
+
void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
-void writeReloc(raw_ostream &OS, const OutputRelocation &Reloc);
-
} // namespace wasm
-std::string toString(const llvm::wasm::ValType Type);
+std::string toString(llvm::wasm::ValType Type);
std::string toString(const llvm::wasm::WasmSignature &Sig);
+std::string toString(const llvm::wasm::WasmGlobalType &Sig);
} // namespace lld